Welcome, Guest. Please Login or Register.  • Help
SMF Underground
+ SHMUP-DEV » SHMUP DEV FORUMS » Training Grounds » Tutorials
|-+ Control Schemes [part 2] : Spline Motion

Pages: [1]   Go Down
0 Members and 1 Guest are viewing this topic. Topic Tools  
Read August 13, 2008, 06:52:56 pm #0
motorherp

Control Schemes [part 2] : Spline Motion

Hello once again shmup fans.  Strap yourself in for another fun filled exhilarating ride through my brain.  This time we'll be discussing how you can quickly, easily, and efficiently create super smooth curved motion for your scripted game objects and have them follow in real time.  This will let your enemies gracefully swoop in on complex attack vectors and create mind boggling formations with each other as they spin around the screen.  At the end of this tutorial I'll be linking it up with the ideas from the last control schemes tutorial so if you haven’t read that already then please do so now.  So without further ado lets crack on.

When designing motion for our scripted game objects we don’t want to have to manually specify their positions for every single frame, imagine how long it would take to create all that data.  Instead we want to specify only a few key positions for the object and have the computer automatically move the object between those key positions.  This is what is known as interpolation and there are many ways we can do it each having different properties and giving different results.  Therefore we want to choose an interpolation method which has the properties we desire.  For this I'll be considering the two major properties we are concerned about.  The first of these is whether the object is forced to move exactly through the key positions we specified or whether these are merely control points for the motion which is approximated between the points.  There really isn't much difference between the two methods since the same motion can be represented with both systems but personally I prefer the first option since it gives more intuitive control over the motion and allows us to set up exact locations for things such as formations of multiple enemies etc.  Therefore I'll want an interpolation method that satisfies the first option.  The second important property is the continuity of the interpolation, i.e.: how smooth the resulting motion is.  For example consider the simplest type of interpolation we can perform which is to move the object linearly between the key positions (imagine connecting up the key positions with straight lines).  In such a system the position aspect of the object is continuous since there are no sudden teleportations in the position.  The objects velocity is discontinuous however since it suddenly changes direction at the key positions giving rise to jagged line motion.  This interpolation method is known as zero order continuous because none of the derivatives of the motion are continuous (velocity being the first derivative of position).  Now imagine a first order continuous method.  In this scheme the objects position and velocities would change smoothly but the objects acceleration (the second derivative) is allowed to change suddenly at the key positions.  Therefore such an object would move in smooth curves between key positions but the curvature is allowed to change suddenly between pairs of control points.  In a second order continuity method our acceleration is now also continuous and hence the rate of change of curvature must also change smoothly.  As you can see the higher the order of continuity the smoother and smoother our motion is going to become.  The trade off however is that higher order systems are more computationally expensive and become more restricting on the motion we can produce.  The visual improvement you get from using higher order systems drops quickly too so it’s not important to use a high order.

So taking all the above into account, an interpolation method known as Catmull-Rom Splines is widely popular for controlling motion.  This is an exact interpolation method (passes directly through key positions) and is first order continuous giving nice smooth curving motion without being too expensive or restrictive.  Therefore this is the interpolation method I'll be using throughout this tutorial.  So how do we use Catmull-Rom splines?  We will consider the spline in segments with the smallest spline we can use containing one segment.  There is no cap on the number of segments a spline can contain and hence there is no limit to the maximum size restriction for a Catmull-Rom spline.  A spline segment consists of two key positions you want to interpolate between, and the key positions either side of those two key positions:



Therefore the minimum number of key positions a spline must contain is 4 since this equates to one segment.  To create longer splines we simply add more key positions onto the end and shift our segment up one key position at a time, thus a spline with 5 key positions has 2 segments, one with 6 key positions has 3 segments, etc.  This allows us to interpolate between every pair of key positions with the exception of the [0,1] pair and the [n-1,n] pair where 'n' is the total number of key positions.  Therefore when creating a spline you must always add in an extra key position on either end of the desired motion.  So how do we do the actual interpolation to determine points on the spline in-between the key positions?  Imagine a spline segment with key position p0, p1, p2, and p3.  Given the requirements for a segment just discussed this means that for this segment we can interpolate between key positions p1 and p2.  Any point between these two key positions can be described by a value 't' which can take any value between 0 and 1 inclusive where t=0 represents key position p1 and t=1 represents key position p2.  There t=0.5 would reference a point on the spline half way between key positions p1 and p2.  Then for a given value of 't' we are interested in we can calculate the actual x,y coordinates of the point on the spline at that 't' using the following equations:

