Hey. I'm trying to create an enemy that travels at a speed s on screen but I'm having trouble with trying to make the speed vary in a smooth motion. Basically, I can get the enemy to move at a constant rate but at random intervals, I'd like it to speed up then slow back down to it's original speed, or slow down then speed up to it's original speed. I imagine I'd have to use a graph function of sorts, but I'm not great at maths so are there any suggestions on how this can be achieved?
Feel free to let me know if my question is unclear.Thanks!
|
|
|||
|
|
|
What you're talking about here is commonly called a "lerp", short for interpolation. You can find a lot of different implementations and specifics about this sort of operation on Google by searching for "lerp", but here's a very basic one:
In this, "fraction" should be a value between zero and one (inclusive), and the type T is anything that supports +, -, and * operators (So floats, vectors, etc). In your case, you'd use one with 'float' instead of T, but this same approach works for interpolating lots of other mathematical types, so this will almost certainly be useful to you again in other situations in the future. The simplest way to get your speed to increase smoothly will be to simply interpolate from the object's current speed toward its target speed each frame, using a low fraction value for the interpolation. For example, like this:
This will give what is referred to as a "slam in, ease out" curve; the object will get a sudden burst of acceleration when it changes its desired speed, but that acceleration will taper off as it approaches that destination speed. If you make speedFraction higher, the object will approach its final speed faster. Lower, and it will reach that speed slower. This is almost certainly all that you'll need to have your character change speeds smoothly enough for you. But be aware that this will produce different behaviours if it's being done 30 times per second than if it's being done 60 times per second. Advanced: If you do want the object to accelerate even more smoothly than this (that is, to start accelerating slowly, instead of quickly), or if it's important that the object actually reaches that final speed (rather than approaching that speed asymptotically), or if you want to make sure that the acceleration works the same no matter what frame rate you're running at, then you can use that same interpolation function differently. If you keep track of when the object began to accelerate, and know how long you want the acceleration to take, then you can calculate:
In this, easeInEaseOutFraction is using a hermite interpolator on the value "fraction", to convert it from a linear transition from zero to one, into a very smooth curve over that same range. And since it still varies only between zero and one, that means that we can pass it into the same Interpolation function we've already been using, to make the interpolation extremely smooth. You may find that you prefer this smoother behaviour over the simpler approach that I gave earlier. Or you may find that it makes no difference in your case. My advice is to do the simpler version first, and stick with it if it's good enough for your purposes. If you do go with the more advanced variation, just be aware that it's critical that the "fraction" value remains between zero and one. If you're using interpolation in this way (by passing in a variable "fraction" value that changes over time), then you must stop interpolating once the object has actually reached its target speed, or else you'll get unexpected behaviour as "fraction" exceeds 1. |
|||||||||||
|
|
You want the speed to increase smoothly from an initial value, let's call it That sounds like a Logisic Function to me! A simple logistic function -- a smooth transition from 0 to 1 is Set up an increment for some variable, let's say
until This is all based on the fact that when The same code works if you want to reduce speed. EDIT: I'd made a logical error with what to choose for |
|||||||||||||||
|
|
You might consider attributing an acceleration value with an enemy. So for each enemy you might associate a velocity(v) and acceleration(a) variable. This would handle the case of the enemy smoothly increasing speed from an initial velocity of zero. Of course you would then need to also associate a maximum speed for the enemy. As for slowing down, there are many ways one could handle this. Simply use the negative of the acceleration, or create your own deceleration variable. |
|||
|
|
|
Here is a function from our engine that I've used over the years. Maybe it can help. It will take aValue up to aMax by aAmount. If you then pass aAmount=0, it will then take it down to zero by aDrag amount... all smoothly. If you view the AstroBlaster video/demo on our site, it uses this routine to control the ship speed. Works great for us. It's Object Pascal but you should be able to adopt it easily to the language you use.
|
|||
|
|