Libgdx - 使用对象的运动来旋转对象

Libgdx - Rotate an object using its movement

我正在尝试为 SpriteAnimation 实现自动旋转方法 class(尝试移植 SpriteAnimation)。

一切正常,精灵绘制正确(它使用正确的动画)它只是没有正确旋转,通常它似乎仅在其目标与其匹配后才指向原点 (0, 0)位置,而我希望它的旋转随着它的移动而更新,我已经尝试了度数和弧度,两者都不起作用。它应该旋转以匹配当前的方向。我已经为此苦苦挣扎了大约一个星期,但仍然没有得到想要的结果。

Full Code Here

相关代码:

来自 SpriteAnimation

// The x position of the sprite's upper left corner pixel.
public int getX() { return (int)position.x; }
public void setX(int value)
{
    prevPosition.x = position.x;
    position.x = value;
    updateRotation();
}

// The y position of the sprite's upper left corner pixel.
public int getY() { return (int)position.y; }
public void setY(int value)
{
    prevPosition.y = position.y;
    position.y = value;
    updateRotation();
}

void updateRotation()
{
    if (rotateByPosition)
    {
        Vector2 rotationVector = new Vector2(position.x - prevPosition.x, position.y - prevPosition.y);
        rotationRad = rotationVector.angle();
        rotationDeg = rotationRad * MathUtils.radiansToDegrees;
    }
}

public void MoveBy(int x, int y)
{
    prevPosition = new Vector2(position);
    position.x += x;
    position.y += y;
    updateRotation();
}

public void Update(float deltaTime)
{
    // Don't do anything if the sprite is not animating
    if (animating)
    {
        // If there is not a currently active animation
        if (getCurrentFrameAnimation() == null)
        {
            // Make sure we have an animation associated with this sprite
            if (animations.size() > 0)
            {
                // Set the active animation to the first animation
                // associated with this sprite
                String[] sKeys = new String[animations.size()];
                int index = 0;
                for (Entry<String, FrameAnimation> mapEntry : animations.entrySet()) {
                    sKeys[index] = mapEntry.getKey();
                    index++;
                }
                setCurrentAnimation(sKeys[0]);
            }
            else
            {
                return;
            }
        }

        // Run the Animation's update method
        getCurrentFrameAnimation().Update(deltaTime);

        // Check to see if there is a "follow-up" animation named for this animation
        if (getCurrentFrameAnimation().getNextAnimation() != null && !getCurrentFrameAnimation().getNextAnimation().isEmpty())
        {
            // If there is, see if the currently playing animation has
            // completed a full animation loop
            if (getCurrentFrameAnimation().getPlayCount() > 0)
            {
                // If it has, set up the next animation
                setCurrentAnimation(getCurrentFrameAnimation().getNextAnimation());
            }
        }
    }
}

public void Draw(SpriteBatch spriteBatch, int xOffset, int yOffset)
{
    updateRotation();   // Calling this while testing to make sure that it is being called
    spriteBatch.draw(getCurrentTextureRegion(), getPosition().x + xOffset - center.x, getPosition().y + yOffset - center.y, center.x, center.y, getCurrentFrameAnimation().getFrameWidth(), getCurrentFrameAnimation().getFrameHeight(), 1.0f, 1.0f, rotationRad);
}

测试屏幕class

package com.darkstudio.darkisle.screens;

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.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.darkstudio.darkisle.DarkIsle;
import com.delib.engine.sprite.MobileSprite;

/**
 * Created by DarkEnder on 2017/06/27.
 */

public class TestScreen implements Screen {
    final DarkIsle game;
    OrthographicCamera camera;
    Texture tankTexture;

    MobileSprite mouseTank;

    public TestScreen(final DarkIsle game)
    {
        this.game = game;

        camera = new OrthographicCamera();
        configureCamera();

        tankTexture = new Texture(Gdx.files.internal("MulticolorTanks.png"));

        mouseTank = new MobileSprite(tankTexture, 32, 32);
        mouseTank.getSprite().AddAnimation("red", 0, 32, 32, 32, 8, 0.1f);
        mouseTank.getSprite().AddAnimation("purple", 0, 128, 32, 32, 8, 0.1f, "red");
        mouseTank.getSprite().AddAnimation("yellow", 0, 64, 32, 32, 8, 0.1f);
        mouseTank.getSprite().setAutoRotate(true);
        mouseTank.setPosition(new Vector2(100, 100));
        mouseTank.setTarget(new Vector2(mouseTank.getPosition()));
        mouseTank.setIsPathing(true);
        mouseTank.setEndPathAnimation("yellow");
        mouseTank.setLoopPath(false);
        mouseTank.setSpeed(2);
    }