Code:
x = 0.5 * ((2 * p1x) + (p2x - p0x)*t + (2*p0x - 5*p1x + 4*p2x - p3x)*t*t + (3*p1x + p3x - p0x - 3*p2x)*t*t*t)

y = 0.5 * ((2 * p1y) + (p2y - p0y)*t + (2*p0y - 5*p1y + 4*p2y - p3y)*t*t + (3*p1y + p3y - p0y - 3*p2y)*t*t*t)

So one option for us to move our object along a spline is to increment 't' by a constant amount each frame and calculate the objects position from the new value of 't'.  When 't' becomes greater than 1 we subtract 1 from the 't' value to put it back in range and move our segment one key position along the spline.  This is repeated until the object has reached key position n-1.  This will give us nice smooth motion but there is a problem in that the length of each spline segment isn't necessarily equal to the length of all the other spline segments.  Even if we spaced our key positions so that they all have the same separation the actual length of the interpolation segments will still vary since they curve by different amounts.  In fact due to the mathematics involved you'll find that the speed of our objects will vary even on different portions of the same spline segment.  What this means for us is that varying 't' by a constant value doesn't equate to our object moving with constant speed.  In fact just using the knowledge we currently have its near impossible for us to control the speed of our objects at all which obviously isn't very good for us.  So how do we tackle this problem?

Clearly what we need is some knowledge of the distance our object is covering during interpolation, specifically we need to know about what is called arc length which is the length of a curve if you imagine it stretched out flat.  What we need to do is reparameterise the Catmull-Rom equations so that they become functions of arc length rather than 't' (the parametric variable).  Often these reparameterisations aren't able to be done analytically and we must use numerical methods.  Since we want to keep our spline code efficient we'll be approximating the reparameterisation by using a pre-calculated look up table.  We calculate this table for each spline segment by evaluating the position along that segment for lots of small increments of 't'.  If our 't' slices are small enough then we can approximate the little slices of curves between each evaluated point as straight lines.  What this means is that by adding up the lengths of the straight lines we can get an estimate for the arc length at each value of 't' we evaluated.  This pre-calculated table is then loaded into our game so that we can control our objects by incrementing their arc lengths directly giving us absolute control over object speed.  The current arc length is then looked up on the table and its corresponding 't' value read off and used to calculate the objects actual new position using the Catmull-Rom spline equations given above.

There is one more complication however.  Given a value of arc length for which we want to know our objects position, it’s unlikely that our table will contain this exact value of arc length to read off the exact 't' value.  Instead we must blend between the 't' values for the two nearest arc lengths in the table either side of our actual desired arc length.  This can be done by following this formula where 'a0' and 'a1' are the two closest tabulated values of arc length our actual desired arc length 'a' lies between, and 't0' and 't1' are the corresponding values of 't' for 'a0' and 'a1' respectively:

Code:
t = t0 + ((a - a0) / (a1 - a0)) * (t1 - t0)

So we can now move our object in nice smooth curving motions whilst maintaining absolute control over their velocities.  There's really only one more thing I need to mention.  Imagine now you control a tank style enemy using such a spline.  You'll want the tanks lower body and tank tracks to rotate so that it looks like the tank is actually driving along the path.  We can achieve this if we know the angle the spline motion takes to some reference direction and then combine this with our sprite perspective trick from the previous control schemes tutorial.  What we need to know is the rate at which the curves position is changing at any point which will give us the direction.  For those of you who know anything about calculus this equates to finding the differential of the spline.  Don’t worry I'm not going to start giving you a tutorial on calculus, I'll just spit out the answer.  So the rate of change of x and y, called 'dx' and 'dy' become:

