2
\$\begingroup\$

So I am working on programming a java 2D platformer for fun on the side and I have a rendered TMX level and a box2d body (just a circle shape) that I am currently using as my player. All the controls work good, but the camera is off center but follows player perfectly. What I am trying to do is to get the sprite to be attached to the body. I am aware they don't work perfectly and that the sprite basically just has to follow the body but can't get it to work.

Right now my sprite displays off the map because it goes to the bottom left corner by default and my map is messed up. I have tried drawing the sprite animation to the x and y from the body position but that isn't working. Here is my code

This is my class and create **I cut out some stuff that wasn't relevant so don't mind the random declarations*

public class MyGdxGame extends ApplicationAdapter implements InputProcessor {
    Texture img;
    TiledMap tiledMap;
    OrthographicCamera camera;
    TiledMapRenderer tiledMapRenderer;
    SpriteBatch sb;
    Texture texture;
    Player player;
    Sprite sprite;
    static float w,h;


    //Box2D Variables
    World world;
    Box2DDebugRenderer b2dr;

    Animator mario;
    private Hud hud;
    public static final int V_WIDTH = 485;
    public static final int V_HEIGHT = 515;
    private static final int FRAME_COLS = 8;
    private static final int FRAME_ROWS = 1;
    public static final float PPM = 100f;
    public SpriteBatch batch;
    Animation runAnimation;
    Texture runSheet;
    TextureRegion[] runFrames;
    TextureRegion currentFrame;

    float stateTime;


