Categories

# 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.

### 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;
```

### 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

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