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.
You can add keys, alter their tangents, and manipulate handles in the curve to find the shape that will deliver the desired results.
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.
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.
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.
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.
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.
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.
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.
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:
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.
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.
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.
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.
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.
To recap, use Animation Curves when developing vehicle motion to:
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.