0

I am developing a game using Cocos2d-X and Marmalade SDK. I have several objects in this game that move around on the screen using a Wander steering behavior, however I am having a lot of problems to orient these objects to face the movement direction.

Inside my GamObject class update method (the sprite is actually a child of this object) I have:

void GameObject::update(float dt)
{
    float angle;
    CCPoint newVelocity;

    newVelocity = gameObjectMovement->calculateSteeringForce(dt);

    // Check if the velocity is greater than the limit.
    if (ccpLength(newVelocity) > MAX_WANDER_SPEED)
        newVelocity = ccpMult(ccpNormalize(newVelocity), MAX_WANDER_SPEED);

    nextPosition = ccpAdd(this->getPosition(), ccpMult(newVelocity, dt));

    angle = calculateAngle(nextPosition);

    this->setPosition(nextPosition);
    this->setRotation(angle);

    velocity = newVelocity;
}

And the calculate angle method is:

float GameObject::calculateAngle(CCPoint nextPosition)
{
    float offsetX, offsetY, targetRotation, currentRotation;
    int divRest;

    currentRotation = this->getRotation();

    // Calculates the angle of the next position.
    targetRotation = atan2f((-1) * nextPosition.y, nextPosition.x);
    targetRotation = CC_RADIANS_TO_DEGREES(targetRotation);

    targetRotation = targetRotation - currentRotation;

    // Make sue that the current rotation is not above 360 degrees.
    if (targetRotation > 0)
    targetRotation = fmodf(targetRotation, 360.0);
    else
        targetRotation = fmodf(targetRotation, -360.0);

    return targetRotation;
}

Unfortunately when I run this code, by objects face everywhere and not the movement direction. I don't know what I am doing wrong.

UPDATE

Hi, I've updated my code according to your suggestions:

void GameObject::update(float dt)
{
    float angle;
    CCPoint newVelocity;

    newVelocity = gameObjectMovement->calculateSteeringForce(dt);

    // Check if the velocity is greater than the limit.
    if (ccpLength(newVelocity) > MAX_WANDER_SPEED)
        newVelocity = ccpMult(ccpNormalize(newVelocity), MAX_WANDER_SPEED);

    nextPosition = ccpAdd(this->getPosition(), ccpMult(newVelocity, dt));

    angle = calculateAngle(newVelocity);

    this->setPosition(nextPosition);
    this->setRotation(angle);

    velocity = newVelocity;
}

float GameObject::calculateAngle(CCPoint velocity)
{
    float offsetX, offsetY, targetRotation, currentRotation;
    int divRest;

    // Calculate the angle based on the velocity.
    targetRotation = atan2f((-1) * velocity.y, velocity.x);
    targetRotation = CC_RADIANS_TO_DEGREES(targetRotation);

    // Make sure that the rotation stays within 360 degrees.
    if (targetRotation > 0)
        targetRotation = fmodf(targetRotation, 360.0);
    else
        targetRotation = fmodf(targetRotation, -360.0);


    return targetRotation;
}

It is working much better now, however I am still seeing some strange behavior. There is a 90 degrees difference between the actual movement direction / velocity and the front side of my objects.

Felipe
  • 6,312
  • 11
  • 52
  • 70
  • You should probably be calculating the rotation based on movement/velocity vector, and not the final position alone... Also, what is currentRotation doing there exactly? – slazyk Jul 07 '14 at 15:28
  • Hi, I accidentaly deleted a line in the code. The current rotation is just a variable that hold the rotation of the node (it was easier to debug this way). I will re-write the code to calculate the rotation based on the velocity vector and see how it goes. – Felipe Jul 07 '14 at 15:32
  • Hi, I changed the line: `angle = calculateAngle(nextPosition);` to: `angle = calculateAngle(newVelocity);` so that I could just try to calculate the angle this way, but the result is still not what I expected, since my objects are not always facing the movement direction. – Felipe Jul 07 '14 at 15:37
  • 2
    Like I mentioned currentRotation is not needed, you're setting the rotation, so no need to subtract currentRotation. – slazyk Jul 07 '14 at 16:02

1 Answers1

1

It looks to me like your equation takes into account absolute position of the next point on the screen, which will not give you the proper rotation.

To fix it use the direction of the velocity vector (I assume it has an X and Y value available) to calculate the sprites rotation. If you use this method, you will not need to account for the previous rotation.

RScottCarson
  • 980
  • 5
  • 20
  • Hi, actually the next position vector was also on local coordinates, so I guess that one of the mistakes that I was making was to take the current rotation into account when I calculated the target rotation. – Felipe Jul 07 '14 at 16:21
  • Yea sounds like slazyk told you the same thing above. – RScottCarson Jul 07 '14 at 16:42
  • Yes, I did exactly what you and @slazik told me to, however there is still something strange: my objects have a 90 degrees offset from the movement direction / velocity vector. If I add 90 degrees to them, then they are correctly oriented. Maybe I am missing something. – Felipe Jul 07 '14 at 17:02
  • 1
    Are you sure you have your axes straight? Do you know where 0 degrees is relative to your screen? It may just be that what you think is 0 degrees is 90 degrees off. – RScottCarson Jul 07 '14 at 17:32
  • Hi, yes you are quite right, I was orienting my objects along the Y axis, however I was calculating the velocity angle with the X axis, therefore I was "90 degrees off alignment". I have now oriented my objects along the X axis and everything is working. Thank you very much for your help! – Felipe Jul 07 '14 at 17:41