Search Unity

Animation Curves, the ultimate design lever

July 21, 2022 in Games | 27 min. read
A white truck going down on a forest road, all made in Unity editor
A white truck going down on a forest road, all made in Unity editor
Topics covered
Share

Is this article helpful for you?

Thank you for your feedback!

This is the third blog post by Christo Nobbs in his series for game designers. The series expands on his contributions to The Unity game designer playbook, a 100+ page in-depth guide that instructs game designers how to prototype, craft, and test gameplay in Unity. Links to Christo’s previous blog posts are included at the end of this piece.

In Unity, there are several “types” we can use to store data that are just as beneficial as design levers for balancing systems, gameplay, character settings, vehicle profiles, and so on. Animation Curves are one such component type that offers game designers and creators interesting possibilities, especially when prototyping. Use them in your project, for instance, within a particle system to control animated variables, or within the audio source component to manage roll-off and other properties.

A curve is a line graph that shows the response (on the Y axis) to the varying value of an input (on the X axis). Unity uses curves in a variety of different contexts, specifically in animation. Curve Editors have a number of different options and tools that you can leverage.

This post will focus on working with Animation Curves via the Unity API, with the variable type AnimationCurve. In this way, they can be used to capture and store data, which is helpful for analyzing results. Curves are also compatible with ScriptableObjects, which, as discussed in the playbook, are great for editing gameplay data.

Animation Curves can be edited within the Inspector either as public variables, or when serialized. You can save, export, or load them in Edit mode or at runtime. Editable tangents make it possible to control the shape of the curve between the keys.

An Animation Curve property in the Inspector
An Animation Curve property in the Inspector: Clicking on it opens the Curve Editor, where you can adjust the curve and save it into your own library by selecting the cog icon.
A tangent's key in Unity
Double-clicking on a curve creates a new key you can use to manipulate it, and also provides several options for controlling the handles of the key.

You can add keys, alter their tangents, and manipulate handles in the curve to find the shape that will deliver the desired results.

An Animation Curve with multiple tangents
An Animation Curve that includes tangents to create organic peaks, troughs, and abrupt angles

Adding lifelike details to everyday motion and movement

A visual design lever like an Animation Curve makes it possible for game designers to finesse gameplay without having to write complex math or easing functions

One way to use Animation Curves is in a timeline, to add nuance and detail into linear motions. Take the example of a character closing a car door. The action starts with a wobble as the hand grasps the lever to close the door. The door closes slowly at first, but the motion speeds up as the door swings shut, and then ends with an abrupt stop; perhaps with a small bounce or click. All of these motions can be saved within the same curve for the sequence.

A brown door opening and closing on a green gar in the Unity editor
A door opening and closing using curves in the animation’s timeline
The curve for opening a door
The curve for opening a door
The curve for closing a door
The curve for closing a door

As this example shows, Animation Curves are beneficial for changing an object’s properties over time to create natural-looking movement. Other use cases center on how an object moves or rotates, a character accelerates or decelerates into or out of a sprint, or an engine delivers power to a car controller.

Animation curve C# code
See this overview of how an Animation Curve in the Inspector returns data on the Y axis at a given position on the X axis. The bottom method shows how to use the EvaluateCurve method by passing the desired curve and position.

When you create an Animation Curve to edit in the Inspector, you’ll be able to evaluate the curve by passing a parameter, referred to as time in Unity. Later in this post, we’ll look at why the position is more descriptive when not using the X axis for time.

A “pseudo” motor torque curve to control engine power output

Let’s examine how you could use an Animation Curve to control the power output of a vehicle’s engine. You can create a “pseudo” motor torque curve to return the force applied to the vehicle based on the current engine RPM (revolutions per minute). This increases over time if the player presses down on the accelerator.

Rather than map the full RPM range for each gear and vehicle, you can “normalize” or set the RPM between 0 and 1. The “torque” curves you create can then be saved and reused for other vehicles and gears.

Set this value by dividing your raw or current value by the max value: 

normalisedCurrentRPM = currentRPM / maxRPM

The output power (Y axis) will also be used between 0 and 1 to keep the Curve Editor manageable, and the curves themselves reusable. This value can be added into the movement force for the vehicle, to move the vehicle Rigidbody forward on the Z axis.

