Skip to content

Commit

Permalink
finished base game logic; added score counter;
Browse files Browse the repository at this point in the history
  • Loading branch information
FairlyTales committed Apr 28, 2021
1 parent 290e808 commit debac8b
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 45 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/.idea
14 changes: 14 additions & 0 deletions js/elem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export default class Elem {
constructor(matrix, cords) {
this.matrix = matrix;
this.cords = cords;
this.value = '';
}

show() {
// assign value to the cell for each set of x-y coordinates
for(let cord of this.cords) {
this.matrix.setCell(cord[0], cord[1], this.value);
}
}
}
8 changes: 8 additions & 0 deletions js/fruit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import Elem from './elem.js'

export default class Fruit extends Elem {
constructor(matrix, cords) {
super(matrix, cords);
this.value = 'fruit';
}
}
25 changes: 23 additions & 2 deletions js/main.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import Fruit from './fruit.js';
import Matrix from './matrix.js';
import Snake from './snake.js';
import Utility from './random.js'

window.onload = function (e) {
let field = document.querySelector('.fields');
Expand All @@ -11,22 +13,41 @@ window.onload = function (e) {
cellSize: 40
}

// snake starting position
const snakeStartPosition = [[10, 5], [9, 5]];

// create gameboard(matrix) and snake objects
let matrix = new Matrix(field, boardDimensions);
let snake = new Snake(matrix, 5, 1, 'right');
let snake = new Snake(matrix, snakeStartPosition, 'right');

// create gameboard and snake on the page
matrix.create();
snake.show();
snake.initInputListener();

// create first fruit
(new Fruit(matrix, Utility.generateFruit(matrix, snake))).show();

// game score
let score = 0;

// game loop
let gameLoop = setInterval(() => {
if(!snake.snekDead) {
snake.move(snake.direction);
if(snake.ateFruit) {
score++;
snake.ateFruit = false;

//todo: add walls to .fruit()
(new Fruit(matrix, Utility.generateFruit(matrix, snake))).show();
}

snake.move();
} else {
console.log('snek is dead');
console.log(`your score is: ${score}`);
clearInterval(gameLoop);
//todo: add overlay and score screen with restart button
}
}, 500);

Expand Down
17 changes: 17 additions & 0 deletions js/random.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export default class Utility {
static generateFruit(matrix, snake, walls) {
let position = [];

do {
position[0] = Math.floor(Math.random() * matrix.boardDimensions.x);
position[1] = Math.floor(Math.random() * matrix.boardDimensions.y);
} while (matrix.getCell(position[0], position[1]) !== '')

return [position];
}

//todo: finish the wall and add it to the main.js
static generateWall(matrix) {

}
}
111 changes: 68 additions & 43 deletions js/snake.js
Original file line number Diff line number Diff line change
@@ -1,98 +1,123 @@
export default class Snake {
import Elem from './elem.js'

constructor(matrix, x, y, direction) {
this.matrix = matrix;
this.x = x;
this.y = y;
this.direction = direction;
export default class Snake extends Elem {

constructor(matrix, coords, direction) {
super(matrix, coords);
this.value = 'snake';
this.direction = direction;
this.newDirection = direction;
this.snekDead = false;
}

show() {
this.matrix.setCell(this.x, this.y, 'snake');
this.ateFruit = false;
}

move(direction) {
// save current snake position
let lastCoords = {
x: this.x,
y: this.y
}
move() {
// update the direction to the last inputed by player
this.direction = this.newDirection;

switch(direction) {
// make a copy of a snake head coordinates
let snakeHead = Array.from(this.cords[0]); // array copy, not a reference!

// change snake head coordinates
switch(this.direction) {
case 'right':
this.x++;
snakeHead[0]++;
break;

case 'left':
this.x--;
snakeHead[0]--;
break;

case 'up':
this.y--;
snakeHead[1]--;
break;

case 'down':
this.y++;
snakeHead[1]++;
break;
}

if (this._snekDeadCheck()) {
// check if the game is over
if (this._snekDeadCheck(snakeHead)) {
this.snekDead = true;
return;
}

// remove the last cell of the snake (in the array, not on the board)
// in order to move the whole snake forward
let tail = this.cords.pop();

// remove snake from current cell
this.matrix.setCell(lastCoords.x, lastCoords.y, '');
// if snake ate the fruit -> extend the snake
if (this._isAteFruit(snakeHead)) {
this.ateFruit = true;
this._extendSnake();
}

// "move" (assign) snake to the next cell
this.matrix.setCell(this.x, this.y, 'snake');
// remove last snake cell from the board
this.matrix.setCell(tail[0], tail[1], '');


// add snakeHead (with the updated coordinates) to the start of the
// snake array, basically moving the head forward (in the array, not on the board)
this.cords.unshift(snakeHead);

// add this new head to the gameboard (displaying it)
this.matrix.setCell(snakeHead[0], snakeHead[1], 'snake');
}

initInputListener() {
let lastDirection = null;

window.addEventListener('keydown', (e) => {
switch(e.key) {
case 'w':
case 'W':
case 'ц':
case 'Ц':
case 'ArrowUp':
if (lastDirection === 'down') break;
this.direction = 'up';
lastDirection = 'up';
if (this.direction === 'down') break;
this.newDirection = 'up';
break;

case 'a':
case 'A':
case 'ф':
case 'Ф':
case 'ArrowLeft':
if (lastDirection === 'right') break;
this.direction = 'left';
lastDirection = 'left';
if (this.direction === 'right') break;
this.newDirection = 'left';
break;

case 's':
case 'S':
case 'ы':
case 'Ы':
case 'ArrowDown':
if (lastDirection === 'up') break;
this.direction = 'down';
lastDirection = 'down';
if (this.direction === 'up') break;
this.newDirection = 'down';
break;

case 'd':
case 'D':
case 'в':
case 'В':
case 'ArrowRight':
if (lastDirection === 'left') break;
this.direction = 'right';
lastDirection = 'right';
if (this.direction === 'left') break;
this.newDirection = 'right';
break;
}
})
}

_snekDeadCheck() {
return this.x < 1 || this.x > this.matrix.boardDimensions.x || this.y < 1 || this.y > this.matrix.boardDimensions.y;
_snekDeadCheck(snakeHead) {
// returns true if snake head go over the game board borders or rams into wall or itself
return snakeHead[0] < 1 || snakeHead[0] > this.matrix.boardDimensions.x || snakeHead[1] < 1 || snakeHead[1] > this.matrix.boardDimensions.y || this.matrix.getCell(snakeHead[0], snakeHead[1]) === 'wall' || this.matrix.getCell(snakeHead[0], snakeHead[1]) === 'snake';
}

_isAteFruit(snakeHead) {
return this.matrix.getCell(snakeHead[0], snakeHead[1]) === 'fruit';
}

_extendSnake() {
// add last element of the snake to the end of the snake array
// extending it by 1 element
this.cords.push(this.cords[this.cords.length - 1]);
}
}
8 changes: 8 additions & 0 deletions js/wall.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import Elem from './elem.js'

export default class Wall extends Elem {
constructor(matrix, cords) {
super(matrix, cords);
this.value = 'wall';
}
}
8 changes: 8 additions & 0 deletions style.css
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,13 @@ html {
}

[data-game="snake"] {
background-color: greenyellow;
}

[data-game="snake--head"] {
background-color: green;
}

[data-game="wall"] {
background-color: blue;
}

0 comments on commit debac8b

Please sign in to comment.