Animation Curves
Animation curves were sort of theme in the previous section, so I figured I’d go all the way and give you a idea of how to do the transitions using actual animation curves
Review
All our camera effects looked very different, but they each had an underlying curve which determined how the animation speed changed. This is often called easing, for example an “ease in” curve starts slow, where as an “ease out” means it ends slow
Let’s take a closer look at some of the curves we already coded up. original, current, and dest represent where the value started, where it current is, and where it’s going respectively. And the r parameter is a fixed value that influences how quickly the curve completes
Feature | Code | Description | Image |
---|---|---|---|
Smooth Camera | current = lerp(current, dest, r) | It get’s slow toward the end, so it’s ease out | |
Camera Shake | current *= r; | Also ease out, this is actually a specific case of the previous where dest = 0 | |
Camera Transition | t += r; current = lerp(original, dest, t) | No ease, this a boring straight line / linear transition. It approaches the destination at the same rate every frame |
So the camera transition was kind of boring, and on screen the linear transition looks a little abrupt. Let’s fix that
Ideally I’d like to have both ease in and ease out (so start slowly, move quickly in the middle, then end slowly), but tbh I have no idea how to do that with math
Animation Curves to the rescue 🦸♂️
Custom Animation Curves
Go ahead and create a new animation curve, and call it animTransition
When we open it up, and expand curve1
you’ll notice that the curve is broken down into a series of points. We can either add them manually, or click/drag on the curve it’s self
and btw, we can also change the range in case we want to go outside the default 0 to 1 range
We’ll just start with a straight line going from (0,0) to (1,1), and come back to update it later
Coding
If you type animcurve_
and hit ctrl + space, you’ll notice that there are a lot of animation curve function available for us
Well luckily, if you create the curves in the editor, we only need 2 functions
animcurve_get_channel
: This will retrieve a specific channel within a curve
What are channels?: Well if we go back to the curve editor, we can actually add multiple curves within the channel, and also name them whatever we want. We’ll stick with 1 channel for now, and I’ll name it “only_channel”
animcurve_channel_evaluate
: With this function will can pass in a x value, and we’ll get the corresponding y value on the curve (not to be confused with room coordinates, here I’m just saying x/y in the context of the curve)
Now let’s see how we can incorporate these into our code 😃
// oControl Create Event
// delete trans_amt
trans_cx = 0;
// oControl Step Event
if(is_transitioning){
//// APPLY TRANSITION ALONG X
trans_cx += 1 / trans_steps;
var ch = animcurve_get_channel(animTransition, 0);
var trans_amt = animcurve_channel_evaluate(ch, trans_cx);
cam_x(lerp(trans_start_x, trans_target_x, trans_amt));
if(trans_cx >= 1){
is_transitioning = false;
}
}else{
//// CENTER ON PLAYER
//// SMOOTH CAMERA
//// CLAMP TO BOUNDS
//// CAMERA SHAKE
//// APPLY
////TRIGGER TRANSITION TO THE LEFT
...
// update trans variables
is_transitioning = true;
trans_cx = 0; // replace trans_amt
trans_start_x = cam_x();
trans_target_x = left_bounds + max_shake_dist;
...
////TRIGGER TRANSITION TO THE RIGHT
...
is_transitioning = true;
trans_cx = 0; // replace trans_amt
trans_start_x = cam_x();
trans_target_x = right_bounds - max_shake_dist - cam_w();
...
}
trans_cx
: This variable represents the x along the curve. I’ve made trans_amt
a temporary variable, and changed most of the trans_amt
references to trans_cx
. We’ll step trans_cx
from 0 to 1 the same way we did with trans_amt
, but now trans_amt
will correspond to the y value along the curve and that will give us a lot of control over how trans_amt
changes
var ch = animcurve_get_channel(animTransition, 0);
: animcurve_get_channel
takes to parameters, the curve and the channel. I could have used "only_channel"
for the channel, but we can also use numbers and I figured that’s easier when there’s only 1 channel. If we had more I would have probably used the name
var trans_amt = animcurve_channel_evaluate(ch, trans_cx);
: Now that we have the channel, we can pass in the current x along the curve and use it to get the current trans_amt
. Again note that I’ve made it a temprary variable, we’ll be retrieve fresh values every step
For now since the curve is just a straight y=x
line the results should be the same. So try testing it out, and make sure it’s still working
More Curve Styles
Now let’s get crazier with our curves!
I mentioned we wanted a ease in / ease out effect, well now that’s easy. Let’s just add a few more points, and see how that looks
It looks better, but it’s still a little abrupt. Luckily we can change how the points get shaped. Let’s try smooth
That’s it 😀! That’s the effect we’re looking for! doesn’t that look a lot better?
Just to be complete, let’s also look at bezier curves. For this we can change the slope at the individual points to have more control
Also, it’s not relevant for this particular curve, but if you hold in alt you can change the left/right sides of the slope
Presets
So adding points will definitely get us where we want to go, but bezier mode also has a lot of handy presets. We can ease in - ease out to make sure it’s following the rough sequence that we want
if we select “between” instead of “overwrite”, we can opt to only apply the preset to subsegments of the curve
Let’s try the elastic preset just for fun
It almost gives a cartoony look 🤣, but I think I’ll go with the more boring quart option as my final selection
Camera Shake
And that’s animation curves! An easy way to adjust how your transitions work w/o doing a lot of math 😍
I mentioned that we used curve logic for the smooth camera as well the camera shake, and we can use animation curves there as well! So if you want to practice maybe you can try replacing the camera shake with animation curves? (smooth camera is a little trickier)
Here’s my code
// oControl Create Event
shake_cx = 0; // remove shake_dist
shake_steps = room_speed;
// oControl Step Event
if(is_transitioning){
//// APPLY TRANSITION ALONG X
}else{
//// CENTER ON PLAYER
//// SMOOTH CAMERA
//// CLAMP TO BOUNDS
//// CAMERA SHAKE
shake_cx = min(shake_cx + 1 / shake_steps, 1);
var ch = animcurve_get_channel(animShake, 0);
var shake_dist = max_shake_dist * animcurve_channel_evaluate(ch, shake_cx);
var shake_dir = random(360);
var shake_x = lengthdir_x(shake_dist, shake_dir);
var shake_y = lengthdir_y(shake_dist, shake_dir);
cam_x += shake_x;
cam_y += shake_y;
//// APPLY
////TRIGGER TRANSITION TO THE LEFT
////TRIGGER TRANSITION TO THE RIGHT
}
// oTurret Destroy Event
with(oControl){
shake_cx = 0;
}
shake_cx = min(shake_cx + 1 / shake_steps, 1);
shake_cx
: Similar to the camera transitions, I went through and replace shake_dist
w/ shake_cx
since that’s now the primary variable in our shake animation. But shake_dist
went from max_shake_dist
to 0, whereas shake_cx
will go from 0 to 1 just like trans_cx
did
shake_cx = min(shake_cx + 1 / shake_steps, 1);
: We want shake_cx
to move all the way to 1 and then stop. If you only want to clamp one side, using min
or max
is a handy trick. In this case it will keep stepping upwards until it goes above 1, once it’s above 1 (1.1 for example), min(1.1, 1)
would ensure it sticks at 1
For making the curve it’s self, I started out with a linear curve going from 1 to 0, and then I applied ease out + bounce (not sure if it’s the most natural looking, but it’s still fun)
var shake_dist = max_shake_dist * animcurve_channel_evaluate(ch, shake_cx);
: I’m having the curve start at 1 and then move to 0. So to incorporate max_shake_dist
I need to multiply it by the curve to make the distance start at max_shake_dist
and then go to 0. I could have also made the curve it’s self bigger, but keeping max_shake_dist
as a variable will make it easier to tweak the magnitude of the shake
with(oControl){ shake_cx = 0; }
: Earlier we had shake_dist = max_shake_dist
, but since shake_cx
goes from 0 to 1 we need to start at 0 to initate the animation
And that should do it, now we can control our camera shake with curves 😍
Animation Curve Series
I hope you enjoyed this little detour down curve lane, if you want to try more things I actually made a whole series with different curve effects. It also includes camera transition and shake tutorials, but they use slightly different approaches. For the shake one in particular I use the curve to control shake_x
/ shake_y
instead of the shake_dist
so you can check it out to see which approach you like better