Sidequest

Colliders and Debug

Let's add some box colliders to our pipes and make sure we can see them when we toggle debug (press the d key).

Box Colliders

Update the pipe entity to add a box collider:

+
import { BoxCollider } from "#/components/box-collider";
2
import { SpriteData } from "#/components/sprite-data";
3
import { Vector2d } from "#/components/vector2d";
4
import { Game } from "#/game";
5
6
// ...
7
8
export class Pipe {
9
height: number;
+
boxCollider: BoxCollider;
11
game: Game;
12
position: Vector2d;
13
rimSpriteData: SpriteData;
14
sliceSpriteData: SpriteData;
15
spriteSheet: HTMLImageElement;
16
type: "top" | "bottom";
17
18
constructor(options: PipeOptions) {
19
this.game = options.game;
20
this.position = options.position;
21
this.rimSpriteData = options.rimSpriteData;
22
this.sliceSpriteData = options.sliceSpriteData;
23
this.spriteSheet = options.spriteSheet;
24
this.type = options.type;
25
26
this.height =
27
this.type === "top"
28
? this.position.y
29
: this.game.config.gameHeight - this.position.y;
30
+
this.boxCollider = new BoxCollider(
+
0,
+
0,
+
this.rimSpriteData.width,
+
this.height
+
);
37
}
38
39
public draw(context: CanvasRenderingContext2D) {
40
// ... previous code ...
+
+
if (this.game.debug) {
+
context.fillStyle = "red";
+
context.globalAlpha = 0.5;
+
+
context.fillRect(
+
this.position.x + this.boxCollider.offsetX,
+
this.type === "top" ? 0 : this.position.y + this.boxCollider.offsetY,
+
this.boxCollider.width,
+
this.boxCollider.height
+
);
+
+
context.globalAlpha = 1;
+
}
55
}
56
}

We're applying our usual 50% opacity on the collider to make it easier to see the underlying sprite. We're applying some logic to set the colliders y position based on the type as well.

When you check the browser you should see the colliders after pressing the d key.

Pipes reference lines diagram
Pipes reference lines diagram

The collider is as wide as the pipe rim. Let's change that so the collider is a little more forgiving and matches the size of the pipe body.

Collider Sizing

We're going to store the pipe collider x offset and the width in our config:

1
export const config = {
2
/**
3
* In pixels
4
*/
5
gameWidth: 352,
6
7
/**
8
* In pixels
9
*/
10
gameHeight: 576,
11
+
pipe: {
+
collider: {
+
offsetX: 4,
+
offsetY: 0,
+
width: 56,
+
},
18
},
19
};
20
21
export type Config = typeof config;

The reason we store the x offset is to account for some of the transparent pixels in the pipe body slice sprite. These transparent pixels exist to make the pipe body sprite match the width of the pipe rim sprites.

Now we'll update the pipe entity to make use of this information:

1
export class Pipe {
2
// ...
3
4
constructor(options: PipeOptions) {
5
this.game = options.game;
6
this.position = options.position;
7
this.rimSpriteData = options.rimSpriteData;
8
this.sliceSpriteData = options.sliceSpriteData;
9
this.spriteSheet = options.spriteSheet;
10
this.type = options.type;
11
12
this.height =
13
this.type === "top"
14
? this.position.y
15
: this.game.config.gameHeight - this.position.y;
16
+
this.boxCollider = new BoxCollider(
+
this.game.config.pipe.collider.offsetX,
+
this.game.config.pipe.collider.offsetY,
+
this.game.config.pipe.collider.width,
+
this.height
+
);
23
}
24
25
// ...
26
}

Which will get us a slightly tighter collider:

Pipes reference lines diagram
Pipes reference lines diagram

Much better! Let's move on to some clean up.