简体   繁体   中英

setCenter() Method is not properly centering sprite texture on box2d fixture

The past few days I've been trying to figure out a display bug I don't understand. I've been working on a simple 2d platformer with box2d and orthogonal Tiled maps. So far so good, the physics work and using the b2d debug renderer I can assert proper player fixture and camera movement through the level.

Now next step I've tried to load textures to display sprites instead of debug shapes. This is where I stumble. I can load animations for my player body/fixture, but when I use the setCenter() method to center the texture on the fixture it is always out of center.

I've tried approaches via halving texture witdths and heights hoping to center the texture on the player fixture but I get the exact same off position rendering. I've played aorund with world/camera/screen unit coordinates but the misalignement persists.

I'm creating the player in my Player class with the following code.

First I define the player in box2d:

     //define player's physical behaviour
     public void definePlayer() {
        //definitions to later use in a body
        BodyDef bdef = new BodyDef();
        bdef.position.set(120 / Constants.PPM, 60 / Constants.PPM);
        bdef.type = BodyDef.BodyType.DynamicBody;
        b2body = world.createBody(bdef);

        //Define needed components of the player's main fixture
        FixtureDef fdef = new FixtureDef();
        PolygonShape shape = new PolygonShape();
        shape.setAsBox(8 / Constants.PPM, 16 / Constants.PPM); //size of the player hitbox
        //set the player's category bit
        fdef.filter.categoryBits = Constants.PLAYER_BIT;
        //set which category bits the player should collide with. If not mentioned here, no collision     occurrs
        fdef.filter.maskBits = Constants.GROUND_BIT |
                            Constants.GEM_BIT | 
                            Constants.BRICK_BIT | 
                            Constants.OBJECT_BIT |
                            Constants.ENEMY_BIT |
                            Constants.TREASURE_CHEST_BIT |
                            Constants.ENEMY_HEAD_BIT |
                            Constants.ITEM_BIT;

        fdef.shape = shape;
        b2body.createFixture(fdef).setUserData(this);
    }

Then I call the texture Region to be drawn in the Player class constructor:

        //define  in box2d
        definePlayer();
        //set initial values for the player's location, width and height, initial animation.
        setBounds(0, 0, 64 / Constants.PPM, 64 / Constants.PPM);
        setRegion(playerStand.getKeyFrame(stateTimer, true));

And finally, I update() my player:

public void update(float delta) {
        //center position of the sprite on its body 
        // setPosition(b2body.getPosition().x - getWidth() / 2, b2body.getPosition().y - getHeight() / 2);
        setCenter(b2body.getPosition().x, b2body.getPosition().y);
           
        
        setRegion(getFrame(delta));
        
        //set all the boolean flags during update cycles approprietly. DO NOT manipulate b2bodies
        //while the simulation happens! therefore, only set flags there, and call the appropriate
        //methods outside the simulation step during update
        checkForPitfall();
        checkIfAttacking();
    }

And my result is this, facing right and this, facing left

Update: I've been trying to just run

setCenter(b2body.getPosition().x, b2body.getPosition().y);

as suggested, and I got the following result: facing right and facing left .

The sprite texture flip code is as follows:

if((b2body.getLinearVelocity().x < 0 || !runningRight) && !region.isFlipX()) {
        region.flip(true, false);
        runningRight = false;
    } else if ((b2body.getLinearVelocity().x > 0 || runningRight) && region.isFlipX()) {
        region.flip(true, false);
        runningRight = true;
    }

I'm testing if either the boolean flag for facing right is set or the x-axis velocity of my player b2body has a positive/negative value and if my texture region is already flipped or not and then use libGDX's flip() accordingly. I should not be messing with fixture coords anywhere here, hence my confusion.

The coordinates of box2d fixtures are offsets from the position, the position isn't necessarily the center (although it could be depending on your shape definition offsets). So in your case i think the position is actually the lower left point of the box2d polygon shape.

In which case you don't need to adjust for width and height because sprites are also drawn from bottom left position. So all you need is;

setPosition(b2body.getPosition().x , b2body.getPosition().y );

I'm guessing you flip the box2d body when the player looks left the position of the shape is now bottom right so the sprite offset of width/2 and height/2 is from the bottom right instead. So specifically when you are looking left you need an offset of

setPosition(b2body.getPosition().x - getWidth() , b2body.getPosition().y );

I think looking right will be fixed from this, but i don't know for sure how you handle looking left in terms of what you do to the body, but something is done because the offset changes entirely as shown in your capture. If you aren't doing some flipping you could add how you handle looking right to the question.

EDIT It seems the answer was that the sprite wasn't centered in the sprite sheet and this additional space around the sprite caused the visual impression of being in the wrong place (see comments).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM