androidlibgdxspine

spine 2d coordinate system libgdx


i don't know what im doing wrong...i think im having brain freeze. I am really struggling with converting my spine objects pixel coordinates to world coordinates. I have recently converted all my code to work with Ashley ecs and i cant seem to get my spine object to display in the correct position. i have a system which handles the rendering and positioning of my spine object but i cant seem to get it displaying in the correct position. I'm hoping someone can point me in the correct direction!

i have included my code for the spine rendering system...hope you can help! i want to place the spine object at the same position as my box 2d object which is using world coordinates. but spine is using pixel coordinates. i have also included an image to show you what is happening. (the grey square near the middle right of the screen is where i want my spine object to be!)

Amarino

in game image

    public class SpineRenderSystem extends IteratingSystem {
    private static final String TAG = com.chaingang.freshstart.systems.SpineRenderSystem.class.getName();

    private PolygonSpriteBatch pBatch;
    SkeletonMeshRenderer skeletonMeshRenderer;
    private boolean process = true;

    BodyComponent bodyComp;
    Spine2DComponent spineComp;

    public SpineRenderSystem(PolygonSpriteBatch pBatch){
        super(Family.all(RenderableComponent.class, Spine2DComponent.class, PositionComponent.class).get());
        this.pBatch = pBatch;
        skeletonMeshRenderer = new SkeletonMeshRenderer();
        skeletonMeshRenderer.setPremultipliedAlpha(true);

    }


    @Override
    protected void processEntity(Entity entity, float deltaTime) {

        bodyComp = Mappers.body.get(entity);
        spineComp = Mappers.spine2D.get(entity);

        float offsetX = 100.00f/Gdx.graphics.getWidth(); //100 equal world width
        float offsetY = 50.00f/Gdx.graphics.getHeight(); //50 equals world height

        pBatch.begin();
            spineComp.skeleton.setX((bodyComp.body.getPosition().x / offsetX) );
            spineComp.skeleton.setY((bodyComp.body.getPosition().y) / offsetY);

            skeletonMeshRenderer.draw(pBatch,spineComp.skeleton);
            //spineComp.get(entity).skeleton.setFlipX(player.dir == -1);
            spineComp.animationState.apply(spineComp.skeleton);
            spineComp.skeleton.updateWorldTransform();
        pBatch.end();


    }
}

Solution

  • What I do for my spine renders is look at the bounding box size in pixels in spine. This is usually in the order of 100s of pixels. But if you are working with box2d scales, it is recommended that you think of 1 as 1 meter.

    With this in mind I will scale a human spine animation with a hip y coordinate of 200 pixels by dividing it by 200, or there about.

    Once you have this ratio, then when you build your Spine Skeleton you can do this (sorry, I do all my libgdx stuff in Kotlin now):

    val atlasLoader = AtlasAttachmentLoader(atlas)
    val skeletonJson = SkeletonJson(atlasLoader)
    skeletonJson.scale = 1/200f
    

    Then you might also want to handle an offset for rendering your spine object, as I see you are trying to do, because possibly your root bone is in the center of your spine object (a hip for example). However, you are doing a division operation, which I guess is exploratory as offsets should be an addition or subtraction. Here is how I do it using the spine pixel coordinates (again, sorry for the Kotlin, but I like it):

    //In some object or global state we have this stuff
    var skeleton: Skeleton
    var skeletonRenderer = SkeletonRenderer<PolygonSpriteBatch>()
    
    
    //Then in the rendering code
    val offset = Vector2(0f,-200f)
    val position = physicsRoot.position().add(offset)
    skeleton.setPosition(position.x, position.y)
    skeleton.updateWorldTransform()
    skeletonRenderer.draw(batch, skeleton)
    

    That should get your spine stuff working as you expect.