An example script to normalize the RPM
Here is an example script for “normalizing” the RPM, then adding a force based on the Y value of the torque curve at given RPM multiplied by the engine power.

You can create various results with the same setup for other vehicles by staying between the values of 0,0 and 1,1 on the curve.

An upwards green curve
This curve shows a vehicle that has a steady start as the mass begins to move, but at peak power, the engine loses force – encouraging the player to change gears at the right position.

Adding a basic gear-ratio equation to your car’s engine can result in realistic-looking vehicles that move and rock as you go through the gears and hit different power curves, or the same curve at different points. This requires the car to be a Rigidbody. As you add other Rigidbodies in the boot or back seats of the car, the car will have impacted movement, which can be fun for timed delivery missions.

If you don’t want to use Unity’s physics system because you have a custom car controller, you can create unladen and laden variants of your curves, and swap these curves at runtime to get the vehicle to drive the way you want it to.

Although you won’t use this often, you can add keys, modify keys (which removes and adds new keys), and remove keys entirely on curves at runtime via the Unity API. This gives you more control over modifying your curves, which can also include smoothing tangents as needed.

Curves for a heavy vehicle, such as a truck with automatic gears that starts up slowly but then doesn’t lose power after reaching peak RPM: This curve shows the truck without a load.
Curves for a heavy vehicle, such as a truck with automatic gears that starts up slowly but then doesn’t lose power after reaching peak RPM: This curve shows the truck without a load.
This curve shows a truck with a heavy load. By adding another key and a power reduction after the vehicle has started moving, you can make the truck feel like it has a drawn-out second gear, for instance, giving it more personality.
Meanwhile, this curve shows a truck with a heavy load. By adding another key and a power reduction after the vehicle has started moving, you can make the truck feel like it has a drawn-out second gear, for instance, giving it more personality.
A single curve for a vehicle that has multiple gears
A single curve for a vehicle that has multiple gears, which gives the feeling of having automatic gears without implementing an engine system with a gearbox: The curve shows the bulk of the power at second, third, and fourth, where third, fourth, and fifth are longer gears, and fifth goes on for awhile before reaching maximum speed. Different tangents are used to create the desired results.

Animation Curves enable you to create excellent abstractions of more complex systems that you can control in a visual format. In the example of the engine, you can add power over time when accelerating with the curve shown above (which represents the “pseudo” gearbox) to create the feeling of the car changing gears – adjusting its pitch up as power is delivered, then down again as the power rolls off at the top of each gear. This is ideal for prototyping a vehicle’s movement by placing all the car power on one curve that maps all the gears, from the start of the first gear at x0,y0 to the top of the fifth gear at x1,y1.

RPM usually accumulates over time when accelerating, so essentially you are plotting values over time, much like adding linear movement to a moving object. Read more about this in the section on timing and animation in the Game designer playbook.

Three futuristic looking cars are racing on a large grid road with neon blue lights surrounding the road
“Pseudo” physics are useful in games where the motion doesn’t adhere to the rules of real-life physics, such as in the futuristic Made with Unity racing game, Antigraviator.

Let’s take another example; the suspension and motion of a car when it drives over uneven terrain, around corners, or when power is delivered at the wheels. Better steering, control of lateral forces or tire slip can all be managed with Animation Curves to create lifelike results that you can refine visually.

When creating raycast-based mechanics for a vehicle, whether a hover vehicle or wheeled, a common choice for creating the effect of “suspension” in the engine is an upward force applied on each ray and a PID (proportional–integral–derivative) controller algorithm to control the bounce, or in some cases, Hooke’s law for damping. An instance of this can be seen in Unity’s Hover Racer Live 7/21 Cycle 4.2, alongside an example further down in this post using a PID based on it.

A PID controller algorithm is a control loop feedback mechanism, or a controller, used in many industries, including game development, when responsive correction is needed. The PID controller calculates an error value as the difference between a measured process variable and a desired set point, and in relation to elasticity (or our given example), it can be used as an alternative to Hooke’s law. A PID in games is also practical for:

  • Making a vehicle regulate a target speed in cruise control mode, while being unpredictably subjected to other factors like carried mass, player input, or terrain angulation.
  • Controlling how much accuracy enemy AI agents have when shooting back at your players, while they avoid getting hit.
  • Latency prediction in multiplayer games.

