Ambience features a range of weapons, which the protagonist (or an enemy) can use to attack. For the player, it’s easy: just press the A-key to get that sword swinging.
But what’s really going on behind the scenes to get the sword and hand moving?
In Ambience, characters with hands have their body and hands drawn and considered separately – in contrast, many other games draw arms and hands as part of the body, including in attack animations. The drawing part’s relatively easy – all that needs to be done there is to draw the hands and body in the correct order, depending on which way the player’s facing. But at what position should the hand be drawn during each part of the attack animation? For this, we’ll need a bit of fancy maths.
At school you probably learned about graphs in Cartesian coordinates, or on the x-y plane. The basic idea there is that an x-value (horizontal) will give a certain y-value (vertical), making a single point on the plane. Doing this over and over gives you lots and lots of points, which together can simply be drawn as a line or curve. For example:
You can make circles and ellipses in Cartesian coordinates fairly easily, too:
These functions could be useful for an attack animation – for example, the hand and weapon could follow an elliptical path out from the body, by setting the hand coordinates to follow the formula for an ellipse. However, when I tried this, the hand movement was a little too smooth and slow at the ends. It looked less like a ferocious attack animation and more like the protagonist was stirring a bowl of egg and flour on your favourite cooking show.
In order to get the attack animation looking better, I needed the end of the path near the player to be sharper, while the rest of the path remained smooth and more-or-less elliptical…
An alternative to Cartesian (x-y) coordinates is to use a polar coordinate system. Instead of drawing every point on the curve at a horizontal (x) and vertical (y) position, this time we pick an angle to the horizontal axis (t, or sometimes the Greek letter θ) and draw a point at a certain radius (r), or straight-line distance from the origin, at that angle. In mathspeak, we’d say that the radius r is a function of the angle t.
An advantage of using polar coordinates is that you can make all sorts of weird shapes, like spirals, figure-eights and flower-petals, relatively easily:
But those flower-petals and figure-eights are exactly what we need for our hand-swinging path! Specifically, we want to pick one petal of the flower (or one loop of the figure-eight) and use that as the path which our hand follows.
Thankfully, GM:S has some handy functions, lengthdir_x and lengthdir_y, which can convert a radius and angle (polar coordinates) into an x and y position (Cartesian coordinates), which made finding the required hand position easy.
Facing Different Directions
However, we also want to rotate that path depending on which way the player’s facing. After all, we don’t want the player to be facing left and still swing his fists to the right.
The way I dealt with this was a little bit mathemagical, so hang in there. Let’s start with the four-petal flower we had before:
Here the radius, r, depends simply on t. But, we can change the rotation of the flower petals by writing r as a function of (t-t0). Here t0 is just a constant which shifts the angle by t0 – in other words, it rotates the curve clockwise by an angle of t0. (That’s in radians, not degrees).
So, when the hand traced out its path and I wanted to rotate that path, all I had to do was incorporate that t0 factor. How? By writing (t-t0) in my formulae instead of just t.
And, since t0 depends on the direction the player’s facing, I also added a script to keep updating t0 depending on which way the player’s facing. That way the path was always rotated the right way. (In reality I chose to update and store three values, which were the t-values at the start, middle, and end of the motion – where t0 is just the value at the start. You’ll see why I did this a little bit later.)
Another way I could have done this is to use an eight-petal flower, and just select and trace out a single petal for each 45 degree direction the player could face. In mathspeak, that’s called restricting the domain of the curve – i.e. selecting only a small range of angles t which the player’s hand should trace out. If I left t unrestricted, the hand would trace out the entire eight-petal flower over and over again, like some weird eight-direction ninja attack.
The reason why I didn’t choose this method was because the “petals” of the polar curve here were a bit too thin, so the sword swing wasn’t as broad and noticeable as I would have liked. It looked too much like a sword thrust motion, which was OK for swinging a sword, but wasn’t really suitable for throwing a punch.
Now, what about the sword itself? So far the sword’s still been facing the same direction while the player swings it around, which looks a little odd. What we want to do is to rotate the sword as it’s swinging, like the player’s using his wrist to really swing that sword at the enemy.
Take a look at this slowed down GIF from before:
Specifically, we want the sword to be angled outwards before it reaches the far end, then horizontal at the end (as the sword’s hitting the enemy), then angled inwards as it’s coming back to the player. Perhaps you’ve noticed that this means the angle of the sword depends on how far the hand is around its path – in other words, the sword angle is also a function of that parameter t!
So in GameMaker, all we have to do is to use an extended draw function to rotate the sword sprite about its origin, using a formula for the rotation which relates to t. This is one place where the three t-values I mentioned earlier come in handy. The formula I used for the sword angle had this form:
sword_angle = (player_direction) + (t-t_middle)*(K)*(isAttacking);
Basically this says that the sword should face in the same direction as the player, if the player isn’t attacking (isAttacking = 0). If the player is attacking (isAttacking = 1), then we take the player direction and also add on another factor (t-t_middle), which based on how far around the path the hand is. At the middle of the path, t = t_middle and so this is where the sword’s fully extended in front of the player. Finally, K is just a constant which essentially controls how much the player’s wrist pivots during the swing, so that the sword rotates by the right amount during the swing.
And, that’s it! Time to slay some enemies!