    float sbX = 80;
    float sbY = 12;
    final float timeStamp = 1.0f / 30.0f;


@Override
public void create (){


    GdxNativesLoader.load();
    w = Gdx.graphics.getWidth();
    h = Gdx.graphics.getHeight();

    tiledMap = new TmxMapLoader().load("Level1-1.tmx");
    tiledMapRenderer = new OrthogonalTiledMapRenderer(tiledMap, 1f / PPM);
    Gdx.input.setInputProcessor(this);

    world = new World(new Vector2(0, -10f), true); //Vector is for gravity
    b2dr = new Box2DDebugRenderer();
    player = new Player(world);
    BodyDef bdef = new BodyDef();
    PolygonShape shape = new PolygonShape();
    FixtureDef fdef = new FixtureDef();
    Body body;
    //Create ground bodies/fixtures
    for(MapObject object : tiledMap.getLayers().get(2).getObjects().getByType(RectangleMapObject.class)){
        Rectangle rect = ((RectangleMapObject) object).getRectangle();

        bdef.type = BodyDef.BodyType.StaticBody;
        bdef.position.set(((rect.getX() + rect.getWidth() / 2) / PPM), ((rect.getY() + rect.getHeight() /2) / PPM));

        body = world.createBody(bdef);
        shape.setAsBox((rect.getWidth() / 2) / PPM, (rect.getHeight() / 2 / PPM));
        fdef.shape = shape;
        body.createFixture(fdef);
    }
    //Create pipe bodies/fixtures
    for(MapObject object : tiledMap.getLayers().get(3).getObjects().getByType(RectangleMapObject.class)){
        Rectangle rect = ((RectangleMapObject) object).getRectangle();

        bdef.type = BodyDef.BodyType.StaticBody;
        bdef.position.set(((rect.getX() + rect.getWidth() / 2) / PPM), ((rect.getY() + rect.getHeight() /2) / PPM));

        body = world.createBody(bdef);
        shape.setAsBox((rect.getWidth() / 2) / PPM, (rect.getHeight() / 2) / PPM);
        fdef.shape = shape;
        body.createFixture(fdef);
    }
    //Create brick bodies/fixtures
    for(MapObject object : tiledMap.getLayers().get(4).getObjects().getByType(RectangleMapObject.class)){
        Rectangle rect = ((RectangleMapObject) object).getRectangle();

        bdef.type = BodyDef.BodyType.StaticBody;
        bdef.position.set(((rect.getX() + rect.getWidth() / 2) / PPM), ((rect.getY() + rect.getHeight() /2) / PPM));

        body = world.createBody(bdef);
        shape.setAsBox((rect.getWidth() /2 / PPM), (rect.getHeight() /2 / PPM));
        fdef.shape = shape;
        body.createFixture(fdef);
    }

    camera = new OrthographicCamera();
    camera.setToOrtho(false, w / PPM, h / PPM);
    camera.update();
    runSheet = new Texture("Squirrel-Run.png");

    TextureRegion[][] tmp = TextureRegion.split(runSheet, runSheet.getWidth()/FRAME_COLS, runSheet.getHeight()/FRAME_ROWS);

    runFrames = new TextureRegion[FRAME_COLS * FRAME_ROWS];
    int index = 0;
    for(int i = 0; i < FRAME_ROWS; i++){
        for(int j = 0; j < FRAME_COLS; j++){
            runFrames[index++] = tmp[i][j];
        }
    }
    runAnimation = new Animation(0.025f, runFrames);
    sb = new SpriteBatch();

    stateTime = 0f;

    hud = new Hud(sb);
    world.step(timeStamp, 6, 2);
}

this is my render, update and input methods

public void update(){

    camera.update();


} 
public void handleInput(){
    if(Gdx.input.isKeyJustPressed(Input.Keys.SPACE))
        player.b2body.applyLinearImpulse(new Vector2(0, 4f), player.b2body.getWorldCenter(), true);

    if(Gdx.input.isKeyPressed(Input.Keys.RIGHT) && player.b2body.getLinearVelocity().x <= 2)
        player.b2body.applyLinearImpulse(new Vector2(0.1f, 0), player.b2body.getWorldCenter(), true);
    if(Gdx.input.isKeyPressed(Input.Keys.LEFT) && player.b2body.getLinearVelocity().x >= -2)
        player.b2body.applyLinearImpulse(new Vector2(-0.1f, 0), player.b2body.getWorldCenter(), true);   

}
@Override
public void render (){
    Gdx.gl.glClearColor(0, 0, 0, 1);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
    tiledMapRenderer.render();

    tiledMapRenderer.setView(camera);
    handleInput();

    //Render our box2dDebugLines
    b2dr.render(world, camera.combined);

    world.step(timeStamp, 6, 2);
    camera.position.set(player.b2body.getWorldCenter().x, player.b2body.getWorldCenter().y, 0);
    camera.update();

    stateTime += Gdx.graphics.getDeltaTime();
    currentFrame = runAnimation.getKeyFrame(stateTime, true);

    sb.begin();
    sb.draw(currentFrame, player.b2body.getPosition().x / PPM, player.b2body.getPosition().y / PPM);
    sb.end();
    sb.setProjectionMatrix(hud.stage.getCamera().combined);
    hud.stage.draw();

And this is my player class

public final class Player {

public int x,y;
public Vector3 position;
public World world;
public com.badlogic.gdx.physics.box2d.Body b2body;


public Player(World world) {
    this.world = world;
    defineSprite();
}
public void defineSprite(){
    BodyDef bdef = new BodyDef();
    bdef.position.set(32 / MyGdxGame.PPM, 32 / MyGdxGame.PPM);
    bdef.type = BodyDef.BodyType.DynamicBody;
    b2body = world.createBody(bdef);

    FixtureDef fdef = new FixtureDef();
    CircleShape shape = new CircleShape();
    shape.setRadius(5 / MyGdxGame.PPM);


    fdef.shape = shape;
    b2body.createFixture(fdef);

}

public float getX() {
    return position.x;
}
public float getY() {
    return position.y;
}
public Vector3 getPosition() {
    return position;
}

public float getWidth() {
    return 32 / MyGdxGame.PPM;
}

public float getHeight() {
    return 32 / MyGdxGame.PPM;
}




}

I know my code is jumbled I am new to programming, I will clean up with separate classes once I get this working. I was looking into .setUserData but I don't know what else i need to put for this. Can anyone point me in the right direction of my camera/attaching the sprite to the body? Thanks

\$\endgroup\$
3
\$\begingroup\$

Two (simple) solutions could look something like this:


Give the player class a Sprite (best).

// In the player class, give the player a Sprite
private Sprite sprite = new Sprite(new Texture("your/texture/location.png"));

// Then we can add a simple render method to our player class.
public void render(SpriteBatch batch) {
    // First we position and rotate the sprite correctly
    int posX = b2Body.position.x * MyGdxGame.PPM;
    int posY = b2Body.position.y * MyGdxGame.PPM;
    float rotation = Math.toDegrees(b2Body.getAngle());
    sprite.setPosition(x, y);
    sprite.setRotation(rotation);

    // Then we simply draw it as a normal sprite.
    sprite.draw(batch);
}

// Then in your render method you can replace this
sb.draw(currentFrame, player.b2body.getPosition().x / PPM, player.b2body.getPosition().y / PPM);

// with this
player.render(sb);

Attach a Sprite as user data to the body.

// Same as above, give the player class a sprite.
// Then in your defineSprite() method add this sprite to your body's user data.
b2Body.setUserData(sprite);

// Remember to position and rotate your sprite like the previous example.

// Then in your render method you can replace this
sb.draw(currentFrame, player.b2body.getPosition().x / PPM, player.b2body.getPosition().y / PPM);

// With this. This might throw a warning in your IDE we're
// that doing an unchecked / unsafe cast. But since we know that our 
// body's user data will always be a Sprite we can ignore it for now.
((Sprite) player.b2Body.getUserData()).draw(sb);

Remember to dispose of all textures you use when you close the game! You can dispose of a Sprite's texture like this sprite.getTexture().dispose();.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.