A game of Snake written in JavaScript 🐍

preview_player
Показать описание
#JavaScript #snake #game

JavaScript snake game tutorial example explained
Рекомендации по теме
Комментарии
Автор

const gameBoard =
const ctx = gameBoard.getContext("2d");
const scoreText =
const resetBtn =
const gameWidth = gameBoard.width;
const gameHeight = gameBoard.height;
const boardBackground = "white";
const snakeColor = "lightgreen";
const snakeBorder = "black";
const foodColor = "red";
const unitSize = 25;
let running = false;
let xVelocity = unitSize;
let yVelocity = 0;
let foodX;
let foodY;
let score = 0;
let snake = [
{x:unitSize * 4, y:0},
{x:unitSize * 3, y:0},
{x:unitSize * 2, y:0},
{x:unitSize, y:0},
{x:0, y:0}
];

window.addEventListener("keydown", changeDirection);
resetBtn.addEventListener("click", resetGame);

gameStart();

function gameStart(){
running= true;
scoreText.textContent = score;
createFood();
drawFood();
nextTick();
};
function nextTick(){
if(running){
setTimeout(()=>{
clearBoard();
drawFood();
moveSnake();
drawSnake();
checkGameOver();
nextTick();
}, 75);
}
else{
displayGameOver();
}
};
function clearBoard(){
ctx.fillStyle = boardBackground;
ctx.fillRect(0, 0, gameWidth, gameHeight);
};
function createFood(){
function randomFood(min, max){
const randNum = Math.round((Math.random() * (max - min) + min) / unitSize) * unitSize;
return randNum;
}
foodX = randomFood(0, gameWidth - unitSize);
foodY = randomFood(0, gameWidth - unitSize);
};
function drawFood(){
ctx.fillStyle = foodColor;
ctx.fillRect(foodX, foodY, unitSize, unitSize);
};
function moveSnake(){
const head = {x: snake[0].x + xVelocity,
y: snake[0].y + yVelocity};

snake.unshift(head);
//if food is eaten
if(snake[0].x == foodX && snake[0].y == foodY){
score+=1;
scoreText.textContent = score;
createFood();
}
else{
snake.pop();
}
};
function drawSnake(){
ctx.fillStyle = snakeColor;
ctx.strokeStyle = snakeBorder;
snake.forEach(snakePart => {
ctx.fillRect(snakePart.x, snakePart.y, unitSize, unitSize);
ctx.strokeRect(snakePart.x, snakePart.y, unitSize, unitSize);
})
};
function changeDirection(event){
const keyPressed = event.keyCode;
const LEFT = 37;
const UP = 38;
const RIGHT = 39;
const DOWN = 40;

const goingUp = (yVelocity == -unitSize);
const goingDown = (yVelocity == unitSize);
const goingRight = (xVelocity == unitSize);
const goingLeft = (xVelocity == -unitSize);

switch(true){
case(keyPressed == LEFT && !goingRight):
xVelocity = -unitSize;
yVelocity = 0;
break;
case(keyPressed == UP && !goingDown):
xVelocity = 0;
yVelocity = -unitSize;
break;
case(keyPressed == RIGHT && !goingLeft):
xVelocity = unitSize;
yVelocity = 0;
break;
case(keyPressed == DOWN && !goingUp):
xVelocity = 0;
yVelocity = unitSize;
break;
}
};
function checkGameOver(){
switch(true){
case (snake[0].x < 0):
running = false;
break;
case (snake[0].x >= gameWidth):
running = false;
break;
case (snake[0].y < 0):
running = false;
break;
case (snake[0].y >= gameHeight):
running = false;
break;
}
for(let i = 1; i < snake.length; i+=1){
if(snake[i].x == snake[0].x && snake[i].y == snake[0].y){
running = false;
}
}
};
function displayGameOver(){
ctx.font = "50px MV Boli";
ctx.fillStyle = "black";
ctx.textAlign = "center";
ctx.fillText("GAME OVER!", gameWidth / 2, gameHeight / 2);
running = false;
};
function resetGame(){
score = 0;
xVelocity = unitSize;
yVelocity = 0;
snake = [
{x:unitSize * 4, y:0},
{x:unitSize * 3, y:0},
{x:unitSize * 2, y:0},
{x:unitSize, y:0},
{x:0, y:0}
];
gameStart();
};

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="gameContainer">
<canvas id="gameBoard" width="500" height="500"></canvas>
<div id="scoreText">0</div>
<button id="resetBtn">Reset</button>
</div>
<script src="index.js"></script>
</body>
</html>

