I have been struggling with this problem for a while. In my project (RTS in space) I have a ship moving on a 2D plane. I want to make the right movement in space so that when I click somewhere in space:
- The ship began the movement by constantly turning its nose towards the destination point. It will turn out some kind of curve;
- or turned around its axis while standing still and then moved to the point if this happens faster than in the first version.
For the first version i came with this pseudocode (assume that Z component always 0, and assume that moveTo is called every tick)
int moveTo(vector3 &position, float deltaTime)
{
float forwardSpeed = 10;
float forwardTurningSpeed = forwardSpeed * 0.5;
// Find direction to destination point
vector3 direction = position - GetActorLocation();
direction.normalize();
// Find on which angle to rotate the actor
float angleBetweenDirectionAndWorldRightVector = getAngleBetweenVectors(direction, GetRightVector());
float angleBetweenActorForwardVectorAndWorldRightVector = getAngleBetweenVectors(GetActorForwardVector(), GetRightVector());
// This subtracion is the root of all problems
float angle = angleBetweenDirectionAndWorldRightVector - angleBetweenActorForwardVectorAndWorldRightVector;
// When finding angle between direction vector and actor`s forward vector the value is from 0 to 180
// and there is no difference when direction is to the left by say 10 degrees or to the right
// I thought that by subtracting angle between actor`s forward vector and world`s right
// vector i could decide whether direction is to the left or to the right from actor`s forward vector
// but its not working in this way
if(angle < 10 || angle > -10)
{
// If actor looking at target position nearly straight then move forward
vector3 newPosition = GetActorLocation() + GetActorForwardVector() * forwardSpeed * deltaTime;
SetActorLocation(newPosition);
}
else
{
// Rotate actor while moving around Z axis (on a plane XY)
if (angle < 180)
{
// Rotate counter-clockwise
SetActorRotation(0,0,GetActorRotation().Yaw() + angle * deltaTime);
}
else
{
// Rotate clockwise
SetActorRotation(0,0,GetActorRotation().Yaw() + angle*(-1) * deltaTime);
}
// Move forward after rotation
vector3 newPosition = GetActorLocation() + GetActorForwardVector() * forwardTurningSpeed * deltaTime;
SetActorLocation(newPosition);
}
// Stop if reached destination
if((position - GetActorLocation()).LenghtSquared() < 100) return 1;
}
float getAngleBetweenVectors(vector3 &first, vector3 &second)
{
// Find angle using dot product
float dotProduct = dotProduct(first, second);
float cosinus = dotProduct / (first.length() * second.length());
return acosd(cosinus); // returns angle in degree
}
This is what I`ve got.
The second variant is quite simple by using standard MoveComponentTo unreal function twice. First apply to rotate around Z axis while standing still and second apply to move straight to destination.
I don`t know how to prebuilt path to avoid obstacles so this is next step.