5
\$\begingroup\$

I have a turn-based car simulation. My vehicles have a maximum speed they can travel in a round, as well as a maximum amount they can change their heading over the course of a round. Say, 20 meters and 45 degrees.

Knowing the starting position of a car (x,y coordinates), and its starting heading (orientation), I want to find the end-of-round coordinates for the car turning its maximum amount and moving its maximum speed. (And values in-between, as well!)

There has to be some simple math formula for this, but I haven't found it yet. I also happen to be working in Unity.

\$\endgroup\$
0

2 Answers 2

7
\$\begingroup\$

Let's say you want its position after time t. Multiply speed by time, an your have your arc length l. Multiply the turn speed by time to get the total turn angle a (you'll need this in radians). Use these to get your turn radius r.

r = l / a

Using the turn radius, you can find the center c of your turning arc by moving left from its starting position, if turning left, or by moving right from its position. To find a certain position on the edge of a circle, you'll need to use some trig. Assuming you were oriented as pictured: arc turning

    newX = c.x + r * cos(a);
    newY = c.y + r * sin(a);

Of course, this only works if you start facing forward and are turning left, but using relative positioning and flipping it for turning right, we can make it work for every situation. In UnityScript:

//turnSpeed assumed to be in radians
function CalculateNewPosition(speed : float, turnSpeed : float, t : float){
    var l = speed * t;
    var a = Mathf.Abs(turnSpeed) * t;
    var r = l/a;
    //start by assuming the vehicle is at the origin
    var c : Vector3 = Vector3.zero;
    var newPos : Vector3 = c;
    if(turnSpeed>0){ //turning left
        c.x -= r;
        newP.x = c.x+r*Mathf.Cos(a);
    } else{ //turning right
        c.x += r;
        newPos.x = c.x-r*Mathf.Cos(a);
    }
    newPos.y = r*Mathf.Sin(a);

    //finally, transform it relative to the vehicle (might mess up if your vehicle
    //isn't at a 1x1x1 scale)
    return transform.TransformPoint(newPos);
}
\$\endgroup\$
8
  • \$\begingroup\$ Does that take into account the current orientation of the car? I guess you could change your starting point on the circle to account for it, but I don't see where you do that in your example. \$\endgroup\$
    – House
    Apr 5, 2013 at 3:50
  • \$\begingroup\$ The last line converts a local point to a global point. Because all calculations were done relative to the car, TransformPoint finds new coordinates taking into account the position and rotation of the vehicle. \$\endgroup\$
    – tyjkenn
    Apr 5, 2013 at 4:20
  • \$\begingroup\$ Ah, neat +1. That's a clever way of doing it. \$\endgroup\$
    – House
    Apr 5, 2013 at 4:23
  • \$\begingroup\$ Hmm, you need to rotate the car object as well, or else it won't continue the curve. Also the turning right version you gave uses sin() and the y angle uses cos(), I believe those should be swapped. I changed the script to my specific use: pastebin.com/T0AFxehn \$\endgroup\$ Apr 5, 2013 at 8:08
  • \$\begingroup\$ Overall great! Thanks for pointing me to this. I'm surprised there's no shorthand way to do this. (Without solving for the whole circle, its origin, etc.) \$\endgroup\$ Apr 5, 2013 at 8:08
0
\$\begingroup\$

You'll likely find that iteration will be the simplest to implement. Essentially you're going to use a for loop, and step along the car's path. You can use the same methods that you use for updating the car's position in game.

You will need to ensure that you have enough iterations to maintain reasonable accuracy, but you may not want the same number of points in your sample. You can just iterate more often than you place points in your list.

Take the amount of time you want to look ahead and divide it by the number of iterations you want to perform. This will give you your time step for each iteration. The smaller the time step, the more accurate the result will be. This is similar to a Riemann sum. You'll get a more accurate picture with finer resolution.

For example, if we wanted to look ahead 10 seconds:

Vector3 simulationPosition = new Vector3(carCurrentPosition);
Vector3 simulationRotation = new Vector3(carCurrentRotation);
List<Vector3> dataPoints = new List<Vector3>(); //a list to hold all our data points
//drawing a line through all these points will give you your anticipated path
float secondsInMS = 10000;
int iterations = 1000;
float timeStep = secondsInMS/iterations;
for(int i = 0; i < 1000; i++) {
    float deltaTime = (float) (i * timeStep);
    //update the simulation position
    //small time step means more frequent updates and more accurate final position
    updatePositionAndRotation(simulationPosition, simulationRotation, velocity, deltaTime);

    if(i%50 == 2) { //mod by 50 so that our 1000 iterations turns into 20 data points
         dataPoints.add(new Vector3(simulationPosition));
    }
}

Where updatePositionAndRotation takes the simulation's current position and rotation and calculates the new position and rotation based on the velocity and delta time. You likely have a function for this already, so use that here to update the simulation values.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .