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.
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.