5
\$\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>

200_success
146k22 gold badges190 silver badges479 bronze badges
asked May 29, 2019 at 18:54
\$\endgroup\$

1 Answer 1

1
\$\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.

answered Jun 1, 2019 at 20:52
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.