Code:
dx = 0.5 * (p2x - p0x + 2*t*(2*p0x - 5*p1x + 4*p2x - p3x) + 3*t*t*(3*p1x + p3x - p0x - 3*p2x))

dy = 0.5 * (p2y - p0y + 2*t*(2*p0y - 5*p1y + 4*p2y - p3y) + 3*t*t*(3*p1y + p3y - p0y - 3*p2y))

The nice thing about this is that many of the bracketed groups and powers of 't' have already been calculated in the Catmull-Rom spline equations and so we can re-use them.  We can now plug these 'dx' and 'dy' values into the atan2 function just like we did in the progear turrets tutorial in order to calculate the direction our object is facing and hence update its sprite accordingly.  Well that’s basically it.  Welcome to the world of super slinky spline motion, I hope you enjoy it.  Sorry this tutorial is a little stunted compared to usual and things maybe aren't explained in the same level as detail as my usual standard but with taking over the website and trying to organise the next compo my time is a little tight.  As usual if you want to ask questions please do so.

 

Thanks for reading

 

 

Dan.
« Last Edit: August 13, 2008, 07:18:41 pm by motorherp »
Offline  
Read August 14, 2008, 09:11:47 pm #1
motorherp

Re: Control Schemes [part 2] : Spline Motion

[reserved]
Offline  
Read August 14, 2008, 09:32:08 pm #2
motorherp

Re: Control Schemes [part 2] : Spline Motion

You can find previous replies to this tutorial posted in the following thread:

http://www.shmup-dev.com/forum/index.php?topic=1172.0

That topic has now been locked.  Please continue any discussions or add any further questions in this thread.  Many thanks.
Offline  
Read August 25, 2008, 03:37:17 pm #3
Yumil

Re: Control Schemes [part 2] : Spline Motion

Hi, it's me again.
I've now been playing around with Catmull-Rom splines thanks to your tutorial(BTW, it was the one I could understand the easiest out of what I've found searching the interwebz). Changing the equation to a function of arc length is great...exactly what I wanted, but I do have one question.

Would it be better to just store a table of positions based on a minimum velocity(say 1) and pass that to the game from an editor. I'm just saying that if you have less points to visit than arc length data on the table, wouldnt it be smaller to just pass the points. I'm just thinking that keeping a sufficiently small t increment for your table to make a smooth curve over a large arc for the smaller arcs would lead to a table that is larger than what you need. Also, by making a table of positions over time, it would get rid of the calculation and the table search.
Offline  
Read August 26, 2008, 10:50:26 am #4
motorherp

Re: Control Schemes [part 2] : Spline Motion

It seems to me that you're massively over-sampling your splines if you're having problems with table sizes.  The velocity of the objects which follow the splines isn't the factor you should be using to determine your sampling rate.  Instead you should be considering the 'frequency' of the spline, in other words how rapidly it can change direction, or how sharp the curviture is.  For an in depth description on data sampling take a look at http://en.wikipedia.org/wiki/Nyquist%E2%80%93Shannon_sampling_theorem.

Your splines though will likely be made up of only a hand full of points spread out across the length of the screen and so wont contain much high frequency data or rapid curviture, therefore a huge sampling rate isn't really required.  If you really wanted to shave off as much space as possible in your tables, then in your spline tool you could start at a high sampling rate and then repeatedly evaluate each spline segment using lower and lower sampling rates and compare the error between that and the first high sampling rate evalution until it rises above some tollerance level.  You'll then know how small a sampling rate you can use for that segment without the results becoming too erroneous.

Lastly there's not a way you can get rid off the table search, not unless you know how fast your object is moving before hand at the time you make the spline and then stored 60 positions a second for that object (assuming your game runs at 60fps which you would also need to know at the time you make the spline).  Now that would be a very large table.  If you want to reduce table size and make your system more flexible and generic so that you can change your objects velocities if and when you want, and run the game at what ever fps you want, then table searches are innevitable.
.
« Last Edit: August 26, 2008, 10:53:33 am by motorherp »
Offline  
Read August 26, 2008, 08:17:35 pm #5
Yumil

