3
\$\begingroup\$

I'm trying to learn javascript (especially the OOP part) and made this simple game. I'm looking for advice and ways to improve my code.

  • Did I handle OOP well enough?
  • What's the best way to create a new object of a given class (object.assign, new Object() etc)? There are a lot of them
  • Which variables should be named using only uppercase letters
  • Did I make a mistake by defining variables like score globaly?
  • foodEaten() { score++; food = new Food(); } Is it a good way to override an object? How can I do this using "this" keyword?
  • Should I stick to window.requestAnimationFrame(gameLoop); or just use the function with given interval?

const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');

let score, food, player, board;

class Board {
    constructor(width, height, backgroundColor) {
        this.height = height;
        this.width = width;
        this.backgroundColor = backgroundColor;
    }
    drawBoard(score) {
        ctx.clearRect(0, 0, this.width, this.height) //clears board
        ctx.fillStyle = this.backgroundColor; //sets background color
        ctx.fillRect(0, 0, this.width, this.height); //background
        ctx.font = "30px Arial";
        ctx.fillStyle = "red";
        ctx.fillText(score, 10, 30);
    }
}

class Player {
    constructor(positionx, positiony, size, color, dx, dy) {
        this.x = positionx;
        this.y = positiony;
        this.size = size;
        this.color = color;
        this.dx = dx;
        this.dy = dy;

    }
    playerMove() {
        this.x += this.dx;
        this.y += this.dy;
    }
    drawPlayer() {
        ctx.strokeStyle = this.color;
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x, this.y, this.size, this.size);
        ctx.stroke();

    }
    checkCollision() {
        this.x + this.size > canvas.width || this.x < 0 ||
            this.y + this.size > canvas.height || this.y < 0 ?
            newGame() : null;
    }
    changeDirection(direction) { 

        switch (direction) {
            case 1: //up
                this.dx = 0;
                this.dy = -2;
                break;
            case 2: //left
                this.dx = -2;
                this.dy = 0;
                break;
            case 3: //down
                this.dx = 0;
                this.dy = 2;
                break;
            case 0: //right
                this.dx = 2;
                this.dy = 0;
                break;
        }
    }
    checkCollisionFood(food) { 
        (food.x > this.x - food.size && food.x < this.x + this.size) &&
            (food.y > this.y - food.size && food.y < this.y + this.size)
            ? food.foodEaten() : null
    }
}

class Food {
    constructor() {
        this.size = 20;
        this.x = Math.floor(Math.random() * (canvas.width - this.size + 1));
        this.y = Math.floor(Math.random() * (canvas.height - this.size + 1));
        this.color = "red";
    }
    drawFood() {
        ctx.strokeStyle = this.color;
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x, this.y, this.size, this.size);
        ctx.stroke();
    }
    foodEaten() {
        score++;
        food = new Food();
    }
}

function gameLoop() {
    board.drawBoard(score);
    player.drawPlayer();
    player.playerMove();
    player.checkCollision();
    player.checkCollisionFood(food);
    food.drawFood();
    window.requestAnimationFrame(gameLoop);
}

newGame();
window.requestAnimationFrame(gameLoop);

function newGame() {
    score = 0;
    food = new Food();
    player = new Player(40, 40, 40, "blue", 0, 0);
    board = new Board(c.width, c.height, "green");
}

document.addEventListener('keydown', (event) => {
    switch (event.keyCode) {
        case 87:  //"w" key
            player.changeDirection(1);
            break;
        case 83:  //"s" key
            player.changeDirection(3);
            break;
        case 68:  //"d" key
            player.changeDirection(0);
            break;
        case 65:  //"a" key
            player.changeDirection(2);
            break;
        default:
            break;
    }

});
<!DOCTYPE html>
<html>

<head>
    <title>canvas</title>
    <link rel="stylesheet" type="text/css" href="style.css">
</head>

<body>
    <canvas id="c" width="300px" height="400px">

    
</body>
<script src="main.js"></script>
</html>

\$\endgroup\$
0
\$\begingroup\$

Thanks for the specific questions. It really helps guide feedback.

Did I handle OOP well enough?

This seems pretty good, although a little more thinking about the "responsibilities" of a class will help.

What's the best way to create a new object of a given class (object.assign, new Object() etc)? There are a lot of them

new Foo() is the standard way.

Which variables should be named using only uppercase letters

Usually just constants, which include class names.

Did I make a mistake by defining variables like score globaly?

Yes, generally it's good to avoid globals.

foodEaten() { ... Is it a good way to override an object? How can I do this using "this" keyword?

You need to step back and look at the design a little bit. Some fn/object/class should be responsible for keeping track of the food, and therefore it would "own" the food variable (as this.food). It would be responsible for creating the original food and replenishing as needed after foodEaten is called. You can sometimes figure this out by passing the variables into where they are needed until you get to the code that can simply define a local variable... and sometimes it takes a little more refactoring.

Should I stick to window.requestAnimationFrame(gameLoop); or just use the function with given interval?

These are basically the same, and probably not worth fretting about. There does probably need some sort of event loop that has locally scoped variables for the game and perhaps food... that's how you would refactor out the global variables.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.