PIDs can be used anywhere in game development, especially in sandboxes and simulations that require “accurate and optimized automatic control”. Kerbal Space Program by Squad uses PID to keep a spacecraft heading in a single direction.

According to this study, “PID regulation is the most mature and widely used technology of continuous systems” outside of game development. See this Control System lecture: Introduction to PID control for additional information.

A space rocket is in a hangar, with an interface open on the left, showing customization options for the rocket
Kerbal Space Program by Squad, available on Steam, uses PID controller algorithms.

PID controller algorithms might not take much time to make, but they do require time to balance; time that is multiplied depending on how many vehicles you have. However, when prototyping, you can use an Animation Curve instead to save time or avoid the technical challenges of implementing and balancing multiple PID controllers (you’d eventually want to replace the curve solution with a PID for ultimate control).

Curves are ideal for prototyping because they can be used to visually match real-world target reference examples. When it comes to space, this is “mathematically perfect” in a game engine, with no opposing motion forces unless they are added or default gravity is enabled. So it is often easier to use a simple curve to control change and yield strong results.

In the case of creating suspension for a vehicle, you can use Animation Curves to inform how much opposing force is applied based on the compression level of the spring, (normalized between 0 and 1), rather than using a PID controller to create damping. Combined with a Rigidbody and a small amount of drag, the bounce oscillation is suppressed and the vehicle’s suspension reacts to increased or decreased load.

To determine the spring compression, you need to subtract the ray hit distance from the spring length from 1.0f. Regardless of its length, when the spring is at 25% compression, the compression value will be 0.25. Set this compression value as the X value on the Animation Curve, multiply it by the desired spring force (because you are working with normalized values), and then use it in AddForceAtPosition to apply the upward force at each point in a loop, based on the number of suspension points. No additional downward forces are needed other than Unity’s default gravity at -9.81f.

Here’s the formula: 

upwardsForce = forceMultiplier * forceCurve.Evaluate(springCompressionNormalized);

rigidBody.AddForceAtPosition(hitNormal * upwardsForce, point.transform.position);

Using a 13:110 mass:force ratio and the below curve.

A white van without wheels falling down on a road in front of a forest, in Unity
A van without wheels with extended suspension lengths (1 meter spring length): The van falls at an uneven angle, straight down, and rocks back-and-forth.
A double sigmoidal curve
See a curve resembling a double sigmoidal wherein the first short phase is a reverse curve, followed by a slight negatively sloping dip at the start of the second phase. The force curve, where X = normalized spring compression, and Y = power (0 to 1), is used to create a damped result on the falling Rigidbody (the vehicle shown above), to simulate suspension.

The vehicle settles at approximately 50% compression using suitable values for mass, upward force, and small amounts of linear and angular drag to suppress oscillation. This allows for the vehicle to bounce and settle – but not bottom out, unless dropped from an extremely high height or overloaded by the player adding mass.

To find good values, start with a y = b^x curve (which looks similar to a quarter of a circle). Keep the drag low and set the vehicle’s mass to what it is in reality. The upward force is then adjusted until the vehicle sits at approximately 50% spring compression. Drop the vehicle a few times to check if it bottoms out and see where it settles after the bounce. Using this approach for the suspension of vehicles that drive over uneven terrain, where each point of traction can be gained or lost, makes for a quick and controllable suspension system.

The use of Animation Curves for your suspension model can ensure varied motions for vehicles – cars, vans, or trucks with bad suspension – namely those that bottom out all the time, bounce like those in arcade games, or roll around corners and wobble when you accelerate and brake. Curves can be used in combination with existing systems if you’re not already using Unity’s Rigidbody system or your own suspension method. You can use curves for steering, or to amplify engine power, suspension, drag, tire slip, braking force, and more. Animation Curves are such a handy and versatile tool in Unity for adding design levers to each vehicle to control their characteristics visually in the Inspector.

Grey balls falling off with different characteristics and curves in Unity
Using different curves for each Rigidbody to view characteristics when dropped
The curves for each sphere in the previous image
The curves for each sphere in the previous image
A code snippet in C# for dropping objects
The code snippet for dropping spheres

The row of spheres in the image above was created by positioning a sequence of Rigidbodies in a row and constraining their X and Z Freeze Position properties. An upward force was then applied using an Animation Curve based on the compression upward force, but with different curves for each sphere, positioned side-by-side for better visualization. You can use this technique to find the desired level of bounce for an object, or to tweak existing bounce to balance out characteristics. As a designer, being able to manipulate the characteristics of the upward force can help you create abstractions of more complex functions.

