Action Lists Part 2

Action lists by themselves are very powerful. As I hopefully showed in part 1, they provide an easy way to chain multiple actions together to form more complex and interesting behavior. But, there are often types of actions that execute in similar ways. If we have an action that scales an object over time, as well as an action that changes an object’s color over time, we have two actions that are repeating the same kind of timing logic. If the time-based logic is abstracted and shared among all actions of that type, it makes things a lot simpler to use, as well as less error-prone. In this post, I’ll show how the interface for these actions can be formed, as well as show some examples of actions that I’ve found useful.

« Read Part 1

Interval Actions

Many times, you’ll want an action that runs for a given amount of time. Creating an action for sliding a menu in from the edge of the screen, or fading a character’s sprite in and out can become much simpler when working with actions instead of managing a timer manually. Here’s where sharing a common interface will really cut down on duplication, and therefore bugs.

Here, we’re simply overriding the startup, update, and shutdown functions of the action class. If C++11 is available, it’s useful to mark these methods with the final specifier to prevent any accidental overriding. These methods keep track of a timer and increment its elapsed time every update. Then, we simply calculate the percentage the action is done stored in a value between 0 and 1, and pass that to a new virtual function.

Example Usage

Here is a simple example that moves an object with a transform by a given amount over a set amount of time.

Instant Actions

We can create a similar class that handles actions that only execute once, such as an action that calls a function, or sets a value. I like to call these instant actions, because they perform their task and finish as soon as they are started.

As you can see, the interface for instant_action is extremely trivial. In fact, one could argue that it’s not a necessary addition at all. However, it defines a clear interface for this type of action. Instead of trying to keep track of whether or not to put the executing code inside of the action’s update or startup, using this interface keeps everything clean and consistent.

Example Usage

Here is an example of an instant_action that destroys an object. This can be useful in a game where an object needs to be destroyed after a chain of actions.

Summary

Using the interval_action and instant_action interfaces, creating interesting actions becomes very straight-forward and cohesive. The interval_action can be further expanded upon for things like easing by calculating the interval in a non-linear fashion before passing it on.

« Read Part 1