0
votes

Problem: my player model is supposed to turn into the direction of the last mouse click but instead of turning slowly it spins in all possible ways(Game has an isometric view, the model is supposed to rotate only around the Y-axis but it rotates around the X- and Z-axis too).

Following method(called in render()) is responsible for the turning behavior of the model:

public static void turnUnit(){
    if(Gdx.input.isButtonPressed(Input.Buttons.LEFT)){
        mX = Gdx.input.getX();
        mY = Gdx.input.getY();
        angle = (float) (180+Math.atan2(mX-Gdx.graphics.getWidth()/2, mY-Gdx.graphics.getHeight()/2)*(180/Math.PI));

        newAngle = ((((currentAngle - angle) % 360) + 540) % 360) - 180;
        turning = newAngle/60*turnRate;

        currentAngle = currentAngle-turning;
    }
    TestGround.player.transform.setToRotation(Vector3.Y, currentAngle).setTranslation(posX,0,posZ);
}

And the movement-method(also called in render()):

public static void movement(){
    if(northM==true){
        TestGround.player.transform.trn(0,0,-1f);
    }
    if(southM==true){
        TestGround.player.transform.trn(0,0,1f);
    }
    if(westM==true){
        TestGround.player.transform.trn(-1f,0,0);
    }
    if(eastM==true){
        TestGround.player.transform.trn(1f,0,0);
    }

    posX = TestGround.player.transform.getTranslation(Vector3.X).x;
    posY = TestGround.player.transform.getTranslation(Vector3.Y).y;
    posZ = TestGround.player.transform.getTranslation(Vector3.Z).z;

}

Tried to use "rotate" in the last line but then it just spins faster.

Also, even though this makes no sense to me but after some testing it seems the movement-method somehow interferes with the turn-method(moving in a certain direction will rotate the model in a certain way).

Am I doing something fundamentally wrong here?

Additional Info:

  • originally I used simple polling to get all keyboard and mouse input
  • calculated movement/rotation in one big method and everything worked fine
  • decided to use the inputprocessor of libgdx to make the code more readable and open-ended
1
i just saw 180/Math.PI - are you sure you want to divide 180 with (180 in radians)?Krab
one possible reason why you are spinning out of control may be because the render() method is called once every 1/60th(ish) of a second. That is very very very fast considering what you want to do. Instead, you might want to use delta time to moderate your change in rotation every frame. Here is a good example on how to use delta: stackoverflow.com/questions/22405390/…Fish
Krab: yeah the math there is kind of wonky but the calculation in newAngle fixes all possible problems Fish: Alright gonna try deltatime, I'll report back if it works. Maybe my original code was really slow and that's why it didn't spin out of control?Boskop88
@Fish well, as you would expect, the rotation was a lot slower but the problem of not rotating exclusively around the Y-axis remained. Thanks for reminding me of deltatime though, I always forget that it exists.Boskop88

1 Answers

0
votes

The Matrix4#getTranslation(Vector3) method will set the specified vector to the translation component of the matrix and return it for chaining. What this means is that the vector you supply as argument to the TestGround.player.transform.getTranslation(vector) method, will be set (read: overwritten) to the translation (position) of the model instance.

So, in the case of the call to:

TestGround.player.transform.getTranslation(Vector3.Y)

This will practically modify the Vector3.Y variable from the default [x:0, y:1, z:0], to whatever the translation component of the matrix is set to. This will result in any other call that uses the Vector3.Y variable (like your call to setToRotation) to behave differently.

To fix that you can modify the last few lines to:

Vector3 pos = new Vector3();
TestGround.player.transform.getTranslation(pos);
posX = pos.x;
posY = pos.y;
posZ = pos.z;

Note that you should move the creation of the Vector3 out of the method and therefor might as well remove the posX, posY and posZ members in favor of the pos member.

So, you might be wondering two questions:

Why does the getTranslation method modify its arguments? This is because libGDX is designed to avoid creating garbage, because that will create hick-ups on some platforms, like Android. So instead of creating a new Vector3 every time the method is called, it allows you to specify an instance of that class which you want to reuse. You will see this pattern throughout the lib at multiple places because of this reason.

Why is it even possible to modify Vector3.Y, making it useless and cause all kind of problems? This is because the Vector3 class is mutable and does not encapsulate its members. So practically it allows you to do vector.x += 3; instead of forcing you to call vector.setX(vector.getX() + 3);. This is both for readability and performance reasons (although the latter might vary on your target platform). Also, java does not support something comparable to const.