Re: Control Schemes [part 2] : Spline Motion

It seems to me that you're massively over-sampling your splines if you're having problems with table sizes.  The velocity of the objects which follow the splines isn't the factor you should be using to determine your sampling rate.  Instead you should be considering the 'frequency' of the spline, in other words how rapidly it can change direction, or how sharp the curviture is.  For an in depth description on data sampling take a look at http://en.wikipedia.org/wiki/Nyquist%E2%80%93Shannon_sampling_theorem.
Thats my problem. I'd been using a much smaller t sample for the table because I was getting huge jumps at the points. I didn't even think of resampling specific areas when the error rate gets too high and just inserting it into the table. Doing that, would probably keep it small, and since its not reliant on the t sample being constant, it'll probably turn out fine.
Offline  
Read August 27, 2008, 09:23:36 am #6
motorherp

Re: Control Schemes [part 2] : Spline Motion

I'd been using a much smaller t sample for the table because I was getting huge jumps at the points.

If you're getting sudden jumps at the nodes then it sounds like a bug in your implementation, possibly with how you deal with crossing sectors.  The thing is that using the implementation in the tutorial you should get continuous motion even with no sub-sampling since the sampling rate just determines how accurately you're able to control the object velocity.  If this is a bug when crossing sectors like I suspect, check out the other discussion thread for this tutorial, there's discussion in there with someone who had the same problem.
Offline  
Read August 27, 2008, 07:49:17 pm #7
Yumil

Re: Control Schemes [part 2] : Spline Motion

I'd been using a much smaller t sample for the table because I was getting huge jumps at the points.

If you're getting sudden jumps at the nodes then it sounds like a bug in your implementation, possibly with how you deal with crossing sectors.  The thing is that using the implementation in the tutorial you should get continuous motion even with no sub-sampling since the sampling rate just determines how accurately you're able to control the object velocity.  If this is a bug when crossing sectors like I suspect, check out the other discussion thread for this tutorial, there's discussion in there with someone who had the same problem.

Now that you point it out...it was due to a floating point error>.< I had a for loop that ended if it was more than or equal to 1 and incremented t by .1...well, by the time it got to .9, it was like .900001 and it would just jump to 0, which I had assumed would be equal to the last value. So, it would skip from .9->the start of the new seg>.<
I had read the last comments in an attempt to make it right the first time. I was sure I took everything into account, and I did, but I forgot the darn nature of floating point. That makes things much better now.
Offline  
Read June 01, 2009, 02:19:28 am #8
Jason Doucette

Re: Control Schemes [part 2] : Spline Motion

Thanks for this tutorial.  It's the best one for Catmull-Rom Splines on the 'net that I've found.  Many game makers are trying to use splines for their enemy motions, and have no idea on how to get the speed to be constant.  In fact, it's hard to find any information on this at all on the 'net.  It's too bad this tutorial wasn't ranked higher in Google.  I had to specifically search for 'shmup' to find it.  And the document I found was this:
http://www.shmup-dev.com/forum/index.php?topic=1638.0;wap2
which is an unformatted page, so it is likely skipped.  In any case, thanks for the tutorial, it's helped greatly.  It basically convinced me this was the only sane way to get constant speeds out of these splines.  And I like to us Catmull Rom rather than others for the same reasons you do: because they go through the waypoints.

Take care,
Offline  
Read April 07, 2010, 03:15:10 am #9
OMNICYPHER

Re: Control Schemes [part 2] : Spline Motion

thanks for the spline formulas, and great explination too! it seems very usefull, but at the same time, couldn't there be an easier way around the problem? if you want an object to keep its velocity while moving through specific coordinates, couldnt you just rotate its vector with logic? then when the seeking missle reaches its target, it aims towards the next target on the list. depending on how you adjusted the the vector direction, couldnt you produce the same curve with less computation per frame? or would that be more computation? im not really sure... anyway, awsome tutorial!


Good gameplay is when Pace is inversely proportional to mental effort
Offline  
Pages: [1]   Go Up
Jump to:  

Page created in 0.128 seconds with 21 queries.