#gameContainer{
text-align: center;
}
#gameBoard{
border: 3px solid;
}
#scoreText{
font-family: "Permanent Marker", cursive;
font-size: 100px;
}
#resetBtn{
font-family: "Permanent Marker", cursive;
font-size: 22px;
width: 100px;
height: 50px;
border: 4px solid;
border-radius: 15px;
cursor: pointer;
}

BroCodez
Автор

I like your style of programming. Super methodical, lay everything out then fill it in

noir
Автор

If you guys are facing the increasing speed issue on clicking the reset button:
What you can do is create a gobal variable for timeout and store setTimeout() in that variabe in the nextTick() function. Then in the reset function do this:
clearTimeout(*your variable name*)

mibrahim
Автор

Congratulations, you are a master, i am learning with your JS course, i am from Colombia, thank you for your help.

juandavidcastroarias
Автор

Thanks, Bro. You don't know how much you just helped me.

icemanho
Автор

if you guys are having velocity change when click restart button,

the solution its just delete de last, call function "*yourFunction()*".

in the example of this video its the last 'gameStart()' call .

vitordejesusferreira
Автор

I’m currently studying python js and c# ur videos make it way easier to understand

Kickthewall
Автор

Hey i have noticed a little mistake in the code. If you want to use other dimensions ( a smaller number for heigth ) for the board when it generates new food is going to be invisible. This is because in the createFood method you assign to foodY the value of the gameWidth also. In your case it doesnt matter because the heigth and width are the same.

alejandrogarzonbello
Автор

If youre having issues with the increased speed on resetBtn, do this: new global variable somewhere before game_start();

let time_out_id;

then add this to your function next_tick. You can see time_out_id = setTimeOut below

function next_tick(){
if (running){
time_out_id = setTimeout (()=>{
clear_board();
draw_food();
move_snake();
draw_snake();
check_game_over();
next_tick();
}, 100);
}
else {
display_game_over();
}
};

LASTLY

reset the setTimeout by using the id function we created in the reset function

function reset_game(){
score = 0;
x_velocity = unit_size;
y_velocity = 0;
snake = [
{x:unit_size * 4, y:0},
{x: unit_size * 3, y:0},
{x:unit_size * 2, y:0},
{x:unit_size, y:0},
{x: 0, y: 0}
];
clearTimeout(time_out_id)
game_start();
};

littlecurrybread
Автор

you can changing the code in the resetGame function to location.reload() and it's do the same thing

yasser
Автор

this is soo nice i used the same concepts to create mine in vue ... very nice video

maxwellmuhanda
Автор

Hey, I have found a bug both in mine and in your snake game.
When you move the direction, you immediately change it, but the snake moves only after a certain amount of time..
This means that the if statement to check if it is not going right when moving left, will work. But i could change direction to up or down and before the moveSnake function gets called, change it back to left, since direction is up or down, moving left is allowed. and you die because you collide with your body...
I have found two solutions, but they are not very good..
1) Move the snake immediately when the user changes direction. It's bad because you could go very fast by switching direction at all times.
2) Make the user change direction only after 200ms. It's bad because it makes the game very laggy and slow..
Thanks bro. Lots of love from Cyprus ( I'm in vacation now :) ) <3

hunin
Автор

hey bro good vid could u maybe do an in browser chess engine next? with pure html css & js. I'm building one ATM but it's difficult. the JS part in particular

dcode
Автор

Great videos in general, this one looks good too. I ran into an error that I cant debug so far on line 20 - ReferenceError: Cannot access 'snake' before initialization
at index.js:20:13, see below. any tips?

let snake = snake [

{x:unitSize *4, y:0},
{x:unitSize *3, y:0},
{x:unitSize *2, y:0},
{x:unitSize, y:0},
{x:0, y:0}
]

douglasl
Автор

That’s cool, but why not a global grid array that is rendered afterwards?

MeinDeutschkurs
Автор

thank you i also added another feature 😍😍😍

HRUstudent
Автор

Shouldn't this be: foodY = randomFood(0, gameHeight - unitSize); in the createFood function?

levyroth
Автор

The snake and the food dont apear on the screen. Can anyone help me please?

alingamerkid
Автор

At the createFood function, why did he minus the min from max and plus min? I can't figure it out, the min is 0. What is the purpose of using min?

huang
Автор

14:20
Can i ask why you used setTimeOut instead of setInterval ?

thereisnoname