Curves are a powerful XY chart data type, and though not technically perfect, they can help you prototype speedy damping solutions that can be visually edited in the Inspector and saved as presets at runtime. In this blog on the art of damping, Alexis Bacot highlights all the things that “depend on good damping. Camera, animation, movement, color gradients, UI transitions, and many many more… it’s used everywhere! Understanding damping is key to achieving great polish. Damping alone can make the difference between a bad or good experience.”

In the same post, he demonstrates how Unity’s SmoothDamp can be used to create a beautiful ease in and out, and reacts to the target changing accurately. But it does not bounce like an “advanced spring damper that can oscillate, which is great for car suspension or fake ball physics” – an example of where Animation Curves provide a powerful advantage.

Of course, curves have more uses than as an XY data type to manipulate gameplay. They can also be treated as an evaluation tool to capture data visually using AddKey via the Unity API. For evaluating a position over time, such as damping in the vehicle suspension example, or the falling spheres, use AddKey(elapsedTime, currentSpringCompression) in a method, and then call that method and pass captureResolution as the repeating rate via InvokeRepeating. A capture resolution of 0.1f means that, at every 0.1s, a key is added to the curve. View the mini result in the Inspector, or open the graph up to see the complete data.

A plotted curve
A plotted curve result from using a linear bounce curve that has a direct straight line from 0,0 to 1,1
A plotted curve
A plotted curve result from using a non-linear, double sigmoidal-like curve, similar to that shown above

Back to the bouncing van

Let’s take one last look at the falling van. The Animation Curve dictates how much force is applied based on the spring compression, and creates a result close to the target, which would have a little more oscillation on the third bounce. You can compare the suspension created with an Animation Curve to that of the PID controller, using the PID in Unity’s Hover Racer Live 7/21 Cycle 4.2. The only difference is that the PID result is multiplied by the hover force instead of the Y value of the Animation Curve.

After implementing the PID and a lot of balancing, the vehicle’s suspension feels closer to the target with less trailing oscillation, and less drag needed for suppression. Unfortunately, the PID needs to be balanced for each vehicle if they have different mass values, which takes a long time. For prototyping purposes, this can be done quickly and visually with Animation Curves, and the plotted results of the motion can be analyzed. To evaluate the PID implementation, again, you can use a curve to plot the result to a blank curve. The result is much better, with a slightly exaggerated second bounce, but providing the motion and appearance you want for a big buoyant van.

A white van without wheels suspended in the air, in Unity
The final implementation of vehicle suspension using PID, but based on the Animation Curves developed during prototyping: The suspension is still exaggerated, using spring lengths of 1 meter.
A target damping curve on the left, with a plotted result curve on the right
See the target damping curve result from Alexis Bacot on the left, and the plotted result of the vehicle’s motion after implementing the PID on the right.

To recap, use Animation Curves when developing vehicle motion to: 

  • Plot the output of a vehicle’s engine power and produce smooth power progression.
  • Create realistic braking motions, like when the brake force is quickly applied and then reduced over time to simulate braking a real car; or, in a game such as iRacing, where the driver brakes on the tire limit so that the car slows down in a short amount of time without spinning out of control.
  • Simulate a suspension system that provides the upward forces for the car.
  • Simulate lateral traction, with lateral counterforce calculations that keep the car from sliding too much to the left or right.
  • Simulate steering when using a controller (steering is usable near the middle, around -0.5 to 0.5, but gets progressively faster when the stick position approaches -1 or 1).
A green block floating on blue water, surrounded by mountains, in Unity
In this prototype, curve.Evaluate(time) is used to move the platform’s Transform on the Y axis over time.

In addition to vehicle physics, Animation Curves can be used as design levers for prototyping player movement, hit damage over time, and more. As a powerful prototyping tool, Animation Curves empower game designers to test the application of varying force, and identify the right “feel” for mechanics, without having to write complex algorithms or physics calculations.

For more guidance and inspiration, check out the Game Designer Playbook available to download for free.

July 21, 2022 in Games | 27 min. read

Is this article helpful for you?

Thank you for your feedback!

Topics covered
Related Posts