In many modern top-down view games, such as The Legend of Zelda: A Link to the Past, players have great freedom of movement in that they can move in any of the four cardinal directions (North, South, East, and West) as well as in directions in between. (This is a step up from games such as the original The Legend of Zelda, where the only possibly movement was North/South/East/West.) Even in games where the player can walk in more than the four basic directions, typically there are still only four walking animations corresponding to the four cardinal directions; whatever angle the player is walking at, the program calculates the primary direction (N/S/E/W) of motion, and activates the corresponding walking animation.
In this article, we demonstrate an efficient way to calculate the direction and set the animation for the player and enemy characters in a game with a top-down view.
A standard practice in game programming is to maintain multiple objects for each character: for example, one sprite object to control the position/rotation/movement/collision detection, and another sprite to store the animations. (For instance, you might want your character to be able to move at a 45 degree angle on the layout, but you don't necessarily want the animation images to be rotated by this amount.)
We begin by creating two sprites. One sprite will be named "Player" and have the 8-Direction, Scroll-To, and Bound-to-Layout behaviors; this object handles our movement. Another sprite will be named "PlayerAnimation" and have the Pin behavior, so that we can set it up to automatically move in sync with the player object. We accomplish this with the events shown below.
Note in particular that when pinning PlayerAnimation to Player, the "Position Only" option should be selected, to avoid undesired rotation of the animation images.
Next, we present two methods for setting the Player's animations correctly. The first method is straightforward but requires many events; the second uses a bit of math and is much more efficient.
In this method, we first calculate the name of the primary direction in which the player is moving, using some comparisons; then, we store the name of the corresponding direction in an instance variable, and use this information to set the animation. If A represents the angle of the Player sprite, then the comparisons are:
Using the "Is Between Angles" condition, we set:
* if -45 <= A <= 45, then set DirectionName = "East"
* if 45 <= A <= 135, then set DirectionName = "South"
* if 135 <= A <= 225, then set DirectionName = "West"
* if 225 <= A <= 315, then set DirectionName = "North"
(( Important technical note: here, we are using the player sprite's image angle to calculate direction of movement; the 8-Direction behavior is configured to sync the image angle, and image angles range from 0 to 360. In some situations, such as using the Angle of Motion from the Bullet behavior, angle measurements use the range -180 to 180; in this scenario you need to compare values using the System: Compare Two Values condition to access the Bullet.AngleOfMotion value, and you would need to make some conversions in the comparisons above, for example, 315 degrees is equal to -45 degrees, etc. ))
Then, using the information stored in DirectionName, and taking into account whether the player is actually moving, the correct animation should be set to play. (For this example, the animation names are WalkEast, WalkSouth, WalkWest, and WalkNorth.) When the player is not moving, the animation should be stopped. The events below detail how to do this.
With a little bit of math, we can accomplish the same result with fewer events (all four comparisons can be achieved with a single action). In this method, instead of storing the names of directions in a DirectionName instance variable, we'll create a number code for each: 0 for East, 1 for South, 2 for West, and 3 for North; these numbers will be stored in a variable called DirectionCode. We create a formula that will convert each of the angle ranges listed above into one of these four numbers. If A represents the angle of the sprite image, then the formula is:
floor( (((A + 45) % 360) / 90) )
To see how it achieves the desired result, we will look at a few examples.
* If the sprite angle is A = 30, then A+45=75, 75%360=75, 75/90=0.833333..., and floor(0.833333...)=0, which corresponds to the Eastern-facing animation.
* If the sprite angle is A = 267, then A+45=312, 312%360=312, 312/90=3.46666..., and floor(3.46666...)=3, which corresponds to the Northern-facing animation.
* If the sprite angle is A = 352, then A+45=397, 397%360=37 (only for numbers greater than 360 will %360 have any effect), 37/90=0.41111..., and floor(0.41111...)=0, which corresponds to the Eastern-facing animation.
For this method, the animations need to be named Walk0, Walk1, Walk2, and Walk3 (for East, South, West, North respectively); then, the events below will have the same effect as the events from Method #1 above.
The process for setting the correct animation for the other characters is almost identical to the events for setting the player animations; there are just a few differences. The more obvious differences are that the Default Controls property of the 8-Direction behavior should be set to No, and when there are multiple enemy objects, they should be processed/updated using a For Each loop.
A less obvious change that needs to be made occurs when there is more than one instance of a particular type of character (which is typically true for most enemies, except for boss-types). Every Enemy sprite will need a corresponding EnemyAnimation sprite, and they need to be "paired" together, so that selecting an Enemy also selects its own EnemyAnimation. The way to accomplish this in Construct 2 is by using Containers. To do this, after creating your Enemy and EnemyAnimation sprites, select the Enemy object in the object list, and in the properties panel, underneath the Container heading, click on "Create", and select the EnemyAnimation object in the window that appears. The result will be that when the layout starts, extra copies of the EnemyAnimation will be spawned until there is one for each Enemy, and they will be "paired" as explained above. (See the manual entry for Containers for more details.)
The events below show how to change the enemy animation, in the same style as the player animation.
As a side note, you may be wondering how to control enemies with an 8-Direction behavior. The included capx file includes a number of events to move the enemies around; for the sake of completeness (at the risk of being off-topic), the events are included below. This uses a technique from artificial intelligence called "state machines", which are discussed at length in my article on A.I. and State Machines, which may be of interest as well.
The example capx file included with this article shows these events in action and is recommended to download and run. Hopefully the techniques discussed in this article will help you in using animations with the 8-Direction behavior in your own Construct 2 projects!