0
\$\begingroup\$

I've wrapped everything inside a gamecontroller, so that everything is private, was this a good idea? that was my first time using oop and module pattern. also the code is in a good shape, or must be refactored?

const scoreDiv = document.querySelector(".score");
const canvas = document.querySelector("#canvas");
const ctx = canvas.getContext("2d");


canvas.width = 165;
canvas.height = 165;




// function that start and control the game
const gameController = (() => {
const scl = 5;
let snakePart = [];
let score = 0;
let gameSpeed = 10;
let snakeTailLenght = 0;

class Snake {
    constructor() {
        this.x = 50;
        this.y = 50;
        this.xVelocity = 0;
        this.yVelocity = 0;
    }


    move() {
        this.x += this.xVelocity * scl;
        this.y += this.yVelocity * scl;
    }
}

class SnakePart {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
}

class Apple {
    constructor() {
        this.x = 75;
        this.y = 60;
    }

    generateNewApple() {
        this.x = Math.floor(Math.random() * (canvas.width - 10));
        this.y = Math.floor(Math.random() * (canvas.height - 10));
        // generate only number that are multiple of five
        this.x = Math.round(this.x / 5) * 5;
        this.y = Math.round(this.y / 5) * 5;
    }
}

const head = new Snake();
const apple = new Apple();

// snake moviment
document.body.addEventListener("keydown", e => {
    switch (e.key) {
        case "ArrowUp":
            if (head.yVelocity === 1 || head.yVelocity === -1) {
                return;
            }
            head.xVelocity = 0;
            head.yVelocity = -1;
            break;

        case "ArrowDown":
            if (head.yVelocity === -1 || head.yVelocity === 1) {
                return;
            }
            head.xVelocity = 0;
            head.yVelocity = 1;
            break;

        case "ArrowLeft":
            if (head.xVelocity === 1 || head.xVelocity === -1) {
                return;
            }
            head.xVelocity = -1;
            head.yVelocity = 0;
            break;

        case "ArrowRight":
            if (head.xVelocity === 1 || head.xVelocity === -1) {
                return;
            }
            head.xVelocity = 1;
            head.yVelocity = 0;
            break;
    }
})


// loop function
function draw() {
    setTimeout(draw, 1000 / gameSpeed);
    checkCollision();       // game over
    appleCollision();
    drawSnake();
    head.move();
}

function checkCollision() {
    if (head.x < 0 || head.x > 160) {
        gameOver();
    }
    if (head.y < 0 || head.y > 160) {
        gameOver();
    }

    snakePart.forEach(element => {
        if (head.x === element.x && head.y === element.y) {
            gameOver();
        }
    })

    function gameOver() {
        score = 0;
        //scoreDiv.textContent = "Score: " + score;
        snakeTailLenght = 0;
        snakePart = [];
        head.x = 50;
        head.y = 50;
    }
}

function appleCollision() {
    if (head.x === apple.x && head.y === apple.y) {
        apple.generateNewApple();
        snakeTailLenght += 2;
        updateScore();
    }

    function updateScore() {
        score++;
        scoreDiv.textContent = "Score: " + score;
    }
}


function drawSnake() {
    ctx.fillStyle = "black";
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = "green";

    // draw new snake part
    for (let i = 0; i < snakePart.length; i++) {
        let part = snakePart[i];
        part.x = Math.round(part.x / 5) * 5;
        part.y = Math.round(part.y / 5) * 5;
        ctx.fillRect(part.x, part.y, 5, 5);
    }

    snakePart.push(new SnakePart(head.x, head.y));
    if (snakePart.length > snakeTailLenght) {
        snakePart.shift();
    }

    ctx.fillRect(head.x, head.y, 5, 5);
    ctx.fillStyle = "red";
    ctx.fillRect(apple.x, apple.y, 5, 5);
}


draw();
})();
\$\endgroup\$
3
  • 2
    \$\begingroup\$ The module pattern would suggest that the IIFE should wrap all declarations in the module, otherwise everything before const gameController is potentially leaking into globals. Also, indentation would help to make it clearer what the scope is. \$\endgroup\$ Commented May 30, 2022 at 11:44
  • \$\begingroup\$ So a game controller to make everything private was a good thing \$\endgroup\$ Commented May 30, 2022 at 14:35
  • 1
    \$\begingroup\$ It's a good idea. However, you should probably read up on Javasript module support, depending on your target, and on tools such as Webpack and Babel that can help you transpile modern code into backwards compatible formats. IIFE for encapsulation is still useful, but as a modularisation technique its becoming outdated. \$\endgroup\$ Commented May 30, 2022 at 16:51

0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.