Categories
guides

Collisions and Depth in Classic Beat em Ups

Classic beat’em up games like Final Fight or Streets of Rage are 2D scrolling games on a faux-3D playing field. This means that though the characters are flat against the background, they need to interact with and block other characters/objects based on their perceived depth of the play field.

Let’s breakdown some of these challenges in GameMaker Studio.


The enemy and those trash cans are both looking for collisions, but the enemy can walk in front because it’s lower on the screen.

Field Depth

Let’s first look at field depth. We need a way for all the objects in the play field to behave as if they’re in a 3D environment… more or less 🙂 First thing is to make sure objects “closer” to the camera stays in front. and everything further “away” is masked by whatever is in front.

Remember, “Closer to the camera” is just lower on the screen. This means the object’s y-coordinate will be higher than the other object. So let’s tie-in the y-coordinate with the object’s depth value.

//STEP EVENT
depth = -y;
That’s more like it.

Collisions

Let’s move on to our collision code. You may want your characters to bump into each other, or maybe you want them to only bump into objects like the beautiful trash-can I just made. Either way, you’ll still want some collision on boundaries in the game.

Remember, the basic collision functions in GMS relate to the sprite’s collision mask that is assigned to the object. So let’s take a look at that.

By default, GMS is going to us automatic masking on the entire image.

When travelling vertically, the top of our sprite’s head is going to bump into the bottom of other objects. Objects that are much “further away” from where the sprite is.

One trick is to set the collision mask for a smaller portion of the sprite. Allowing for the characters to pass through other objects. Setting the height of the collision mask would then be like setting the depth of the object.

Airborne Collisions

So now we’ve got our objects on the screen at the correct depth. And they’re all able to move around and run into each other at the correct spacing. But let’s add some flavor, let’s add some jumping to our little game.

To start us us off we have an example of basic movement and collision, based on the excellent tutorials by Shawn Spaulding.

//STEP EVENT
hsp = (-left + right) * movespeed; //apply horizontal speed
vsp = (-up + down) * movespeed; //apply vertical speed

//check for horizontal collision, stop object at wall
if (place_meeting(x+hsp,y,obj_wall)) {
   while (!place_meeting(x,y,obj_wall)) {
      x += sign(hsp);
   }
   hsp = 0;
}

//check for vertical collision, stop object at wall
if (place_meeting(x,y+vsp,obj_wall)) {
   while (!place_meeting(x,y,obj_wall)) {
      y += sign(vsp);
   }
   vsp = 0;
}

//apply speed to coordinates
x += hsp;
y += vsp;

In a regular 2D platforming game, we would check for all the collisions across the horizontal and vertical axis because the camera is looking at the gameplay from a perpendicular perspective. Beat’em up games like ours also control depth. If the object moves up the screen, it’s actually moving further away from the camera. So we’ll need to lock down the character’s y-coordinate movements.

First, let’s set a flag variable (true/false, boolean) on the character object to see if the character is grounded.

Next, let’s consider the collision box we have on the character’s sprite. If the object moves up, that collision box is going to move too.

Helper objects to the rescue!

Fortunately, I added a “shadow” to the character by creating its own object.

I simply move the position of the shadow object with the player object during the step event.

//CREATE EVENT
shadow = instance_create_depth(x,y-1,obj_shadow)

//STEP EVENT (added)
with (shadow) {
   x = other.x;
   y = other.y;
}

Since it’s moving with the character at their feet, then why not use it for collisions! Let’s go back to our collision code, and modify it to use our new shadow object.

We’ll use the handy “with” function to run all the collision code using the shadow object, and then use “other” to call back to our player object.

with (shadow) {
   //check for horizontal collision, stop object at wall
   if (place_meeting(x+hsp,y,obj_wall)) {
      while (!place_meeting(x,y,obj_wall)) {
         other.x += sign(hsp);
      }
      hsp = 0;
   }
   //check for vertical collision, stop object at wall
   if (other.grounded) {
      if (place_meeting(x,y+vsp,obj_wall)) {
         while (!place_meeting(x,y,obj_wall)) {
            other.y += sign(vsp);
         }
         vsp = 0;
       }
   }
}

Let’s not forget the shadow object is moving in step with our player object. So we’ll need to use that “grounded” flag we created to make the y axis conditional. Otherwise we’re just ignoring vertical collisions and our player will get stuck in walls and boundaries!

//STEP EVENT
with (shadow) {
   x = other.x;
   if (other.grounded) y = other.y;
}

Conclusion

Hopefully you can see how quickly we can sketch-out the beat’em up depth mechanics quickly in GameMaker Studio. Obviously you’ll want to fine-tune the collisions for your own game. And it definitely goes without saying there are more ways to handle this type of movement in GameMaker, this is just one way.

By Rob Nichols

Rob Nichols is an IT professional with years of experience creating games in GameMaker Studio, creating electronic music, and producing the weekly VGM podcast Rhythm and Pixels.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s