0

I was writing a snake game in JavaScript but whenever I press any WASD keys it returns this error:

Uncaught TypeError: Cannot read properties of undefined (reading 'set_direction')
    at HTMLDocument.on_key_press (snake.js:66:28)

Here is my code, the constructor and draw functions work fine, the only problem is when pressing keys. The code continues running after the error is called but the snake does not change direction.:

class Snake {
    

    constructor() {

        this.position = [[2, 2], [1, 2]];
        this.direction = 2;

    }

    draw(){

        var canvas = document.getElementById("game_display_canvas");
        var ctx = canvas.getContext("2d");

        ctx.fillStyle = "#FFFFFF";

        for(let i = 0; i < this.position.length - 1; i++) {
            ctx.fillRect(this.position[i][0] * 10, this.position[i][1] * 10, 10, 10);
        }

    }

    move() {

        const directions = [[0, -1], [1, 0], [0, 1], [-1, 0]];
        let next_cell = this.position[this.position.length - 1];

        next_cell = [next_cell[0] + directions[this.direction][0], next_cell[1] + directions[this.direction][1]];
        this.position.push(next_cell);

    }

    set_direction(direction) {
        this.direction = direction;
    }
}

class GameManager {

    constructor(snake) {
        this.snake = snake;
    }

    on_key_press(event) {

        const W_KEY = 87;
        const A_KEY = 65;
        const S_KEY = 83;
        const D_KEY = 68;
    
        let keyPressed = event.keyCode;
    
        switch(keyPressed) {
            case W_KEY:
                this.snake.direction = 0;
                break;
            case A_KEY:
                this.snake.set_direction(3);
                break;
            case S_KEY:
                this.snake.set_direction(2);
                break;
            case D_KEY:
                this.snake.set_direction(1);
                break;
        }
    
    }
}

function main() {

    const snake = new Snake()

    const manager = new GameManager(snake);
    running = true;

    document.addEventListener("keydown", manager.on_key_press);

    gameLoop(manager, running)

}

function gameLoop(manager, running) {
    setTimeout(function onTick() {
        manager.snake.move();
        manager.snake.draw();

        if (running) {
            gameLoop(manager, running);
        }
    }, 100)
}

I tried both setting the attribute directly and using a set function within the snake class, but both cause the same error.

Edit: I can't figure out how to mark this as answered, but this answer from Titus what worked for me:

"Use something like this: document.addEventListener("keydown", manager.on_key_press.bind(manager)) – Titus"

  • you don't need `snake` in the `this.snake.set_direction` function call, you just need `this.set_direction` – Harrison Dec 12 '22 at 19:16
  • 2
    Use something like this: `document.addEventListener("keydown", manager.on_key_press.bind(manager))` – Titus Dec 12 '22 at 19:16
  • 2
    @Harrison that is not correct, that method is on the Snake class. – Pointy Dec 12 '22 at 19:19
  • The problem is that adding the method as an event handler the way you're doing it will lose track of the relationship between the GameManager instance and the method, so `this` inside the event handler will be wrong. You have to either bind the method to the instance, or else pass an anonymous function that calls the handler. – Pointy Dec 12 '22 at 19:20
  • 2
    `document.addEventListener("keydown", () => manager.on_key_press())` – epascarello Dec 12 '22 at 19:24
  • My bad @Pointy, I misread the code and thought that the functional call was inside the `snake` class – Harrison Dec 12 '22 at 19:28
  • @Titus this worked for me can you please post it as an answer so i can accept as answered – RipeContext Dec 12 '22 at 19:29

0 Answers0