For some reason after adding buttons to my application it has stopped functioning on android. It works as expected on desktop, but when attempting to run on android the app builds successfully, launches, then immediately crashes before it ever loads the scene. I attempted to view the logs via aLogcat, however I see nothing in these logs indicating an issue has occurred.
I have come to the conclusion that this issue has something to do with the uiskin/buttons being added to the stage, as I can add the stage without any actors and the app will still function in android. The files outlined in the uiskin.json file are all located in /android/assets directory as they should be. Is there something I have done incorrectly? Something I have missed?
uiskin.json
{
"com.badlogic.gdx.graphics.g2d.BitmapFont":{
"default_font": {
"file": "book_antiqua.fnt"
}
},
"com.badlogic.gdx.scenes.scene2d.ui.TextButton$TextButtonStyle":{
"default": {
"down": "default-round-down",
"up": "default-round",
"font": "default_font"
}
},
"com.badlogic.gdx.scenes.scene2d.ui.Window$WindowStyle":{
"default": {
"titleFont": "default_font"
}
}
}
Main class
package com.freedom.thirty;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputMultiplexer;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.PerspectiveCamera;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
import com.badlogic.gdx.graphics.g3d.Environment;
import com.badlogic.gdx.graphics.g3d.Model;
import com.badlogic.gdx.graphics.g3d.ModelBatch;
import com.badlogic.gdx.graphics.g3d.ModelInstance;
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight;
import com.badlogic.gdx.graphics.g3d.Material;
//import com.badlogic.gdx.graphics.g3d.utils.CameraInputController;
import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.graphics.FPSLogger;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.badlogic.gdx.utils.Align;
import com.badlogic.gdx.utils.viewport.FillViewport;
import com.badlogic.gdx.utils.viewport.ScreenViewport;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.freedom.thirty.MyCameraInputController;
public class FreedomThirty implements ApplicationListener {
public ScreenViewport vp;
public ScreenViewport stageVp;
public OrthographicCamera cam;
public MyCameraInputController camController;
public ModelBatch modelBatch;
public AssetManager assets;
public Array<ModelInstance> allModelInstances = new Array<ModelInstance>();
public Environment environment;
public boolean loading;
// Model instances that make up the map
public ModelInstance bridge;
public ModelInstance container_001;
public ModelInstance crate_001;
public ModelInstance crate_002;
public ModelInstance crate_003;
public ModelInstance crate_004;
public ModelInstance crate_005;
public ModelInstance grass_area;
public ModelInstance gravel_area;
public ModelInstance rock_wall;
public ModelInstance water;
public ModelInstance player;
public ModelInstance skybox;
public Skin skin;
public Stage stage;
public Table table;
//public FPSLogger fpsLogger = new FPSLogger();
#Override
public void create() {
modelBatch = new ModelBatch();
assets = new AssetManager();
environment = new Environment();
environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.8f, 0.8f, 0.8f, 1f));
//environment.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f));
cam = new OrthographicCamera();
cam.position.set(-4f, 4f, 4f);
cam.lookAt(8f, 0f, -8f);
cam.near = 1f;
cam.far = 2000f;
cam.update();
// Create input controller for default scene camera. This is what allows the user to orbit around the scene
camController = new MyCameraInputController(cam);
// Set the position where the camera will look. This will need to come from json config file in the future
camController.target.set(8f, 0f, -8f);
vp = new ScreenViewport(cam);
vp.setUnitsPerPixel(0.017f);
vp.apply();
stageVp = new ScreenViewport();
stageVp.apply();
stage = new Stage(stageVp);
assets.load("uiskin.json", Skin.class);
assets.load("map_003.g3db", Model.class);
loading = true;
}
private void doneLoading(){ // Assets are now loaded into memory and can be accessed without error
// Load UI skin
skin = assets.get("uiskin.json", Skin.class);
// Define the buttons that will be in the ui table
final TextButton zoomOut = new TextButton("Zoom Out",skin,"default");
final TextButton zoomIn = new TextButton("Zoom In",skin,"default");
// Create UI table actor
table = new Table();
table.setWidth(stage.getWidth());
table.align(Align.center | Align.top);
// In the future determine what the current viewport height/width is, and set these
// to different sizes based on where the viewport falls between. Just like bootstrap's xs,sm,md,lg classes
table.setSize(250f, 250f);
table.setPosition(800f,400f);
zoomOut.setWidth(200);
zoomOut.setHeight(50);
zoomIn.setWidth(200);
zoomIn.setHeight(50);
// Event listeners for ui buttons
zoomOut.addListener(new ClickListener(){
#Override
public void clicked(InputEvent event, float x, float y){
//Gdx.app.log("Zoom Out", "Press successful");
vp.setUnitsPerPixel(vp.getUnitsPerPixel() + 0.001f);
vp.update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
stageVp.update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
event.stop();
}
});
zoomIn.addListener(new ClickListener(){
#Override
public void clicked(InputEvent event, float x, float y){
//Gdx.app.log("Zoom In", "Press successful");
vp.setUnitsPerPixel(vp.getUnitsPerPixel() - 0.001f);
vp.update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
stageVp.update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
event.stop();
}
});
// Add buttons to table
table.row().padBottom(30).padTop(30);
table.add(zoomOut);
table.add(zoomIn);
// Add table to stage
stage.addActor(table);
// Create an input multiplexer and add our stage and camController to it, set input processor to our new multiplexer
InputMultiplexer im = new InputMultiplexer(stage, camController);
Gdx.input.setInputProcessor(im);
// Load the 3d map, and character as character happens to be in the map file as of right now
// In the future each map and it's elements will be contained within it's own class, extended from
// map class
Model model = assets.get("map_003.g3db", Model.class);
bridge = new ModelInstance(model, "bridge");
allModelInstances.add(bridge);
container_001 = new ModelInstance(model, "container_001");
allModelInstances.add(container_001);
crate_001 = new ModelInstance(model, "crate_001");
allModelInstances.add(crate_001);
crate_002 = new ModelInstance(model, "crate_002");
allModelInstances.add(crate_002);
crate_003 = new ModelInstance(model, "crate_003");
allModelInstances.add(crate_003);
crate_004 = new ModelInstance(model, "crate_004");
allModelInstances.add(crate_004);
crate_005 = new ModelInstance(model, "crate_005");
allModelInstances.add(crate_005);
grass_area = new ModelInstance(model, "grass_area");
allModelInstances.add(grass_area);
gravel_area = new ModelInstance(model, "gravel_area");
allModelInstances.add(gravel_area);
rock_wall = new ModelInstance(model, "rock_wall");
allModelInstances.add(rock_wall);
water = new ModelInstance(model, "water");
allModelInstances.add(water);
player = new ModelInstance(model, "character");
allModelInstances.add(player);
player.transform.setTranslation(8f,0f,-6f); // Test character movement on the map
loading = false;
}
#Override
public void render() {
if(loading && assets.update()){
doneLoading();
}
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
camController.update();
//Gdx.app.log("Camera Position: ", cam.position.toString());
modelBatch.begin(cam);
modelBatch.render(allModelInstances, environment);
modelBatch.end();
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
//fpsLogger.log();
}
#Override
public void dispose() {
modelBatch.dispose();
allModelInstances.clear();
assets.dispose();
}
#Override
public void resize(int width, int height) {
vp.update(width, height);
stageVp.update(width, height);
}
#Override
public void pause() {
}
#Override
public void resume() {
}
}
What finally corrected this issue was downloading the default uiskin files from the libgdx repository on github. Apparently I missed something when I built them from scratch? The files I used from the repo are:
uiskin.json
uiskin.atlas
default.png
uiskin.png
I think it takes to long to load the uiskin file. Try instead of skin = new Skin(Gdx.files.internal("uiskin.json")); something like that:
AssetManager manager = new AssetManager();
manager.load("uiskin.json", Skin.class);
manager.finishLoading();
skin = manager.get("uiskin.json", Skin.class);
Don't forget to dispose the AssetManager, when before you finish your game.
Related
I've got a slight problem, I'm writing a gps tracking app to track several objects at once. The data comes in over a serial interface, this is coming in fine from what I can tell. The issue is that I need to continually update the JPanel where the map is created and displayed.
public JPanel mapDisplay(){
JPanel mapPanel = new JPanel();
mapPanel.setSize(560, 540);
Coordinate start = new Coordinate (-34.9286, 138.6);
trackMap.addMapMarker(new MapMarkerDot(1Lat, 1Lon));
trackMap.setDisplayPosition(start,8);
System.out.println(1Lat);
mapPanel.add(trackMap);
mapPanel.setVisible(true);
return mapPanel;
}
This is what I have and it's happy to display the point once but won't update. If I print out the 1Lat variable in the serial method it continually prints, however it only does it once here.
A lot of the answers I've found refer to setting markers by arrays, however that won't work in this case as the objects I'm tracking could be anywhere.
Any help would be greatly appreciated :)
Is it possible to use a worker thread and not use an ArrayList? I would run the risk of missing data if I do.
Not necessarily. In a SwingWorker, your implementation of the doInBackground() method can publish() results as they become available. Note in particular that "Results from multiple invocations of publish() are often accumulated for a single invocation of process()." In your process(), simply loop through the List<Coordinate>, update the route and repaint() the map.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.SwingWorker;
import org.openstreetmap.gui.jmapviewer.Coordinate;
import org.openstreetmap.gui.jmapviewer.JMapViewer;
import org.openstreetmap.gui.jmapviewer.MapPolygonImpl;
/**
* #see http://stackoverflow.com/a/37193636/230513
*/
public class MapWorkerTest {
private final List<Coordinate> route = new ArrayList<>();
private void display() {
JFrame f = new JFrame("MapWorker");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JMapViewer map = new JMapViewer() {
#Override
public Dimension getPreferredSize() {
return new Dimension(640, 480);
}
#Override
public String getToolTipText(MouseEvent e) {
Coordinate c = (Coordinate) getPosition(e.getX(), e.getY());
return c.getLat() + " " + c.getLon();
}
};
map.setToolTipText("");
Coordinate start = new Coordinate(-34.9286, 138.6);
route.add(start);
MapPolygonImpl poly = new MapPolygonImpl(route);
poly.setColor(Color.blue);
map.addMapPolygon(poly);
map.setDisplayPosition(start, 10);
f.add(map);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
new MapWorker(map, start).execute();
}
private class MapWorker extends SwingWorker<Void, Coordinate> {
private final JMapViewer map;
private Coordinate last;
public MapWorker(JMapViewer map, Coordinate start) {
this.map = map;
this.last = start;
}
#Override
protected Void doInBackground() throws Exception {
while (!isCancelled()) {
last = new Coordinate(last.getLat() + 0.0025, last.getLon() + 0.01);
publish(last);
Thread.sleep(1000);
}
return null;
}
#Override
protected void process(List<Coordinate> chunks) {
for (Coordinate c : chunks) {
route.add(c);
}
map.repaint();
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new MapWorkerTest()::display);
}
}
Multiple route management left as a exercise.
I can't figure out why I'm not able to see my thouchpad that I've created, but it works. Here is the code
package com.mygdx.game;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.ui.Touchpad;
import com.badlogic.gdx.scenes.scene2d.utils.Drawable;
public class AnalogStick extends Touchpad {
private static Touchpad.TouchpadStyle touchpadStyle;
private static Skin touchpadSkin;
private static Drawable touchBackground;
private static Drawable touchKnob;
public AnalogStick(float x, float y) {
super(10, getTouchpadStyle());
setBounds(15, 15, 200, 200);
setPosition(x,y);
}
private static Touchpad.TouchpadStyle getTouchpadStyle() {
touchpadSkin = new Skin();
touchpadSkin.add("touchBackground", new Texture("touchBackground.png"));
touchpadSkin.add("touchKnob", new Texture("touchKnob.png"));
touchpadStyle = new Touchpad.TouchpadStyle();
touchBackground = touchpadSkin.getDrawable("touchBackground");
touchKnob = touchpadSkin.getDrawable("touchKnob");
touchpadStyle.background = touchBackground;
touchpadStyle.knob = touchKnob;
return new TouchpadStyle();
}
}
And in my Create class I use this code for adding it into the stage
asMove = new AnalogStick(15,15);
Gdx.input.setInputProcessor(stage);
playerTexture = new Texture(Gdx.files.internal("player.png"));
playerSprite = new Sprite(playerTexture);
stage = new Stage(new ScreenViewport(), batch);
stage.addActor(asMove);
Gdx.input.setInputProcessor(stage);
And in the render method this code
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
There seems to be a problem with your getTouchpadStyle method: it initializes touchpadStyle but instead of returning it, it returns a new and empty style object. In other words, Replace
return new TouchpadStyle();
with
return touchpadStyle;
I have a problem with my pause screen. I made a simple Splash screen, followed by the main menu, where you can start or end the game, followed by a random picture. If the user presses Esc it switches to the pause screen, which is very similar to the main menu. Only difference is that it doesn't generate a new picture if the user clicks on "Continue", instead it just renders the game screen again. But if I press Esc after continuing again, the pause menu appears lower on the screen than it should. If I repeat pressing Continue and then Escape, the buttons eventually moved out of the displayed screen. I didn't find a solution yet, so I made an account here, since this site helped me a lot so far.
Furthermore I want to know if there are things I could improve. I just started with libGDX, so there probably are a lot of things I could've done better, and I want to know that. SO if you have a few improvements, I would be glad to read them :)!
This is the code:
import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.actions.Actions;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
public class GameScreen implements Screen{
private Texture[] monsterTextures = {new Texture(Gdx.files.internal("Ressources/DemonHunter.jpg")), new Texture(Gdx.files.internal("Ressources/WingedDemon.jpg")),
new Texture(Gdx.files.internal("Ressources/Viking.jpg")), new Texture(Gdx.files.internal("Ressources/DemonWarrior.jpg"))};
private Image[] monsterImages = {new Image(monsterTextures[0]), new Image(monsterTextures[1]), new Image(monsterTextures[2]), new Image(monsterTextures[3])};
private Stage gameStage = new Stage(), pauseStage = new Stage();
private Table table = new Table();
private Skin menuSkin = new Skin(Gdx.files.internal("skins/menuSkin.json"),
new TextureAtlas(Gdx.files.internal("skins/menuSkin.pack")));
private TextButton buttonContinue = new TextButton("Continue", menuSkin),
buttonExit = new TextButton("Exit", menuSkin);
private Label title = new Label ("Game", menuSkin);
private int randomMonster;
public static final int GAME_RUNNING = 0;
public static final int GAME_PAUSING = 1;
public static final int GAME_PAUSED = 2;
private int gamestatus = 0;
#Override
public void show() {
randomMonster = 0 + (int)(Math.random() * ((3-0) + 1));
gameStage.addActor(monsterImages[randomMonster]);
}
#Override
public void render(float delta) {
if(Gdx.input.isKeyJustPressed(Keys.ESCAPE)) pauseGame();
if(gamestatus == GAME_RUNNING) {
Gdx.gl.glClearColor(0,0,0,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
gameStage.act();
gameStage.draw();
}
if(gamestatus == GAME_PAUSING) {
buttonContinue.addListener(new ClickListener(){
public void clicked(InputEvent event, float x, float y) {
Gdx.gl.glClearColor(0,0,0,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
gamestatus = GAME_RUNNING;
}
});
buttonExit.addListener(new ClickListener(){
public void clicked(InputEvent event, float x, float y) {
Gdx.app.exit();
}
});
table.add(title).padBottom(40).row();
table.add(buttonContinue).size(150, 60).padBottom(20).row();
table.add(buttonExit).size(150, 60).padBottom(20).row();
table.setFillParent(true);
pauseStage.addActor(table);
Gdx.input.setInputProcessor(pauseStage);
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
pauseStage.act();
pauseStage.draw();
gamestatus = GAME_PAUSED;
}
if(gamestatus == GAME_PAUSED) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
pauseStage.act();
pauseStage.draw();
}
}
public void pauseGame() {
gamestatus = GAME_PAUSING;
}
#Override
public void resize(int width, int height) {
// TODO Auto-generated method stub
}
#Override
public void pause() {
pauseGame();
}
#Override
public void resume() {
// TODO Auto-generated method stub
}
#Override
public void hide() {
// TODO Auto-generated method stub
}
#Override
public void dispose() {
for(int i = 0; i < monsterTextures.length; i++) {
monsterTextures[i].dispose();
}
gameStage.dispose();
pauseStage.dispose();
menuSkin.dispose();
}
}
Thanks, Joshflux
I think your render() method is doing things it shouldn't. Like creating the clickListener and also adding buttons to the table (and possibly some other items in there).
The render method gets called every "frame". You don't want to be recreating this, say 60 times a second. You want to do it once (like when you create the particular screen) and then just draw (render) it every frame.
Restructure your code to do the "Creation" stuff once. The render() method should just draw it. I think you continually adding items to your table each frame may be what is causing the buttons to move off the screen.
I'm trying to play around with Box2D in libgdx but unfortunately I can't seem to understand the way it works.
Here are a few examples that drive me crazy:
.1. It is known that Box2D works with meters. Everybody knows that. Then, why I getting results by Pixels? For instance, if I define some body definition and I set the position to 0,1, It draws the related fixture/sprite at the bottom-left corner of the screen! I thought the 0,0 point in Box2D is at the center of the screen.
.2. Another problem that I have been struggling to understand and solve is the values of the Shapes, Joints and other stuff. Let's start with the shapes: I defined a Polygon shape like this:
shape.setAsBox(1, 2);
Now the shape was supposed to be 2 meters wide and 4 meters height, but it's not the case. What I got is a super small shape.
And lastly, the values of the joints. I defined a body with a polygon shape and a ground body. Now I "pinned" those two to the center of the ground body using the Revolute Joint, with the goal to create some sort of a catapult that rotates nicely within a certain range.
Now I defined also a Mouse Joint so I could drag the catapult(the polygon shape) back and forth nicely, but it seems that I need to set the maxForce of the joint to an enormous value so I can actually see movement/rotation of the catapult! I don't understand. All this matter should be operated by small values, with regard to the values I had to set up.
Here is my very basic code that contains all of the above. Please tell me what I'm doing wrong, I'm freaking out here:
GameScreen.java
package com.david.box2dpractice;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.physics.box2d.ChainShape;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.physics.box2d.joints.RevoluteJointDef;
import com.badlogic.gdx.utils.Array;
public class GameScreen implements Screen{
private Box2DDebugRenderer debugRenderer;
private Texture texture;
private Sprite sprite;
private Sprite tempSprite;
private SpriteBatch batch;
private Body arm , ground;
private World world;
public OrthographicCamera camera;
private RevoluteJointDef jointDef;
private Array<Body> tempBodies;
public GameScreen() {
debugRenderer = new Box2DDebugRenderer();
batch = new SpriteBatch();
texture = new Texture(Gdx.files.internal("catapult_arm.png"));
camera = new OrthographicCamera();
camera.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
tempBodies = new Array<Body>();
}
#Override
public void render(float delta) {
// TODO Auto-generated method stub
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
world.getBodies(tempBodies);
batch.begin();
for(Body body : tempBodies) {
if(body.getUserData() != null && body.getUserData() instanceof Sprite) {
tempSprite = (Sprite) body.getUserData();
tempSprite.setPosition(body.getPosition().x-tempSprite.getWidth()/2, body.getPosition().y-tempSprite.getHeight()/2);
tempSprite.setRotation((float) Math.toDegrees(body.getAngle()));
tempSprite.draw(batch);
}
}
batch.end();
debugRenderer.render(world, camera.combined);
world.step(1/60f, 6, 2);
}
#Override
public void resize(int width, int height) {
// TODO Auto-generated method stub
Gdx.app.log("System", "resize() was invoked");
}
#Override
public void show() {
// TODO Auto-generated method stub
Gdx.app.log("System", "show() was invoked");
world = new World(new Vector2(0,0), true);
sprite = new Sprite(texture);
BodyDef bodyDef = new BodyDef();
bodyDef.position.set(Gdx.graphics.getWidth()/2,Gdx.graphics.getHeight()/2+sprite.getHeight()/2);
bodyDef.type = BodyType.DynamicBody;
// The shape
PolygonShape shape = new PolygonShape();
shape.setAsBox(11, 91);
// The fixture
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
fixtureDef.density = .10f;
arm = world.createBody(bodyDef);
arm.createFixture(fixtureDef);
sprite.setOrigin(sprite.getWidth()/2, sprite.getHeight()/2);
arm.setUserData(sprite);
shape.dispose();
bodyDef = new BodyDef();
bodyDef.position.set(Gdx.graphics.getWidth()/2,Gdx.graphics.getHeight()/2);
bodyDef.type = BodyType.StaticBody;
ChainShape shape2 = new ChainShape();
shape2.createChain(new Vector2[] {new Vector2(-20*Pixels_To_Meters,0),new Vector2(20*Pixels_To_Meters,0)});
// The fixture
fixtureDef.shape = shape2;
fixtureDef.restitution = .65f;
fixtureDef.friction = .75f;
ground = world.createBody(bodyDef);
ground.createFixture(fixtureDef);
shape2.dispose();
// joint
jointDef = new RevoluteJointDef();
jointDef.bodyA = arm;
jointDef.bodyB = ground;
jointDef.localAnchorB.set(ground.getLocalCenter());
jointDef.localAnchorA.set(arm.getLocalCenter().x,arm.getLocalCenter().y-sprite.getHeight()/2);
jointDef.enableLimit = true;
jointDef.enableMotor = true;
jointDef.motorSpeed = 15;
jointDef.lowerAngle = (float) -Math.toRadians(75);
jointDef.upperAngle = (float) -Math.toRadians(9);
jointDef.maxMotorTorque = 4800;
world.createJoint(jointDef);
Gdx.input.setInputProcessor(new InputHandler(arm,ground,world,camera));
}
#Override
public void hide() {
// TODO Auto-generated method stub
Gdx.app.log("System", "hide() was invoked");
dispose();
}
#Override
public void pause() {
// TODO Auto-generated method stub
Gdx.app.log("System", "pause() was invoked");
}
#Override
public void resume() {
// TODO Auto-generated method stub
Gdx.app.log("System", "resume() was invoked");
}
#Override
public void dispose() {
// TODO Auto-generated method stub
Gdx.app.log("System", "dispose() was invoked");
texture.dispose();
batch.dispose();
world.dispose();
}
}
InputHandler.java
package com.david.box2dpractice;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.badlogic.gdx.physics.box2d.QueryCallback;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.physics.box2d.joints.MouseJoint;
import com.badlogic.gdx.physics.box2d.joints.MouseJointDef;
public class InputHandler implements InputProcessor{
Body ground;
MouseJoint mouseJoint;
MouseJointDef mouseJointDef;
World world;
Vector2 target,initialPos;
Vector3 temp;
QueryCallback query;
OrthographicCamera camera;
boolean firstTime = true;
public InputHandler(Body arm, Body ground, final World world, OrthographicCamera camera) {
this.camera = camera;
this.ground = ground;
this.world = world;
mouseJointDef = new MouseJointDef();
target = new Vector2();
temp = new Vector3();
mouseJointDef.bodyA = ground;
mouseJointDef.collideConnected = true;
mouseJointDef.maxForce = 9000;
query = new QueryCallback() {
#Override
public boolean reportFixture(Fixture fixture) {
// TODO Auto-generated method stub
if(!fixture.testPoint(temp.x, temp.y))
return true;
if(firstTime) {
initialPos = new Vector2(fixture.getBody().getPosition().x,fixture.getBody().getPosition().y);
firstTime = false;
}
mouseJointDef.bodyB = fixture.getBody();
mouseJointDef.target.set(temp.x,temp.y);
mouseJoint = (MouseJoint) world.createJoint(mouseJointDef);
return false;
}
};
}
#Override
public boolean keyDown(int keycode) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean keyUp(int keycode) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean keyTyped(char character) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
// TODO Auto-generated method stub
camera.unproject(temp.set(screenX, screenY, 0));
world.QueryAABB(query, temp.x, temp.y, temp.x, temp.y);
return true;
}
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
// TODO Auto-generated method stub
if(mouseJoint == null)
return false;
mouseJoint.setTarget(initialPos);
world.destroyJoint(mouseJoint);
mouseJoint = null;
firstTime = true;
return true;
}
#Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
// TODO Auto-generated method stub
if(mouseJoint == null)
return false;
camera.unproject(temp.set(screenX, screenY, 0));
mouseJoint.setTarget(target.set(temp.x, temp.y));
return true;
}
#Override
public boolean mouseMoved(int screenX, int screenY) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean scrolled(int amount) {
// TODO Auto-generated method stub
return false;
}
}
If you could help me out here I would really really appreaciate that. Thanks!!
Box2D is only the Physic-Engine, the logical part. It does nothing with the view, so it is your job to convert the meters to pixels.
In Libgdx this could be done by using a Camera.
You are allready using a Camera, but you give it the "wrong" Viewport-Size.
You tell the Camera to be as big as the game (Gdx.graphics.getWidth, Gdx.graphics.getHeight), instead you should think about how many meters you want to show on your Screen.
If you want to show 80 meters in width and 45 meters i height (16/9), then you need to setup the Camera like this:
camera = new OrthographicCamera();
camera.setToOrtho(false, 80, 45);
So if your Game has a resolution of 1600*900 px, every meter would be convertet to 20px (camera does this for you), if you are using a resolution of 800*450, every meter would be converted to 10px.
Also box2Ds P(0/0) is not in the middle of the Screen, it is nowhere on the screen. It is on the P(0/0) of the box2D world, it is your job to draw it in the middle or the bottom or whererever you want.
Again, this is done by Camera. the Cameras P(0/0) by default is in the middle of the Screen, but you can move the camera arround, so it could be everywhere.
Now it should be clear, that the shape you created is not "super-small", but you just did not "zoom in". A 3m long car seems verry small if you watch it from a few 100m of distance. If you instead stand 1m away from it, you are almost unable to see the whole car at one time, as it is bigger then your "viewport".
I am not sure about the joints/forces, but it could be, that your problem is solved, if you "zoom in" by using a camera. But i also can be wrong, as i never used box2D...
Some tutorials:
IForce2D - Box2D, it is a tutorial fpr C++. but by reading the explanations you should understand it and be able to implement it in java/libgdx.
Using Box2D in Libgdx Game, this tutorial showes you how to create a game with box2D and libgdx. It really helps by understanding how to connect box2D with Libgdx.
I've been working on this for some time, and I'd really appreciate some help right now.
I'm trying to get the JFrame containing the text input fields to close from my actionPerformed method, but I can't seem to get anything to work. JFrame.dispose wont let me access the right Jframe, and setVisible(false) is equally useless, unless I'm doing this completely wrong.
//halp
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
class PersonInput extends JPanel
implements ActionListener {
//Fields for data entry
private JFormattedTextField firstField, lastField, dateField;
public String x[] = new String[3];
public PersonInput() {
//Values for the fields
String first = "First Name";
String last = "Last Name";
String date = "MM/DD/YYYY";
//Create the text fields and set them up.
firstField = new JFormattedTextField();
firstField.setValue(new String(first));
lastField = new JFormattedTextField();
lastField.setValue(new String(last));
dateField = new JFormattedTextField();
dateField.setValue(new String(date));
dateField.setColumns(10);
JButton ok = new JButton("OK");
ok.setVerticalTextPosition(AbstractButton.BOTTOM);
ok.setHorizontalTextPosition(AbstractButton.CENTER);
ok.setActionCommand("ok");
ok.addActionListener(this);
ok.setToolTipText("Confirms user input and continues with the program.");
JPanel buttons = new JPanel(new GridLayout(0,1));
buttons.add(ok);
//Layout the text fields in a panel.
JPanel fieldPane = new JPanel(new GridLayout(0,1));
fieldPane.add(firstField);
fieldPane.add(lastField);
fieldPane.add(dateField);
//Put the panels in this panel, labels on left,
//text fields on right.
setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
add(fieldPane, BorderLayout.CENTER);
add(buttons, BorderLayout.LINE_END);
}
public void actionPerformed(ActionEvent e) {
if ("ok".equals(e.getActionCommand()))
{
JFrame frame1 = new JFrame("People Sorter");
x[0] = firstField.getText();
x[1] = lastField.getText();
x[2] = dateField.getText();
JOptionPane.showMessageDialog(frame1, "Person has been added.");
dispPerson();
frame.setVisible(false);
}
}
public void dispPerson()
{
System.out.println(x[0] + x[1] + x[2]);
}
public static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("Person Input");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Add contents to the window.
frame.add(new PersonInput());
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
//Turn off metal's use of bold fonts
UIManager.put("swing.boldMetal", Boolean.FALSE);
createAndShowGUI();
}
});
}
}
I'm all ears if anyone has any ideas; I've been stressed over this all day. Thanks much for lending me your time!
EDIT: Just for clarification, the frame I'm trying to close is the one instantiated in the createAndShowGUI method.
it seems that the problem is that we are trying to merge both static and non static contents. For a short explanation static contents can be referred without need of creating an instance (object) of that class. Which means that createAndShowGUI can be called:
inside another static method (like main)
From class reference PersonInput.createAndShowGUI()
or from an object, but that method or attribute will be always the same, static attributes are shared.
I can suggest 2 ways to solve your problem.
One is pass the object frame to PersonInput
//halp
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
class PersonInput extends JPanel
implements ActionListener {
//Fields for data entry
private JFormattedTextField firstField, lastField, dateField;
public String x[] = new String[3];
JFrame frame;
public PersonInput(JFrame frame) {
this.frame = frame;
//the rest of your code
}
The other way is to have the frame object outside the method and declare it static.
static JFrame frame = new JFrame("Person Input");;
public static void createAndShowGUI() {
//Create and set up the window.
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Add contents to the window.
frame.add(new PersonInput());
//Display the window.
frame.pack();
frame.setVisible(true);
}
Remember that static variable cannot be referenced from a static context