Enemy Collisions

Our game is already filled with different types of collision reactions with NPCs. However, in order to make our game even more challenging, we can introduce the idea of having an Enemy. Having an enemy doesn’t come without its consequences. In this lesson, you will learn how to create consequences when our player collides with an enemy.

Creating an Enemy

In order to make our enemy, we decided to create a new class for it. We made a new .js file titled ‘Enemy.js’. Like the other aspects of our game, this allows us to store all the functions for the enemy and create consequences for collisions without making a mess of our code. We extended this class from our character class. There it is:

import Character from './Character.js';
import Player from './Player.js';

class Enemy extends Character {
    constructor(data = null, gameEnv = null) {
        super(data, gameEnv);
        this.playerDestroyed = false; // Tracks if the player has been "killed"
    }

    // Overrides the update method to handle collision detection.
    update() {
        // Start by drawing the object
        this.draw();

        // Check if the enemy collides with the player
        if (!this.playerDestroyed && this.collisionChecks()) {
            this.handleCollisionEvent();
        }
    }

    // Checks if the Enemy collides with the Player.
    // Returns true if a collision is detected, otherwise false.
    collisionChecks() {
        for (const gameObj of this.gameEnv.gameObjects) {
            if (gameObj instanceof Player) {
                this.isCollision(gameObj);
                if (this.collisionData.hit) {
                    return true;
                }
            }
        }
        return false;
    }

    // Handles what happens when the player collides with the enemy.
    handleCollisionEvent() {
        console.log("Player collided with the Enemy. Player is dead.");
        this.playerDestroyed = true; // Mark the player as "dead"
        this.gameEnv.gameControl.currentLevel.continue = false; // Restart the level
    }
}

export default Enemy;
;

Having the enemy be its own special case file is important because it allows for the enemy to be able to restart the game and have the player die. It being its own class allows it to have special consequences that affect the gameplay.

In this version, we have it so that the player dies and the game automatically resets after collision. There are no animations in this version–that’s for the next lesson.

Explanation:

This file is very similar to the NPC.js except in this case, it creates a way for something to happen when the player and enemy collide with each other.

For example, in the very beginning of the file, it checks if the player is destroyed (this.playerDestroyed = false) and we set it to false so that it can be changed to true later on in the code.

Then it goes to collisionChecks which simply checks if the enemy is colliding with the player. If the player is collided with the enemy then this.collisionData.hit returns true because the player and the enemy are colliding. If its true, a handleCollisionEvent occurs, which runs the following:

  • We used console.log to print a message after they collide
  • this.playerDestroyed = false is changed to this.playerDestroyed = true, what we were talking about in the beginning player should be ‘dead’
  • this.gameEnv.gameControl.currentLevel.continue = false; this part of the function terminates the game loop and stops the player from continuing to the next level.

Now, in order to make more specific functions for the creeper (or whatever enemy you have), we created another class extending from the enemy class. We named it ‘Creeper.js.’

Having a separate creeper class extending from the enemy class allows us to have even more specific functions for an enemy. This is helpful for when you have multiple enemies with different functions associated. It allows your game to be more nuanced in its story, the interactions, characters, etc.