For anyone who's played Sean O'Connors "Critical Mass", I'm trying to recreate the ship control system from that game.
I have a vehicle using a custom "racecar" type movement. It has an initial speed and angle. It also has a limit on the maximum acceleration/deceleration and turning rates.
The game is kind of turn-based - every turn, you set the vehicles acceleration and steering rate, which the vehicle then follows for a fixed period of time. Acceleration and steering rate are both fixed once the vehicle is actually moving (it can't turn right and then go straight during the same turn, for example).
Here's where it gets really tricky...
I want the player to be able to point to a destination with the mouse. I then want the game to calculate the nearest point to the destination that the vehicle is able to reach in one turn (given the steering/accel constraints), and the turning rate & acceleration used to get there.
My current version actually tests out every possible combination of acceleration and turning rate, and uses whichever gets closest. The problem with that is that it's *very* slow, and also not pixel-perfect (it can only use whole-number acceleration and turing rate values).
So,
* Can anyone think of a better way to go about this?
* Ideally, is there a mathematical solution? Like a formula I could use somehow to instantly calculate the optimum acceleration & turning?
It's something I've been trying to figure out for absolutely ages (pretty much since I first played Critical Mass infact).
I'd be hugely grateful to anyone who can help me with this
It's based on this formula: Sn = (n\2)*(a+l)
Where Sn is the sum of the first n terms of a progression, n is the amount of terms in the progression, a is the first term and l is the last term.
It only works if each "part" in your equation increments in the same amount each time though.
It all works perfectly if R=0.
If I change R though, it starts going wrong
Do you think it's possible that you've just made a small slip somewhere, or am I going to have to start over?
Well the Sn = (n/2)*(a+l) formula will only work for equations where the same value is added in each part, like this:
3 + 7 + 11 + 15... etc
The numbers in that equation are going up by exactly 4 each time, and an equation like that is called an Arithmetic Progression (or AP). I tried tried replacing A, R, V & T in your equation with the numbers 1, 2, 3, & 4 and found that your really long equation wasn't an AP because the difference between each section was not always the same, but this entirely depended on the values of A, R, V & T so it might have been a fluke that it worked for you when R was 0.
Is there any way you could simplify this: (Cos(A+(R*1))*(V+(T*1))) + (Cos(A+(R*50))*(V+(T*50))) ?
I'm beginning to think you might have to start again on a different path, the Cos function will always be the tiniest bit inaccurate because the method used to find the Cos value involves an infinite equation, so the computer just takes the first 3 or 4 parts of that equation and still gives a very accurate result; it's basically like rounding the number 0.8234629873642346 to 0.8234630000000000 in which you can see the slight inaccuracy. Perhaps because we are dealing with a lot of equations and essentially 100 uses of the Cos function, the inaccuracy could be multiplying and throwing off the final value...
That's a pretty far fetched idea though so it's most likely not the case.
I really don't know how you could simplify your really long equation now... you might have to try something different.
The best advice I could give would be to try and rearrange this part: (Cos(A+(R*1))*(V+(T*1))) somehow and see if you can get everything inside the Cos() brackets, it might make it a lot easier.
Thnaks a lot for your help.
I think I see the problem now.
There is some error caused by the approximation of Cos(A), but it's not enough for me to be worried about - eg. The expression returns 8600 instead of 8800.
The real problem though, is that it's not an "arithmetic progression" as you put it.
It's actually quite obvious once you know what A,V,R, and T stand for, and what the expression does - I should really have told you that before.
A = angle
V = velocity
R = rotation (change in angle per "step")
T = thrust (change in velocity per "step")
The expression itself is to find the change in the objects X-Coordinate (I'd basically just replace Cos with Sin for the Y-Axis).
If you can picture it, any change in angle (ie. if R is not = 0) is bound to change the rate of acceleration along one axis - it's only the increase in straight-line speed that is constant.
It's very slow, and nowhere near "pixel perfect" precise. It's so frustrating because it really doesn't seem like it should be this tough
I may have to just replace the "drag & drop" interface for a simpler system where you control acceleration and turning directly (like in "Flight Commander 2" / "Over The Reich" / "Achtung Spitfire" etc). That would be pretty clunky though.
MMF sometimes handles numbers as integers when instead you want floats. You could multiply certain expressions by 1.0 to make them floats. Maybe this will help the jumping effect.
If you find the solution, please post it here, I've also been wondering about something similar.
Someone else also suggested Bézier curves to me, so I think that might be the way to go.
I've haven't got it quite figured out yet, but I'll let you know if/when I do.
It's pretty confusing so far
The problem I had with the arrow "jumping" was only partly to do with me using integers instead of floats. I could have used floats, but that would make it too slow (every decimal place of precision, would require another 10x as many calculations, the way I was doing it).
At the moment, I have two problems with using Bézier curves.
1.) I don't know where to put the "helper points", or even how many I need.
2.) Even if I could make a curve that looks right, how do I get an acceleration and turn rate from that?
I've read the wikipedia page http://en.wikipedia.org/wiki/B%C3%A9zier_curve (and others) on Bézier Curves, many times, and given the 3 or more points, I understand how to draw a curve.
The problem is that I only know 2 points - P0 and P2. How do I find P1?
Is P1 just the point you'd end up at without any rotation or acceleration? If so, I already got as far as drawing that curve.
Even having got a curve though, I don't understand how you can find acceleration & turning from it.
I thought maybe (if I have 50 frames per turn):
* P0 = start point
* P2 = end point (mouse)
* P1 = end point if turning & accel. = 0
* Q0 = 1/50th of the way from P0 to P1
* Q1 = 1/50th of the way from P1 to P2
* B = 1/50th of the way from Q0 to Q1
* Accel. = distance from P0 to B, minus original speed
* Turning = angle from P0 to B, minus original angle
Where have I gone wrong (or is just all completely wrong)?
I think your method of finding the Acceleration and Turning would work. As for finding P1, I had an idea that it could be something like this:
Lol It's complicated but I think this will accurately give P1:
I hope this GIF makes sense:
Imagine that the Green line is the distance between P0 and P2 and it is also the angle between those points, lets say that it is 40 degrees. Note that the purple dot is the EXACT centre of that green line. Now imagine the green line moves back to form a rectangle with 90 degree angles, and P1 is the part of the green line that the arrow is looking at directly.
When P1 meets the centre point of the green line, that's where it should stop.
That sounded a bit confusing..
Basically, the distance between P1 and P2, and the distance between P1 and P0, should be the same; and P1 should be directly in the "Line of sight" of the arrow (the arrow always points at P1).
Anyway, with this method, because the green line changes angle based on where P2 is, you should always get a good curve:
And it will work whichever way the arrow is facing:
So...
Angle from P0 to P1 = Ships Initial Heading
Distance from P0 to P1 = Distance from P1 to P2
XP3 = (XP1 + XP2) / 2
YP3 = (YP1 + YP2) / 2
A couple of potential problems though:
1.)
I still can't see how to calculate the position of P1.
We can't use trigonometry/pythagoras, because the only length we know is P0->P3, and we need either P0->P1 or P1->P3.
2.)
Should P1 move depending on the initial speed of the object?
The actual shape of the curve would definitely be different, but that might not matter as we really only care about the first frame?
Correction to my previous post - the shape of the curve actually changes depending on acceleration, rather than just the initial speed.
The pink line represents the vehicle moving at constant speed.
The blue line represents the vehicle decelerating.
The Vitalize example worked ok (in IE atleast - not if FireFox for some reason).
It certainly draws a nice curve, but there's still a major problem.
It can't be used to provide actual values for Acceleration & Turning still (see my modified version - click to plot actual movement).
Your acceleration/deceleration value needs to be replaced with something directly related to the initial speed of the object. Otherwise, the line drawn will bear no resemblance to the path actually travelled by the object.
I like that your version is so simple
In one of my version, this is what I ended up with, for calculating the X coordinate of the first "step":
I have this habit of always trying to find the simplest way of making something work.. it usually means it takes me ages to code a game because I'm never happy with it
As for finding out Acceleration and Turning... Sorry but I have no idea , this one has finally stumped me .
No problem - I really appreciate all your help up to this point
You want some more DC Points? I have lots and there's nothing to spend them on anyway
This is what someone else has told me:
"I'm pretty sure (in Critical Mass) acceleration works instantaneously at the start of each turn and you will move each turn with a constant speed.
I can see that in the quadratic example there, P1 is most definitely not end point if turn/accel=0. it is basically the intersection between the line you would travel if turn=0 and the line you would be traveling in after the turn (extending backwards).
now, i am assuming you will want to approximate a circular arc as this is what it's like in CM as far as I can see. after some geometry/trig, the point P1 is a distance d=(r/2)/cos(θ along the line of travel if turn=0, where θ = angle between line of travel if turn=0 and line between ship and mouse and r is distance from ship to mouse."
Well, I eventually managed to get something working that I'm happy with. Thanks to Julian, and everyone else who helped.
I'll still change a few things, such as making the arrow a solid line instead of dotted, but the hard part is done now.
Anyway, the big change, which made it possible, was getting rid of the gradual acceleration. Instead, the ship now accelerates instantly to its new speed at the start of the turn. This means that the movement curve is now simply a circular arc, which makes the maths *much* simpler.
As it turns out, this is the same method as used in "Critical Mass" (the game I'm kind of copying), so it's ok
* Find A1;
Difference between initial heading and angle from start to finish points.
* Find A2;
90 - A1
We know P3 is at a 90 degree angle from the original heading.
* Find A4;
180 - (A2 * 2)
A2 and A3 are the same, and interior angles of a triangle always add up to 180.
This is also the angle the ship turns through.
* Find distance from P3 to P4;
We know A2 and A3, and can calculate the distance from P1 to P2 (using Pythagoras' theorum), so we can use "triangulation".
* Find distance from P3 to P1;
We know the distances from P3 to P4 and from P1 to P4 (half the distance from P1 to P2), so we can use Pythagoras' theorum.
This is the radius of the circle who's arc is travelled along.
* Find length of arc travelled;
We know the radius of the circle, so by dividing by 360, and multiplying by the total angle travelled (A4), we can find the distance travelled.
This gives us the new speed of the ship. By subtracting the initial speed we can find the acceleration.
* Find acceleration & turning;
We know the total change in angle and speed, so can divide these by the number of frames, to find the change per frame.
Actually, it's a bit long-winded. I could have use the law-of-sines and skipped a couple steps, but whatever.