Sizzlor ox
Sizzlor ox

Reputation: 13

Libgdx rotating to angle with Vector2s

I am trying to make the player rotate and face a target position, and have encountered a problem I am unable to fix.

When the ship is rotating towards the target position, when it reaches directly below the target position, it goes crazy and moves left and right while going downwards (away from the target position) and eventually off the screen.

I do not want to limit the screen as it will look weird when it is slowly rotating if it is near the screen limit. In this case if I do limit the screen, it will still get stuck at the bottom as it keeps turning left and right. I uploaded an image on imgur to try to better explain my problem.

Yellow is the direction ship is moving (it is rotating towards the target position but will cross the red line), Green is an imaginary vector towards the target position, Red is another imaginary vector which represents whenever the ship goes crazy. When the green line goes on top of the red line, the ship begins to bug out and go out the screen.

public void ai() {
    switch (playerArrived()) {
        case 0:
            break;
        case 1:
            pTargetPos.set(ran(0, Gdx.graphics.getWidth()), ran(0, Gdx.graphics.getHeight()));
            System.out.println("Player Destination Reached: " + pPos.x + "," + pPos.y + " Moving to new point: " + pTargetPos.x + "," + pTargetPos.y);
            break;
    }
    turn();
    move();
    ePlayerBody.set(pPos.x, pPos.y, pWidth);
}

public int playerArrived() {
    if (pTargetPos.x < pPos.x + pWidth && pTargetPos.x > pPos.x - pWidth && pTargetPos.y < pPos.y + pHeight && pTargetPos.y > pPos.y - pHeight) {
        return 1;
    } else {
        return 0;
    }
}

public float ran(float low, float high) {
    return (float) (Math.random() * (high - low + 1)) + low;
}

public void move() {
    pVel.set(pTargetPos.x - pPos.x, pTargetPos.y - pPos.y);
    pVel.nor();
    pVel.x *= sMaxSpeed + Gdx.graphics.getDeltaTime();
    pVel.y *= sMaxSpeed + Gdx.graphics.getDeltaTime();
    pVel.setAngle(pNewRotation + 90);
    pPos.add(pVel);
}

public void turn() {
    pRotation = ((Math.atan2(pTargetPos.x - pPos.x, -(pTargetPos.y - pPos.y)) * 180.0d / Math.PI)+180.0f);
    pNewRotation += (pRotation - pNewRotation) * Gdx.graphics.getDeltaTime();
    System.out.println(pRotation+"    "+pNewRotation);
}

I uploaded an image on imgur to try to better explain my problem

image

Upvotes: 1

Views: 1028

Answers (2)

Sizzlor ox
Sizzlor ox

Reputation: 13

This worked for me:

    public void turn() {
    pRotation = ((tPos.y - pPos.y) / (tPos.x - pPos.x) * 180.0d / Math.PI);
    pNewRotation += (pRotation - pNewRotation) * Gdx.graphics.getDeltaTime();
}

public void move() {
    pVel.set(pDir);
    pVel.nor();
    pVel.x *= sMaxSpeed + Gdx.graphics.getDeltaTime();
    pVel.y *= sMaxSpeed + Gdx.graphics.getDeltaTime();
    pVel.setAngle(pNewRotation + 90);
    pPos.add(pVel);
}

Upvotes: 0

dcsohl
dcsohl

Reputation: 7396

When your ship is directly below, and just a little bit to the left of, the target, then the call Math.atan2(pTargetPos.x - pPos.x, -(pTargetPos.y - pPos.y)) will return a value very close to π/2. When your ship is directly below, and just a little to the right of, the target, that call will return -π/2. As you cross the red line, your direction will flip-flop by 180 degrees (π radians). That's why it's "going crazy".

You need to figure out a better way to determine what angle you should turn towards. I'd offer suggestions on that, but I'm still unclear on exactly what behaviour you are expecting.

Upvotes: 1

Related Questions