    @Override
    public void show() {

    }

    @Override
    public void render(float delta) {
        Gdx.gl.glClearColor(0, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);

        update();

        game.batch.begin();

        mouseTank.draw(game.batch);

        game.batch.end();
    }

    @Override
    public void resize(int width, int height) {

    }

    @Override
    public void pause() {

    }

    @Override
    public void resume() {

    }

    @Override
    public void hide() {

    }

    @Override
    public void dispose() {

    }

    private void configureCamera()
    {
        Vector3 camPos = new Vector3(camera.position);

        float size = 800;
        float cameraWidth = 0;
        float cameraHeight = 0;

        if (Gdx.graphics.getHeight() < Gdx.graphics.getWidth())
        {
            cameraWidth = size;
            cameraHeight = size * Gdx.graphics.getHeight() / Gdx.graphics.getWidth();
        }
        else
        {
            cameraWidth = size * Gdx.graphics.getWidth() / Gdx.graphics.getHeight();
            cameraHeight = size;
        }

        camera.setToOrtho(true, cameraWidth, cameraHeight);
        camera.position.set(camPos.x + camera.viewportWidth / 2f, camPos.y + camera.viewportHeight / 2f, 0);
    }

    private void update() {
        int xTouch = Gdx.input.getX(0);
        int yTouch = Gdx.input.getY(0);
        mouseTank.setTarget(xTouch, yTouch);
        mouseTank.update(Gdx.graphics.getDeltaTime());
    }
}

编辑:现在只是说我已经尝试在 MathUtils 中使用 atan2,它给出了相同的结果。

MobileSprite更新方法

public void update(float deltaTime)
{
    if (active && movingTowardsTarget)
    {
        if ((target != null))
        {
            // Get a vector pointing from the current location of the sprite
            // to the destination.
            Vector2 Delta = new Vector2(target.x - sprite.getX(), target.y - sprite.getY());

            if (Delta.len() > getSpeed())
            {
                Delta.nor();
                Delta.scl(getSpeed());
                getPosition().add(Delta);
            }
            else
            {
                if (target == sprite.getPosition())
                {
                    if (pathing)
                    {
                        if (queuePath.size() > 0)
                        {
                            target = queuePath.remove();
                            if (loopPath)
                            {
                                queuePath.remove(target);
                            }
                        }
                        else
                        {
                            if (!(endPathAnimation == null))
                            {
                                if (!(getSprite().getCurrentAnimation() == endPathAnimation))
                                {
                                    getSprite().setCurrentAnimation(endPathAnimation);
                                }
                            }

                            if (deactivateAtEndOfPath)
                            {
                                setIsActive(false);
                            }

                            if (hideAtEndOfPath)
                            {
                                setIsVisible(false);
                            }
                        }
                    }
                }
                else
                {
                    sprite.setPosition(target);
                }
            }
        }
    }
    if (active)
        sprite.Update(deltaTime);
}

获取弧度角:

void updateRotation()
{
    if (rotateByPosition)
    {
        Vector2 rotationVector = new Vector2(position.x - prevPosition.x, position.y - prevPosition.y);
        rotationRad = rotationVector.angleRad();
        rotationDeg = rotationRad * MathUtils.radiansToDegrees;
    }
}

绘制方法需要角度:

spriteBatch.draw(
            getCurrentTextureRegion(),
            getPosition().x + xOffset - center.x,
            getPosition().y + yOffset - center.y,
            center.x, center.y,
            getCurrentFrameAnimation().getFrameWidth(), getCurrentFrameAnimation().getFrameHeight(),
            1.0f, 1.0f,
            rotationDeg
    );

屏幕鼠标位置是从左上角开始渲染器需要从左下角开始:

int xTouch = Gdx.input.getX(0);
int yTouch = Gdx.graphics.getHeight() - Gdx.input.getY(0);