title: Libgdx - Rotate an object using its movement
body: <p>I'm trying to implement an autorotation method for a SpriteAnimation class (trying to port <a href="http://xnaresources.com/default.asp?page=Tutorial:SpriteEngine:3" rel="nofollow noreferrer">SpriteAnimation</a>).</p>
  
  <p>Everything is working, the sprite draws correctly (it uses the correct animations) it just doesn't rotate properly if at all, normally it seems to point to the origin (0, 0) only after its target matches its position while I want its rotation to update as it moves, i've tried both degrees and radians, neither of which work. It should be rotating to match the current direction it's going. I've been struggling with this for about a week now, but still have not gotten the desired result.</p>
  
  <p><a href="https://github.com/EnderHDMC/DarkIsle/tree/master/.AndroidStudioProjects/DarkIsle" rel="nofollow noreferrer">Full Code Here</a></p>
  
  <p>Relevant code:</p>
  
  <p>From SpriteAnimation</p>
  
  <pre><code>// 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() &gt; 0)
              {
                  // Set the active animation to the first animation
                  // associated with this sprite
                  String[] sKeys = new String[animations.size()];
                  int index = 0;
                  for (Entry&lt;String, FrameAnimation&gt; 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 &amp;&amp; !getCurrentFrameAnimation().getNextAnimation().isEmpty())
          {
              // If there is, see if the currently playing animation has
              // completed a full animation loop
              if (getCurrentFrameAnimation().getPlayCount() &gt; 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);
  }
  </code></pre>
  
  <p>TestScreen class</p>
  
  <pre><code>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() &lt; 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());
      }
  }
  </code></pre>
  
  <p>Edit: Just saying now that I've already tried using atan2 in MathUtils and it gave the same results.</p>
  
  <p>The MobileSprite update method</p>
  
  <pre><code>public void update(float deltaTime)
  {
      if (active &amp;&amp; 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() &gt; getSpeed())
              {
                  Delta.nor();
                  Delta.scl(getSpeed());
                  getPosition().add(Delta);
              }
              else
              {
                  if (target == sprite.getPosition())
                  {
                      if (pathing)
                      {
                          if (queuePath.size() &gt; 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);
  }
  </code></pre>