Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Basic Snake HTML Game

Basic Snake HTML Game

Snake is a fun game to make as it doesn't require a lot of code (less than 100 lines with all comments removed). This is a basic implementation of the snake game, but it's missing a few things intentionally and they're left as further exploration for the reader.

image

Further Exploration

  • Score
    • When the snake eats an apple, the score should increase by one. Use context.fillText() to display the score to the screen
  • Mobile and touchscreen support
  • Better apple spawning
    • Currently the apple spawns in any random grid in the game, even if the snake is already on that spot. Improve it so it only spanws in empty grid locations

Important note: I will answer questions about the code but will not add more features or answer questions about adding more features. This series is meant to give a basic outline of the game but nothing more.

License

(CC0 1.0 Universal) You're free to use this game and code in any project, personal or commercial. There's no need to ask permission before using these. Giving attribution is not required, but appreciated.

Other Basic Games

Support

Basic HTML Games are made possible by users like you. When you become a Patron, you get access to behind the scenes development logs, the ability to vote on which games I work on next, and early access to the next Basic HTML Game.

Top Patrons

  • Innkeeper Games
  • Karar Al-Remahy
<!DOCTYPE html>
<html>
<head>
<title></title>
<style>
html, body {
height: 100%;
margin: 0;
}
body {
background: black;
display: flex;
align-items: center;
justify-content: center;
}
canvas {
border: 1px solid white;
}
</style>
</head>
<body>
<canvas width="400" height="400" id="game"></canvas>
<script>
var canvas = document.getElementById('game');
var context = canvas.getContext('2d');
var grid = 16;
var count = 0;
var snake = {
x: 160,
y: 160,
// snake velocity. moves one grid length every frame in either the x or y direction
dx: grid,
dy: 0,
// keep track of all grids the snake body occupies
cells: [],
// length of the snake. grows when eating an apple
maxCells: 4
};
var apple = {
x: 320,
y: 320
};
// get random whole numbers in a specific range
// @see https://stackoverflow.com/a/1527820/2124254
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}
// game loop
function loop() {
requestAnimationFrame(loop);
// slow game loop to 15 fps instead of 60 (60/15 = 4)
if (++count < 4) {
return;
}
count = 0;
context.clearRect(0,0,canvas.width,canvas.height);
// move snake by it's velocity
snake.x += snake.dx;
snake.y += snake.dy;
// wrap snake position horizontally on edge of screen
if (snake.x < 0) {
snake.x = canvas.width - grid;
}
else if (snake.x >= canvas.width) {
snake.x = 0;
}
// wrap snake position vertically on edge of screen
if (snake.y < 0) {
snake.y = canvas.height - grid;
}
else if (snake.y >= canvas.height) {
snake.y = 0;
}
// keep track of where snake has been. front of the array is always the head
snake.cells.unshift({x: snake.x, y: snake.y});
// remove cells as we move away from them
if (snake.cells.length > snake.maxCells) {
snake.cells.pop();
}
// draw apple
context.fillStyle = 'red';
context.fillRect(apple.x, apple.y, grid-1, grid-1);
// draw snake one cell at a time
context.fillStyle = 'green';
snake.cells.forEach(function(cell, index) {
// drawing 1 px smaller than the grid creates a grid effect in the snake body so you can see how long it is
context.fillRect(cell.x, cell.y, grid-1, grid-1);
// snake ate apple
if (cell.x === apple.x && cell.y === apple.y) {
snake.maxCells++;
// canvas is 400x400 which is 25x25 grids
apple.x = getRandomInt(0, 25) * grid;
apple.y = getRandomInt(0, 25) * grid;
}
// check collision with all cells after this one (modified bubble sort)
for (var i = index + 1; i < snake.cells.length; i++) {
// snake occupies same space as a body part. reset game
if (cell.x === snake.cells[i].x && cell.y === snake.cells[i].y) {
snake.x = 160;
snake.y = 160;
snake.cells = [];
snake.maxCells = 4;
snake.dx = grid;
snake.dy = 0;
apple.x = getRandomInt(0, 25) * grid;
apple.y = getRandomInt(0, 25) * grid;
}
}
});
}
// listen to keyboard events to move the snake
document.addEventListener('keydown', function(e) {
// prevent snake from backtracking on itself by checking that it's
// not already moving on the same axis (pressing left while moving
// left won't do anything, and pressing right while moving left
// shouldn't let you collide with your own body)
// left arrow key
if (e.which === 37 && snake.dx === 0) {
snake.dx = -grid;
snake.dy = 0;
}
// up arrow key
else if (e.which === 38 && snake.dy === 0) {
snake.dy = -grid;
snake.dx = 0;
}
// right arrow key
else if (e.which === 39 && snake.dx === 0) {
snake.dx = grid;
snake.dy = 0;
}
// down arrow key
else if (e.which === 40 && snake.dy === 0) {
snake.dy = grid;
snake.dx = 0;
}
});
// start the game
requestAnimationFrame(loop);
</script>
</body>
</html>
@iammanmohit

This comment has been minimized.

Copy link

@iammanmohit iammanmohit commented Mar 18, 2018

Wow!!! It's GREAT!!!

@GandalfTheGinger

This comment has been minimized.

Copy link

@GandalfTheGinger GandalfTheGinger commented Mar 23, 2018

There is a problem when I hit the wall I don't die so could you fix that in some way and could you tell me how you fixed cause i'm curious

@Spartacusboy

This comment has been minimized.

Copy link

@Spartacusboy Spartacusboy commented Mar 26, 2018

GandalfTheGinger it's not a bug. That's how the original game was, I'm pretty sure.

@Mr-Alpheous

This comment has been minimized.

Copy link

@Mr-Alpheous Mr-Alpheous commented Apr 4, 2018

woooow wow it nice but score is missing

@Tigermagooster

This comment has been minimized.

Copy link

@Tigermagooster Tigermagooster commented Apr 6, 2018

How to control?

@ghost

This comment has been minimized.

Copy link

@ghost ghost commented Apr 14, 2018

Could you add a way to control it on mobile?

@andrewreed549

This comment has been minimized.

Copy link

@andrewreed549 andrewreed549 commented May 9, 2018

heres the mobile code

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
  <title>snake</title>
  <style>
 
  body {
    background:blue;
        }
  canvas {
    border:3px solid;
    background:#efe;
  }
  
  .control {
  position:relative;
  border-radius:10px;
  width:70px;
  height:30px;
  bottom:-30px;
  }
  
  button {
  outline:0;
  }
  </style>
</head>
<body onselectstart="return false" onpaste="return false;" onCopy="return false" onCut="return false" onDrag="return false" onDrop="return false" oncontextmenu="return false">

<canvas width="340" height="340" id="game"></canvas>
<script>
var canvas = document.getElementById('game');
var context = canvas.getContext('2d');
var grid = 10;
var colors = "rgb("
    +Math.floor(Math.random() * 226)
    +","
    +Math.floor(Math.random() * 226)
    +","
    +Math.floor(Math.random() * 226)
    +")";

var snake = {
  x: 160,
  y: 160,
  dx: grid,
  dy: 0,
  cells: [],
  maxCells: 4
};
var count = 0;
var apple = {
  x: 320,
  y: 320
};
function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min)) + min;
}

function loop() {
  requestAnimationFrame(loop);
 
  if (++count < 7) {
    return;
  }
  count = 0;
  context.clearRect(0,0,canvas.width,canvas.height);
  snake.x += snake.dx;
  snake.y += snake.dy;
  // wrap snake position on edge of screen
  if (snake.x < 0) {
    snake.x = canvas.width - grid;
  }
  else if (snake.x >= canvas.width) {
    snake.x = 0;
  }
  if (snake.y < 0) {
    snake.y = canvas.height - grid;
  }
  else if (snake.y >= canvas.height) {
    snake.y = 0;
  }
 
  snake.cells.unshift({x: snake.x, y: snake.y});
  
  if (snake.cells.length > snake.maxCells) {
    snake.cells.pop();
  }

  context.fillStyle = 'green';
  context.fillRect(apple.x, apple.y, grid-1, grid-1)

  context.fillStyle = colors;
  snake.cells.forEach(function(cell, index) {
    context.fillRect(cell.x, cell.y, grid-1, grid-1);
  
    if (cell.x === apple.x && cell.y === apple.y) {
      snake.maxCells++;

      apple.x = getRandomInt(0, 30) * grid;
      apple.y = getRandomInt(0, 30) * grid;
    }


    for (var i = index + 1; i < snake.cells.length; i++) {
  
  
      if (cell.x === snake.cells[i].x && cell.y === snake.cells[i].y) {
        alert("you lose, your score is")
        alert(snake.maxCells)
        colors = "rgb("
    +Math.floor(Math.random() * 226)
    +","
    +Math.floor(Math.random() * 226)
    +","
    +Math.floor(Math.random() * 226)
    +")";
        snake.x = 160;
        snake.y = 160;
        snake.cells = [];
        snake.maxCells = 4;
        snake.dx = grid;
        snake.dy = 0;
        apple.x = getRandomInt(0, 25) * grid;
        apple.y = getRandomInt(0, 25) * grid;
      }
    }
  });
}

  function left(){
  if (snake.dx === 0) {
    snake.dx = -grid;
    snake.dy = 0;
  }
  }
  function up(){
  if ( snake.dy === 0) {
    snake.dy = -grid;
    snake.dx = 0;
  }
  }
  function right(){
  if ( snake.dx === 0) {
    snake.dx = grid;
    snake.dy = 0;
  }
  }
  function down(){
  if (snake.dy === 0) {
    snake.dy = grid;
    snake.dx = 0;
  }
  }
  function hack(){
  if (snake.maxCells){
  snake.maxCells++;
  }
  }
  function hackd(){
  if (snake.maxCells){
  colors = "rgb("
    +Math.floor(Math.random() * 226)
    +","
    +Math.floor(Math.random() * 226)
    +","
    +Math.floor(Math.random() * 226)
    +")";
  }
  }
  function hacku(){
  if (snake.maxCells){
  apple.x = getRandomInt(0, 25) * grid;
  apple.y = getRandomInt(0, 25) * grid;
  }
  }
document.addEventListener('keydown', function(e) {
  // prevent snake from backtracking on itself
  if (e.which === 37 && snake.dx === 0) {
    snake.dx = -grid;
    snake.dy = 0;
  }
  else if (e.which === 38 && snake.dy === 0) {
    snake.dy = -grid;
    snake.dx = 0;
  }
  else if (e.which === 39 && snake.dx === 0) {
    snake.dx = grid;
    snake.dy = 0;
  }
  else if (e.which === 40 && snake.dy === 0) {
    snake.dy = grid;
    snake.dx = 0;
  }
requestAnimationFrame(loop);
</script>
<svg width="340px" height="200px">    
    <circle cx="130px" Cy="80px" r="30" onclick="left()">
    </circle>
    <circle cx="175px" Cy="30px" r="30" onclick="up()">
    </circle>
    <circle cx="175px" Cy="125px" r="30" onclick="down()">
    </circle>
    <circle cx="220px" Cy="80px" r="30" onclick="right()">
    </circle>
    <circle cx="300px" Cy="75px" r="40" onclick="hack()">
    </circle>
    <circle cx=" 45px" Cy="75px" r="40" onclick="hackd()">
    </circle>
  <circle cx=" 0px" Cy="0px" r="40" onclick="hacku()">
    </circle>
</svg>
</body>
</html>
@GandalfTheGinger

This comment has been minimized.

Copy link

@GandalfTheGinger GandalfTheGinger commented May 14, 2018

could you please add the scoring

@HenryAkaya

This comment has been minimized.

Copy link

@HenryAkaya HenryAkaya commented May 24, 2018

heres the mobile code

<title>snake</title> <style> body { background:blue; } canvas { border:3px solid; background:#efe; }

.control {
position:relative;
border-radius:10px;
width:70px;
height:30px;
bottom:-30px;
}

button {
outline:0;
}
</style>

<script> var canvas = document.getElementById('game'); var context = canvas.getContext('2d'); var grid = 10; var colors = "rgb(" +Math.floor(Math.random() * 226) +"," +Math.floor(Math.random() * 226) +"," +Math.floor(Math.random() * 226) +")"; var snake = { x: 160, y: 160, dx: grid, dy: 0, cells: [], maxCells: 4 }; var count = 0; var apple = { x: 320, y: 320 }; function getRandomInt(min, max) { return Math.floor(Math.random() * (max - min)) + min; } function loop() { requestAnimationFrame(loop); if (++count < 7) { return; } count = 0; context.clearRect(0,0,canvas.width,canvas.height); snake.x += snake.dx; snake.y += snake.dy; // wrap snake position on edge of screen if (snake.x < 0) { snake.x = canvas.width - grid; } else if (snake.x >= canvas.width) { snake.x = 0; } if (snake.y < 0) { snake.y = canvas.height - grid; } else if (snake.y >= canvas.height) { snake.y = 0; } snake.cells.unshift({x: snake.x, y: snake.y}); if (snake.cells.length > snake.maxCells) { snake.cells.pop(); } context.fillStyle = 'green'; context.fillRect(apple.x, apple.y, grid-1, grid-1) context.fillStyle = colors; snake.cells.forEach(function(cell, index) { context.fillRect(cell.x, cell.y, grid-1, grid-1); if (cell.x === apple.x && cell.y === apple.y) { snake.maxCells++; apple.x = getRandomInt(0, 30) * grid; apple.y = getRandomInt(0, 30) * grid; } for (var i = index + 1; i < snake.cells.length; i++) { if (cell.x === snake.cells[i].x && cell.y === snake.cells[i].y) { alert("you lose, your score is") alert(snake.maxCells) colors = "rgb(" +Math.floor(Math.random() * 226) +"," +Math.floor(Math.random() * 226) +"," +Math.floor(Math.random() * 226) +")"; snake.x = 160; snake.y = 160; snake.cells = []; snake.maxCells = 4; snake.dx = grid; snake.dy = 0; apple.x = getRandomInt(0, 25) * grid; apple.y = getRandomInt(0, 25) * grid; } } }); } function left(){ if (snake.dx === 0) { snake.dx = -grid; snake.dy = 0; } } function up(){ if ( snake.dy === 0) { snake.dy = -grid; snake.dx = 0; } } function right(){ if ( snake.dx === 0) { snake.dx = grid; snake.dy = 0; } } function down(){ if (snake.dy === 0) { snake.dy = grid; snake.dx = 0; } } function hack(){ if (snake.maxCells){ snake.maxCells++; } } function hackd(){ if (snake.maxCells){ colors = "rgb(" +Math.floor(Math.random() * 226) +"," +Math.floor(Math.random() * 226) +"," +Math.floor(Math.random() * 226) +")"; } } function hacku(){ if (snake.maxCells){ apple.x = getRandomInt(0, 25) * grid; apple.y = getRandomInt(0, 25) * grid; } } document.addEventListener('keydown', function(e) { // prevent snake from backtracking on itself if (e.which === 37 && snake.dx === 0) { snake.dx = -grid; snake.dy = 0; } else if (e.which === 38 && snake.dy === 0) { snake.dy = -grid; snake.dx = 0; } else if (e.which === 39 && snake.dx === 0) { snake.dx = grid; snake.dy = 0; } else if (e.which === 40 && snake.dy === 0) { snake.dy = grid; snake.dx = 0; } requestAnimationFrame(loop); </script>

@andrewreed549
This code for mobile did not work.

@dehuachen

This comment has been minimized.

Copy link

@dehuachen dehuachen commented May 25, 2018

@HenryAkaya @SawyerBx
Here is a mobile version:

<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title></title>
  <style>
  html, body {
    height: 100%;
    margin: 0;
  }

  body {
    background: black;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow-y: hidden;
  }
  canvas {
    border: 1px solid white;
  }
  </style>
</head>
<body>
<canvas width="400" height="400" id="game"></canvas>
<script>
var canvas = document.getElementById('game');
var context = canvas.getContext('2d');

var grid = 16;
var snake = {
  x: 160,
  y: 160,
  dx: grid,
  dy: 0,
  cells: [],
  maxCells: 4
};
var count = 0;
var apple = {
  x: 320,
  y: 320
};

function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min)) + min;
}

// game loop
function loop() {
  requestAnimationFrame(loop);

  // slow game loop to 15 fps instead of 60 - 60/15 = 4
  if (++count < 4) {
    return;
  }

  count = 0;
  context.clearRect(0,0,canvas.width,canvas.height);

  snake.x += snake.dx;
  snake.y += snake.dy;

  // wrap snake position on edge of screen
  if (snake.x < 0) {
    snake.x = canvas.width - grid;
  }
  else if (snake.x >= canvas.width) {
    snake.x = 0;
  }

  if (snake.y < 0) {
    snake.y = canvas.height - grid;
  }
  else if (snake.y >= canvas.height) {
    snake.y = 0;
  }

  // keep track of where snake has been. front of the array is always the head
  snake.cells.unshift({x: snake.x, y: snake.y});

  // remove cells as we move away from them
  if (snake.cells.length > snake.maxCells) {
    snake.cells.pop();
  }

  // draw apple
  context.fillStyle = 'red';
  context.fillRect(apple.x, apple.y, grid-1, grid-1);

  // draw snake
  context.fillStyle = 'green';
  snake.cells.forEach(function(cell, index) {
    context.fillRect(cell.x, cell.y, grid-1, grid-1);

    // snake ate apple
    if (cell.x === apple.x && cell.y === apple.y) {
      snake.maxCells++;

      apple.x = getRandomInt(0, 25) * grid;
      apple.y = getRandomInt(0, 25) * grid;
    }

    // check collision with all cells after this one (modified bubble sort)
    for (var i = index + 1; i < snake.cells.length; i++) {
      
      // collision. reset game
      if (cell.x === snake.cells[i].x && cell.y === snake.cells[i].y) {
        snake.x = 160;
        snake.y = 160;
        snake.cells = [];
        snake.maxCells = 4;
        snake.dx = grid;
        snake.dy = 0;

        apple.x = getRandomInt(0, 25) * grid;
        apple.y = getRandomInt(0, 25) * grid;
      }
    }
  });
}

var allowedTime = 200;
var startX = 0;
var startY = 0;

document.addEventListener('touchstart', function(e){
    var touch = e.changedTouches[0]
    startX = touch.pageX
    startY = touch.pageY
    startTime = new Date().getTime()
    e.preventDefault()
}, false)

document.addEventListener('touchmove', function(e){
    e.preventDefault()
}, false)

document.addEventListener('touchend', function(e){
    var touch = e.changedTouches[0]
    distX = touch.pageX - startX
    distY = touch.pageY - startY

    if (Math.abs(distX) > Math.abs(distY)) {
      if (distX > 0 && snake.dx === 0) {
        snake.dx = grid;
        snake.dy = 0;
      }
      else if (distX < 0 && snake.dx === 0) {
        snake.dx = -grid;
        snake.dy = 0;
      }
    } else {
      if (distY > 0 && snake.dy === 0) {
        snake.dy = grid;
        snake.dx = 0;
      }
      else if (distY < 0 && snake.dy === 0) {
        snake.dy = -grid;
        snake.dx = 0;
      }
    }
    e.preventDefault();

}, false)

document.addEventListener('keydown', function(e) {
  // prevent snake from backtracking on itself
  if (e.which === 37 && snake.dx === 0) {
    snake.dx = -grid;
    snake.dy = 0;
  }
  else if (e.which === 38 && snake.dy === 0) {
    snake.dy = -grid;
    snake.dx = 0;
  }
  else if (e.which === 39 && snake.dx === 0) {
    snake.dx = grid;
    snake.dy = 0;
  }
  else if (e.which === 40 && snake.dy === 0) {
    snake.dy = grid;
    snake.dx = 0;
  }
});

requestAnimationFrame(loop);
</script>
</body>
</html>
@Bluwinters

This comment has been minimized.

Copy link

@Bluwinters Bluwinters commented Jun 5, 2018

How does the computer know the input for the snake movement what line of code was that

@ericsondevan

This comment has been minimized.

Copy link

@ericsondevan ericsondevan commented Jun 30, 2018

it is nice but i need help on how to add score and pause button.

@JesseBS2

This comment has been minimized.

Copy link

@JesseBS2 JesseBS2 commented Sep 7, 2018

@Bluwinters

It’s practically the last line of JavaScript code, right above the final requestAnimationFrame(loop)
key up:
`document.addEventListener('keydown', function(e){

if(e.which == 37){
snake.dy= -grid;
snake.dx = 0;
}

})`

that code is all correct(Although 37 Might not be the Up arrow, It could also be Left, Right or Down)

@subeshb1

This comment has been minimized.

Copy link

@subeshb1 subeshb1 commented Oct 4, 2018

@Jackolanturn0

This comment has been minimized.

Copy link

@Jackolanturn0 Jackolanturn0 commented Oct 23, 2018

I am a beginner at coding, and lots of times I base my code off of this code. It's awesome!

@Smt1195

This comment has been minimized.

Copy link

@Smt1195 Smt1195 commented Nov 9, 2018

woooow wow it nice but score is missing

@Smt1195

This comment has been minimized.

Copy link

@Smt1195 Smt1195 commented Nov 9, 2018

Copy this and enjoy. It has score an highscore added to it

<!DOCTYPE html>
<html>
<head>
  <title></title>
  <style>
  html, body {
    height: 100%;
    margin: 0;
  }
  body {
    background: black;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  canvas {
    border: 1px solid white;
  }
  #p1
  {
    color:red;
	position:absolute;
	left:100px;
	top:10px;
  }
    #p2
  {
    color:red;
	position:absolute;
	left:100px;
	top:30px;
  }
  #score
  {
    color:yellow;
    position:absolute;
	left:155px;
	top:10px;
  }
  #high
  {
    color:yellow;
    position:absolute;
	left:195px;
	top:30px;
  }
  </style>
</head>
<body>
<p id="p1">SCORE:</p>
<p id="p2">HIGHSCORE:</p>
<p id="score"></p>
<p id="high"></p>
<canvas width="400" height="400" id="game"></canvas>
<script>
var canvas = document.getElementById('game');
var context = canvas.getContext('2d');
var grid = 16;
var count = 0;
var score=0;
var max=0;  

var snake = {
  x: 160,
  y: 160,
  
  // snake velocity. moves one grid length every frame in either the x or y direction
  dx: grid,
  dy: 0,
  
  // keep track of all grids the snake body occupies
  cells: [],
  
  // length of the snake. grows when eating an apple
  maxCells: 4
};
var apple = {
  x: 320,
  y: 320
};

// get random whole numbers in a specific range
// @see https://stackoverflow.com/a/1527820/2124254
function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min)) + min;
}
// game loop
function loop() {
  requestAnimationFrame(loop);
  // slow game loop to 15 fps instead of 60 (60/15 = 4)
  if (++count < 4) {
    return;
  }
  count = 0;
  context.clearRect(0,0,canvas.width,canvas.height);
  // move snake by it's velocity
  snake.x += snake.dx;
  snake.y += snake.dy;
  // wrap snake position horizontally on edge of screen
  if (snake.x < 0) {
    snake.x = canvas.width - grid;
  }
  else if (snake.x >= canvas.width) {
    snake.x = 0;
  }
  
  // wrap snake position vertically on edge of screen
  if (snake.y < 0) {
    snake.y = canvas.height - grid;
  }
  else if (snake.y >= canvas.height) {
    snake.y = 0;
  }
  // keep track of where snake has been. front of the array is always the head
  snake.cells.unshift({x: snake.x, y: snake.y});
  // remove cells as we move away from them
  if (snake.cells.length > snake.maxCells) {
    snake.cells.pop();
  }
  // draw apple
  context.fillStyle = 'red';
  context.fillRect(apple.x, apple.y, grid-1, grid-1);
  // draw snake one cell at a time
  context.fillStyle = 'green';
  snake.cells.forEach(function(cell, index) {
    
    // drawing 1 px smaller than the grid creates a grid effect in the snake body so you can see how long it is
    context.fillRect(cell.x, cell.y, grid-1, grid-1);  
    // snake ate apple
    if (cell.x === apple.x && cell.y === apple.y) {
      snake.maxCells++;
	  score+=10;
	  //max=score;
	  document.getElementById('score').innerHTML=score;
	
      // canvas is 400x400 which is 25x25 grids 
      apple.x = getRandomInt(0, 25) * grid;
      apple.y = getRandomInt(0, 25) * grid;
    }
    // check collision with all cells after this one (modified bubble sort)
    for (var i = index + 1; i < snake.cells.length; i++)
	{
      
      // snake occupies same space as a body part. reset game
      if (cell.x === snake.cells[i].x && cell.y === snake.cells[i].y) 
	 { 
	 
	    if(score>max)
	    {
	     max=score;
	    }
    	snake.x = 160;
        snake.y = 160;
        snake.cells = [];
        snake.maxCells = 4;
        snake.dx = grid;
        snake.dy = 0;
		score=0;
        apple.x = getRandomInt(0, 25) * grid;
        apple.y = getRandomInt(0, 25) * grid;
	    document.getElementById('high').innerHTML=max;
      }
    }
  }
  
  );
  
}
// listen to keyboard events to move the snake
document.addEventListener('keydown', function(e) {
  // prevent snake from backtracking on itself by checking that it's 
  // not already moving on the same axis (pressing left while moving
  // left won't do anything, and pressing right while moving left
  // shouldn't let you collide with your own body)
  
  // left arrow key
  if (e.which === 37 && snake.dx === 0) {
    snake.dx = -grid;
    snake.dy = 0;
  }
  // up arrow key
  else if (e.which === 38 && snake.dy === 0) {
    snake.dy = -grid;
    snake.dx = 0;
  }
  // right arrow key
  else if (e.which === 39 && snake.dx === 0) {
    snake.dx = grid;
    snake.dy = 0;
  }
  // down arrow key
  else if (e.which === 40 && snake.dy === 0) {
    snake.dy = grid;
    snake.dx = 0;
  }
});
// start the game
requestAnimationFrame(loop);
</script>
</body>
</html>
@noamboy2006

This comment has been minimized.

Copy link

@noamboy2006 noamboy2006 commented Nov 18, 2018

<script>
var canvas = document.getElementById('game');
var context = canvas.getContext('2d');
var grid = 16;
var count = 0;

var snake = {
  x: 160,
  y: 160,
  dx: grid,
  dy: 0,
  cells: [],
  maxCells: 4
};
var apple = {
  x: 320,
  y: 320
};
function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min)) + min;
}
function loop() {
  requestAnimationFrame(loop);
  if (++count < 4) {
    return;
  }
  count = 0;
  context.clearRect(0,0,canvas.width,canvas.height);
  snake.x += snake.dx;
  snake.y += snake.dy;
  if (snake.x < 0) {
    snake.x = canvas.width - grid;
  }
  else if (snake.x >= canvas.width) {
    snake.x = 0;
  }
  if (snake.y < 0) {
    snake.y = canvas.height - grid;
  }
  else if (snake.y >= canvas.height) {
    snake.y = 0;
  }
  snake.cells.unshift({x: snake.x, y: snake.y});
  if (snake.cells.length > snake.maxCells) {
    snake.cells.pop();
  }
  context.fillStyle = 'red';
  context.fillRect(apple.x, apple.y, grid-1, grid-1);
  context.fillStyle = 'green';
  snake.cells.forEach(function(cell, index) {
    context.fillRect(cell.x, cell.y, grid-1, grid-1);
    if (cell.x === apple.x && cell.y === apple.y) {
      snake.maxCells++;
      apple.x = getRandomInt(0, 25) * grid;
      apple.y = getRandomInt(0, 25) * grid;
    }
    for (var i = index + 1; i < snake.cells.length; i++) {
      if (cell.x === snake.cells[i].x && cell.y === snake.cells[i].y) {
        alert((snake.maxcells-4)+"점");
        snake.x = 160;
        snake.y = 160;
        snake.cells = [];
        snake.maxCells = 4;
        snake.dx = grid;
        snake.dy = 0;
        apple.x = getRandomInt(0, 25) * grid;
        apple.y = getRandomInt(0, 25) * grid;
      }
    }
  });
}
document.addEventListener('keydown', function(e) {

  if (e.which === 37 && snake.dx === 0) {
    snake.dx = -grid;
    snake.dy = 0;
  }
  else if (e.which === 38 && snake.dy === 0) {
    snake.dy = -grid;
    snake.dx = 0;
  }
  else if (e.which === 39 && snake.dx === 0) {
    snake.dx = grid;
    snake.dy = 0;
  }
  else if (e.which === 40 && snake.dy === 0) {
    snake.dy = grid;
    snake.dx = 0;
  }
});
requestAnimationFrame(loop);
</script>

score is here

@JesseBS2

This comment has been minimized.

Copy link

@JesseBS2 JesseBS2 commented Nov 20, 2018

@straker Hello! I am a big fan of this, project. I actually created an AI in pure javaScript to beat the game(because I stink at snake), it still has it's fair share of glitches, and hasn't once beaten the game, but I would still really like it if you checked out the repository here: https://github.com/JesseBS2/Snake-Ai

@nedwar01

This comment has been minimized.

Copy link

@nedwar01 nedwar01 commented Nov 26, 2018

Beautiful! Thanks for this guys

@Mubarak1234

This comment has been minimized.

Copy link

@Mubarak1234 Mubarak1234 commented Jan 11, 2019

Hi
how to add score in snake on HTML.
tell me

@ismailmuktar

This comment has been minimized.

Copy link

@ismailmuktar ismailmuktar commented Jan 13, 2019

thanks so much.

@firdous1

This comment has been minimized.

Copy link

@firdous1 firdous1 commented Mar 7, 2019

<!DOCTYPE html>
<html>
<head>
 <title></title>
 <style>
 html, body {
   height: 100%;
   margin: 0;
 }
 body {
   background: black;
   display: flex;
   align-items: center;
   justify-content: center;
 }
 canvas {
   border: 1px solid white;
 }
 </style>
</head>
<body>
<canvas width="400" height="400" id="game"></canvas>
<script>
var canvas = document.getElementById('game');
var context = canvas.getContext('2d');
var grid = 16;
var count = 0;
 
var snake = {
 x: 160,
 y: 160,
 
 // snake velocity. moves one grid length every frame in either the x or y direction
 dx: grid,
 dy: 0,
 
 // keep track of all grids the snake body occupies
 cells: [],
 
 // length of the snake. grows when eating an apple
 maxCells: 4
};
var apple = {
 x: 320,
 y: 320
};
// get random whole numbers in a specific range
// @see https://stackoverflow.com/a/1527820/2124254
function getRandomInt(min, max) {
 return Math.floor(Math.random() * (max - min)) + min;
}
// game loop
function loop() {
 requestAnimationFrame(loop);
 // slow game loop to 15 fps instead of 60 (60/15 = 4)
 if (++count < 4) {
   return;
 }
 count = 0;
 context.clearRect(0,0,canvas.width,canvas.height);
 // move snake by it's velocity
 snake.x += snake.dx;
 snake.y += snake.dy;
 // wrap snake position horizontally on edge of screen
 if (snake.x < 0) {
   snake.x = canvas.width - grid;
 }
 else if (snake.x >= canvas.width) {
   snake.x = 0;
 }
 
 // wrap snake position vertically on edge of screen
 if (snake.y < 0) {
   snake.y = canvas.height - grid;
 }
 else if (snake.y >= canvas.height) {
   snake.y = 0;
 }
 // keep track of where snake has been. front of the array is always the head
 snake.cells.unshift({x: snake.x, y: snake.y});
 // remove cells as we move away from them
 if (snake.cells.length > snake.maxCells) {
   snake.cells.pop();
 }
 // draw apple
 context.fillStyle = 'red';
 context.fillRect(apple.x, apple.y, grid-1, grid-1);
 // draw snake one cell at a time
 context.fillStyle = 'green';
 snake.cells.forEach(function(cell, index) {
  
   // drawing 1 px smaller than the grid creates a grid effect in the snake body so you can see how long it is
   context.fillRect(cell.x, cell.y, grid-1, grid-1); 
   // snake ate apple
   if (cell.x === apple.x && cell.y === apple.y) {
     snake.maxCells++;
     // canvas is 400x400 which is 25x25 grids
     apple.x = getRandomInt(0, 25) * grid;
     apple.y = getRandomInt(0, 25) * grid;
   }
   // check collision with all cells after this one (modified bubble sort)
   for (var i = index + 1; i < snake.cells.length; i++) {
    
     // snake occupies same space as a body part. reset game
     if (cell.x === snake.cells[i].x && cell.y === snake.cells[i].y) {
       snake.x = 160;
       snake.y = 160;
       snake.cells = [];
       snake.maxCells = 4;
       snake.dx = grid;
       snake.dy = 0;
       apple.x = getRandomInt(0, 25) * grid;
       apple.y = getRandomInt(0, 25) * grid;
     }
   }
 });
}
// listen to keyboard events to move the snake
document.addEventListener('keydown', function(e) {
 // prevent snake from backtracking on itself by checking that it's
 // not already moving on the same axis (pressing left while moving
 // left won't do anything, and pressing right while moving left
 // shouldn't let you collide with your own body)
 
 // left arrow key
 if (e.which === 37 && snake.dx === 0) {
   snake.dx = -grid;
   snake.dy = 0;
 }
 // up arrow key
 else if (e.which === 38 && snake.dy === 0) {
   snake.dy = -grid;
   snake.dx = 0;
 }
 // right arrow key
 else if (e.which === 39 && snake.dx === 0) {
   snake.dx = grid;
   snake.dy = 0;
 }
 // down arrow key
 else if (e.which === 40 && snake.dy === 0) {
   snake.dy = grid;
   snake.dx = 0;
 }
});
// start the game
requestAnimationFrame(loop);
</script>
</body>
</html>
@darthvader1925

This comment has been minimized.

Copy link

@darthvader1925 darthvader1925 commented Apr 1, 2019

It's great! it is a little too fast to move around without missing the `apples.

@kylecumber

This comment has been minimized.

Copy link

@kylecumber kylecumber commented May 1, 2019

so this was coded in html javasctript

@arifattal

This comment has been minimized.

Copy link

@arifattal arifattal commented Jul 29, 2019

Great work on this.
I would love to minimize the game's size to 400x200, and to replace the arrow keys with a,w,d,s.
I have edited the code as following, however, the controlling keys are still the arrow keys and the snake isn't always able to 'eat' the apples, any suggestions?

<html>
<head>
  <title></title>
  <style>
  html, body {
    height: 100%;
    margin: 0;
  }
  body {
    background: transparent;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  canvas {
    border: 0px solid white;
  }
  </style>
</head>
<body>
<canvas width="400" height="200" id="game"></canvas>
<script>
var canvas = document.getElementById('game');
var context = canvas.getContext('2d');
var grid = 16;
var count = 0;
  
var snake = {
  x: 160,
  y: 100,
  
  // snake velocity. moves one grid length every frame in either the x or y direction
  dx: grid,
  dy: 0,
  
  // keep track of all grids the snake body occupies
  cells: [],
  
  // length of the snake. grows when eating an apple
  maxCells: 4
};
var apple = {
  x: 320,
  y: 120
};
// get random whole numbers in a specific range
// @see https://stackoverflow.com/a/1527820/2124254
function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min)) + min;
}
// game loop
function loop() {
  requestAnimationFrame(loop);
  // slow game loop to 15 fps instead of 60 (60/15 = 4)
  if (++count < 4) {
    return;
  }
  count = 0;
  context.clearRect(0,0,canvas.width,canvas.height);
  // move snake by it's velocity
  snake.x += snake.dx;
  snake.y += snake.dy;
  // wrap snake position horizontally on edge of screen
  if (snake.x < 0) {
    snake.x = canvas.width - grid;
  }
  else if (snake.x >= canvas.width) {
    snake.x = 0;
  }
  
  // wrap snake position vertically on edge of screen
  if (snake.y < 0) {
    snake.y = canvas.height - grid;
  }
  else if (snake.y >= canvas.height) {
    snake.y = 0;
  }
  // keep track of where snake has been. front of the array is always the head
  snake.cells.unshift({x: snake.x, y: snake.y});
  // remove cells as we move away from them
  if (snake.cells.length > snake.maxCells) {
    snake.cells.pop();
  }
  // draw apple
  context.fillStyle = 'red';
  context.fillRect(apple.x, apple.y, grid-1, grid-1);
  // draw snake one cell at a time
  context.fillStyle = 'black';
  snake.cells.forEach(function(cell, index) {
    
    // drawing 1 px smaller than the grid creates a grid effect in the snake body so you can see how long it is
    context.fillRect(cell.x, cell.y, grid-1, grid-1);  
    // snake ate apple
    if (cell.x === apple.x && cell.y === apple.y) {
      snake.maxCells++;
      // canvas is 400x400 which is 25x25 grids 
      apple.x = getRandomInt(0, 25) * grid;
      apple.y = getRandomInt(0, 12.5) * grid;
    }
    // check collision with all cells after this one (modified bubble sort)
    for (var i = index + 1; i < snake.cells.length; i++) {
      
      // snake occupies same space as a body part. reset game
      if (cell.x === snake.cells[i].x && cell.y === snake.cells[i].y) {
        snake.x = 160;
        snake.y = 100;
        snake.cells = [];
        snake.maxCells = 4;
        snake.dx = grid;
        snake.dy = 0;
        apple.x = getRandomInt(0, 25) * grid;
        apple.y = getRandomInt(0, 12.5) * grid;
      }
    }
  });
}
// listen to keyboard events to move the snake
document.addEventListener('keydown', function(e) {
  // prevent snake from backtracking on itself by checking that it's 
  // not already moving on the same axis (pressing left while moving
  // left won't do anything, and pressing right while moving left
  // shouldn't let you collide with your own body)
  
  // a arrow key
  if (e.which === 37 && snake.dx === 0) {
    snake.dx = -grid;
    snake.dy = 0;
  }
  // w arrow key
  else if (e.which === 38 && snake.dy === 0) {
    snake.dy = -grid;
    snake.dx = 0;
  }
  // d arrow key
  else if (e.which === 39 && snake.dx === 0) {
    snake.dx = grid;
    snake.dy = 0;
  }
  // s arrow key
  else if (e.which === 40 && snake.dy === 0) {
    snake.dy = grid;
    snake.dx = 0;
  }
});
// start the game
requestAnimationFrame(loop);
</script>
</body>
</html>
@morganpage

This comment has been minimized.

Copy link

@morganpage morganpage commented Sep 9, 2019

Nice! Did a Phaser version here

@AndreWWWolf

This comment has been minimized.

Copy link

@AndreWWWolf AndreWWWolf commented Sep 11, 2019

Great work on this.
I would love to minimize the game's size to 400x200, and to replace the arrow keys with a,w,d,s.
I have edited the code as following, however, the controlling keys are still the arrow keys and the snake isn't always able to 'eat' the apples, any suggestions?

<title></title> <style> html, body { height: 100%; margin: 0; } body { background: transparent; display: flex; align-items: center; justify-content: center; } canvas { border: 0px solid white; } </style> <script> var canvas = document.getElementById('game'); var context = canvas.getContext('2d'); var grid = 16; var count = 0; var snake = { x: 160, y: 100,

// snake velocity. moves one grid length every frame in either the x or y direction
dx: grid,
dy: 0,

// keep track of all grids the snake body occupies
cells: [],

// length of the snake. grows when eating an apple
maxCells: 4
};
var apple = {
x: 320,
y: 120
};
// get random whole numbers in a specific range
// @see https://stackoverflow.com/a/1527820/2124254
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}
// game loop
function loop() {
requestAnimationFrame(loop);
// slow game loop to 15 fps instead of 60 (60/15 = 4)
if (++count < 4) {
return;
}
count = 0;
context.clearRect(0,0,canvas.width,canvas.height);
// move snake by it's velocity
snake.x += snake.dx;
snake.y += snake.dy;
// wrap snake position horizontally on edge of screen
if (snake.x < 0) {
snake.x = canvas.width - grid;
}
else if (snake.x >= canvas.width) {
snake.x = 0;
}

// wrap snake position vertically on edge of screen
if (snake.y < 0) {
snake.y = canvas.height - grid;
}
else if (snake.y >= canvas.height) {
snake.y = 0;
}
// keep track of where snake has been. front of the array is always the head
snake.cells.unshift({x: snake.x, y: snake.y});
// remove cells as we move away from them
if (snake.cells.length > snake.maxCells) {
snake.cells.pop();
}
// draw apple
context.fillStyle = 'red';
context.fillRect(apple.x, apple.y, grid-1, grid-1);
// draw snake one cell at a time
context.fillStyle = 'black';
snake.cells.forEach(function(cell, index) {

// drawing 1 px smaller than the grid creates a grid effect in the snake body so you can see how long it is
context.fillRect(cell.x, cell.y, grid-1, grid-1);  
// snake ate apple
if (cell.x === apple.x && cell.y === apple.y) {
  snake.maxCells++;
  // canvas is 400x400 which is 25x25 grids 
  apple.x = getRandomInt(0, 25) * grid;
  apple.y = getRandomInt(0, 12.5) * grid;
}
// check collision with all cells after this one (modified bubble sort)
for (var i = index + 1; i < snake.cells.length; i++) {
  
  // snake occupies same space as a body part. reset game
  if (cell.x === snake.cells[i].x && cell.y === snake.cells[i].y) {
    snake.x = 160;
    snake.y = 100;
    snake.cells = [];
    snake.maxCells = 4;
    snake.dx = grid;
    snake.dy = 0;
    apple.x = getRandomInt(0, 25) * grid;
    apple.y = getRandomInt(0, 12.5) * grid;
  }
}

});
}
// listen to keyboard events to move the snake
document.addEventListener('keydown', function(e) {
// prevent snake from backtracking on itself by checking that it's
// not already moving on the same axis (pressing left while moving
// left won't do anything, and pressing right while moving left
// shouldn't let you collide with your own body)

// a arrow key
if (e.which === 65 && snake.dx === 0) {
snake.dx = -grid;
snake.dy = 0;
}
// w arrow key
else if (e.which === 86 && snake.dy === 0) {
snake.dy = -grid;
snake.dx = 0;
}
// d arrow key
else if (e.which === 68 && snake.dx === 0) {
snake.dx = grid;
snake.dy = 0;
}
// s arrow key
else if (e.which === 83 && snake.dy === 0) {
snake.dy = grid;
snake.dx = 0;
}
});
// start the game
requestAnimationFrame(loop);
</script>

//the numbers called in the arrow key functions are key values, 37, 38, 39, 40 are the arrow keys. so replacing those values with the ones above as i edited will use the w,a,s,d keys instead of arrows. look up "keyboard key values html" to see a full list.

@erosramses18

This comment has been minimized.

Copy link

@erosramses18 erosramses18 commented Sep 19, 2019

i download the game

@nhat-nam

This comment has been minimized.

Copy link

@nhat-nam nhat-nam commented Sep 20, 2019

How does the computer know the input for the snake movement what line of code was that
the eventListener part

@Nyal1

This comment has been minimized.

Copy link

@Nyal1 Nyal1 commented Oct 27, 2019

The two issues are that there is no score counter, and the snake doesnt die when it hits the wall. To add a score counter:

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<style>
canvas {
    border:1px solid #d3d3d3;
    background-color: #f1f1f1;
}
</style>
</head>
<body onload="startGame()">
<script>

var myGamePiece;
var myObstacles = [];
var myScore;

function startGame() {
    myGamePiece = new component(30, 30, "red", 10, 120);
    myScore = new component("30px", "Consolas", "black", 280, 40, "text");
    myGameArea.start();
}

var myGameArea = {
    canvas : document.createElement("canvas"),
    start : function() {
        this.canvas.width = 480;
        this.canvas.height = 270;
        this.context = this.canvas.getContext("2d");
        document.body.insertBefore(this.canvas, document.body.childNodes[0]);
        this.frameNo = 0;
        this.interval = setInterval(updateGameArea, 20);
        },
    clear : function() {
        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
    },
    stop : function() {
        clearInterval(this.interval);
    }
}

function component(width, height, color, x, y, type) {
    this.type = type;
    this.width = width;
    this.height = height;
    this.speedX = 0;
    this.speedY = 0;    
    this.x = x;
    this.y = y;    
    this.update = function() {
        ctx = myGameArea.context;
        if (this.type == "text") {
            ctx.font = this.width + " " + this.height;
            ctx.fillStyle = color;
            ctx.fillText(this.text, this.x, this.y);
        } else {
            ctx.fillStyle = color;
            ctx.fillRect(this.x, this.y, this.width, this.height);
        }
    }
    this.newPos = function() {
        this.x += this.speedX;
        this.y += this.speedY;        
    }
    this.crashWith = function(otherobj) {
        var myleft = this.x;
        var myright = this.x + (this.width);
        var mytop = this.y;
        var mybottom = this.y + (this.height);
        var otherleft = otherobj.x;
        var otherright = otherobj.x + (otherobj.width);
        var othertop = otherobj.y;
        var otherbottom = otherobj.y + (otherobj.height);
        var crash = true;
        if ((mybottom < othertop) || (mytop > otherbottom) || (myright < otherleft) || (myleft > otherright)) {
            crash = false;
        }
        return crash;
    }
}

function updateGameArea() {
    var x, height, gap, minHeight, maxHeight, minGap, maxGap;
    for (i = 0; i < myObstacles.length; i += 1) {
        if (myGamePiece.crashWith(myObstacles[i])) {
            myGameArea.stop();
            return;
        } 
    }
    myGameArea.clear();
    myGameArea.frameNo += 1;
    if (myGameArea.frameNo == 1 || everyinterval(150)) {
        x = myGameArea.canvas.width;
        minHeight = 20;
        maxHeight = 200;
        height = Math.floor(Math.random()*(maxHeight-minHeight+1)+minHeight);
        minGap = 50;
        maxGap = 200;
        gap = Math.floor(Math.random()*(maxGap-minGap+1)+minGap);
        myObstacles.push(new component(10, height, "green", x, 0));
        myObstacles.push(new component(10, x - height - gap, "green", x, height + gap));
    }
    for (i = 0; i < myObstacles.length; i += 1) {
        myObstacles[i].speedX = -1;
        myObstacles[i].newPos();
        myObstacles[i].update();
    }
    myScore.text="SCORE: " + myGameArea.frameNo;
    myScore.update();
    myGamePiece.newPos();    
    myGamePiece.update();
}

function everyinterval(n) {
    if ((myGameArea.frameNo / n) % 1 == 0) {return true;}
    return false;
}

function moveup() {
    myGamePiece.speedY = -1; 
}

function movedown() {
    myGamePiece.speedY = 1; 
}

function moveleft() {
    myGamePiece.speedX = -1; 
}

function moveright() {
    myGamePiece.speedX = 1; 
}

function clearmove() {
    myGamePiece.speedX = 0; 
    myGamePiece.speedY = 0; 
}
</script>
<div style="text-align:center;width:480px;">
  <button onmousedown="moveup()" onmouseup="clearmove()" ontouchstart="moveup()">UP</button><br><br>
  <button onmousedown="moveleft()" onmouseup="clearmove()" ontouchstart="moveleft()">LEFT</button>
  <button onmousedown="moveright()" onmouseup="clearmove()" ontouchstart="moveright()">RIGHT</button><br><br>
  <button onmousedown="movedown()" onmouseup="clearmove()" ontouchstart="movedown()">DOWN</button>
</div>

<p>The score will count one point for each frame you manage to "stay alive".</p>
</body>
</html>
@Code-With-Me-YT

This comment has been minimized.

Copy link

@Code-With-Me-YT Code-With-Me-YT commented Nov 19, 2019

Can someone please edit this so that it closes the window if you hit the wall. Thankyou.

var canvas = document.getElementById('game');
var context = canvas.getContext('2d');
var grid = 16;
var count = 0;
  
var snake = {
  x: 160,
  y: 160,
  
  // snake velocity. moves one grid length every frame in either the x or y direction
  dx: grid,
  dy: 0,
  
  // keep track of all grids the snake body occupies
  cells: [],
  
  // length of the snake. grows when eating an apple
  maxCells: 4
};
var apple = {
  x: 320,
  y: 320
};
// get random whole numbers in a specific range
// @see https://stackoverflow.com/a/1527820/2124254
function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min)) + min;
}
// game loop
function loop() {
  requestAnimationFrame(loop);
  // slow game loop to 15 fps instead of 60 (60/15 = 4)
  if (++count < 4) {
    return;
  }
  count = 0;
  context.clearRect(0,0,canvas.width,canvas.height);
  // move snake by it's velocity
  snake.x += snake.dx;
  snake.y += snake.dy;
  // wrap snake position horizontally on edge of screen
  if (snake.x < 0) {
    snake.x = canvas.width - grid;
  }
  else if (snake.x >= canvas.width) {
    snake.x = 0;
  }
  
  // wrap snake position vertically on edge of screen
  if (snake.y < 0) {
    snake.y = canvas.height - grid;
  }
  else if (snake.y >= canvas.height) {
    snake.y = 0;
  }
  // keep track of where snake has been. front of the array is always the head
  snake.cells.unshift({x: snake.x, y: snake.y});
  // remove cells as we move away from them
  if (snake.cells.length > snake.maxCells) {
    snake.cells.pop();
  }
  // draw apple
  context.fillStyle = 'red';
  context.fillRect(apple.x, apple.y, grid-1, grid-1);
  // draw snake one cell at a time
  context.fillStyle = 'green';
  snake.cells.forEach(function(cell, index) {
    
    // drawing 1 px smaller than the grid creates a grid effect in the snake body so you can see how long it is
    context.fillRect(cell.x, cell.y, grid-1, grid-1);  
    // snake ate apple
    if (cell.x === apple.x && cell.y === apple.y) {
      snake.maxCells++;
      // canvas is 400x400 which is 25x25 grids 
      apple.x = getRandomInt(0, 25) * grid;
      apple.y = getRandomInt(0, 25) * grid;
    }
    // check collision with all cells after this one (modified bubble sort)
    for (var i = index + 1; i < snake.cells.length; i++) {
      
      // snake occupies same space as a body part. reset game
      if (cell.x === snake.cells[i].x && cell.y === snake.cells[i].y) {
        snake.x = 160;
        snake.y = 160;
        snake.cells = [];
        snake.maxCells = 4;
        snake.dx = grid;
        snake.dy = 0;
        apple.x = getRandomInt(0, 25) * grid;
        apple.y = getRandomInt(0, 25) * grid;
      }
    }
  });
}
// listen to keyboard events to move the snake
document.addEventListener('keydown', function(e) {
  // prevent snake from backtracking on itself by checking that it's 
  // not already moving on the same axis (pressing left while moving
  // left won't do anything, and pressing right while moving left
  // shouldn't let you collide with your own body)
  
  // left arrow key
  if (e.which === 37 && snake.dx === 0) {
    snake.dx = -grid;
    snake.dy = 0;
  }
  // up arrow key
  else if (e.which === 38 && snake.dy === 0) {
    snake.dy = -grid;
    snake.dx = 0;
  }
  // right arrow key
  else if (e.which === 39 && snake.dx === 0) {
    snake.dx = grid;
    snake.dy = 0;
  }
  // down arrow key
  else if (e.which === 40 && snake.dy === 0) {
    snake.dy = grid;
    snake.dx = 0;
  }
});
// start the game
requestAnimationFrame(loop);
@resynth1943

This comment has been minimized.

Copy link

@resynth1943 resynth1943 commented Dec 12, 2019

can you guys stop sending unformatted / unhighlighted source? you're fucking up the comment section

@UdiePie

This comment has been minimized.

Copy link

@UdiePie UdiePie commented Dec 14, 2019

<title></title> <style> html, body { height: 100%; margin: 0; } body { background: black; display: flex; align-items: center; justify-content: center; } canvas { border: 1px solid white; } #p1 { color:red; position:absolute; left:100px; top:10px; } #p2 { color:red; position:absolute; left:100px; top:30px; } #score { color:yellow; position:absolute; left:155px; top:10px; } #high { color:yellow; position:absolute; left:195px; top:30px; } </style> SCORE:

HIGHSCORE:

<script> var canvas = document.getElementById('game'); var context = canvas.getContext('2d'); var grid = 16; var count = 0; var score=0; var max=0; var snake = { x: 160, y: 160, // snake velocity. moves one grid length every frame in either the x or y direction dx: grid, dy: 0, // keep track of all grids the snake body occupies cells: [], // length of the snake. grows when eating an apple maxCells: 4 }; var apple = { x: 320, y: 320 }; // get random whole numbers in a specific range // @see https://stackoverflow.com/a/1527820/2124254 function getRandomInt(min, max) { return Math.floor(Math.random() * (max - min)) + min; } // game loop function loop() { requestAnimationFrame(loop); // slow game loop to 15 fps instead of 60 (60/15 = 4) if (++count < 4) { return; } count = 0; context.clearRect(0,0,canvas.width,canvas.height); // move snake by it's velocity snake.x += snake.dx; snake.y += snake.dy; // wrap snake position horizontally on edge of screen if (snake.x < 0) { snake.x = canvas.width - grid; } else if (snake.x >= canvas.width) { snake.x = 0; } // wrap snake position vertically on edge of screen if (snake.y < 0) { snake.y = canvas.height - grid; } else if (snake.y >= canvas.height) { snake.y = 0; } // keep track of where snake has been. front of the array is always the head snake.cells.unshift({x: snake.x, y: snake.y}); // remove cells as we move away from them if (snake.cells.length > snake.maxCells) { snake.cells.pop(); } // draw apple context.fillStyle = 'red'; context.fillRect(apple.x, apple.y, grid-1, grid-1); // draw snake one cell at a time context.fillStyle = 'green'; snake.cells.forEach(function(cell, index) { ``` // drawing 1 px smaller than the grid creates a grid effect in the snake body so you can see how long it is context.fillRect(cell.x, cell.y, grid-1, grid-1); // snake ate apple if (cell.x === apple.x && cell.y === apple.y) { snake.maxCells++; score+=10; //max=score; document.getElementById('score').innerHTML=score; // canvas is 400x400 which is 25x25 grids apple.x = getRandomInt(0, 25) * grid; apple.y = getRandomInt(0, 25) * grid; } // check collision with all cells after this one (modified bubble sort) for (var i = index + 1; i < snake.cells.length; i++) { // snake occupies same space as a body part. reset game if (cell.x === snake.cells[i].x && cell.y === snake.cells[i].y) { if(score>max) { max=score; } snake.x = 160; snake.y = 160; snake.cells = []; snake.maxCells = 4; snake.dx = grid; snake.dy = 0; score=0; apple.x = getRandomInt(0, 25) * grid; apple.y = getRandomInt(0, 25) * grid; document.getElementById('high').innerHTML=max; } } ``` } ); } // listen to keyboard events to move the snake document.addEventListener('keydown', function(e) { // prevent snake from backtracking on itself by checking that it's // not already moving on the same axis (pressing left while moving // left won't do anything, and pressing right while moving left // shouldn't let you collide with your own body) // left arrow key if (e.which === 37 && snake.dx === 0) { snake.dx = -grid; snake.dy = 0; } // up arrow key else if (e.which === 38 && snake.dy === 0) { snake.dy = -grid; snake.dx = 0; } // right arrow key else if (e.which === 39 && snake.dx === 0) { snake.dx = grid; snake.dy = 0; } // down arrow key else if (e.which === 40 && snake.dy === 0) { snake.dy = grid; snake.dx = 0; } }); // start the game requestAnimationFrame(loop); </script>

hey i just am confused with your score system it wont work is that for html? i did what you said but it did not work, sorry to bother you im new to programming have any idea what i did wrong? :)

@Kazibwe02

This comment has been minimized.

Copy link

@Kazibwe02 Kazibwe02 commented Dec 22, 2019

Nice Game Thanks Please

@Kazibwe02

This comment has been minimized.

Copy link

@Kazibwe02 Kazibwe02 commented Dec 22, 2019

With score system, us the codes below

<!DOCTYPE html>
<html>
<head>
  <title></title>
  <style>
  html, body {
    height: 100%;
    margin: 0;
  }
  body {
    background: black;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  canvas {
    border: 1px solid white; background-color:gold;
  }
  #p1
  {
    color:red;
	position:absolute;
	left:100px;
	top:10px;
  }
    #p2
  {
    color:red;
	position:absolute;
	left:100px;
	top:30px;
  }
  #score
  {
    color:yellow;
    position:absolute;
	left:155px;
	top:10px;
  }
  #high
  {
    color:yellow;
    position:absolute;
	left:195px;
	top:30px;
  }
  </style>
</head>
<body>
<p id="p1">SCORE:</p>
<p id="p2">HIGHSCORE:</p>
<p id="score"></p>
<p id="high"></p>
<canvas width="400" height="400" id="game"></canvas>
<script>
var canvas = document.getElementById('game');
var context = canvas.getContext('2d');
var grid = 16;
var count = 0;
var score=0;
var max=0;  

var snake = {
  x: 160,
  y: 160,
  
  // snake velocity. moves one grid length every frame in either the x or y direction
  dx: grid,
  dy: 0,
  
  // keep track of all grids the snake body occupies
  cells: [],
  
  // length of the snake. grows when eating an apple
  maxCells: 4
};
var apple = {
  x: 320,
  y: 320
};

// get random whole numbers in a specific range
// @see https://stackoverflow.com/a/1527820/2124254
function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min)) + min;
}
// game loop
function loop() {
  requestAnimationFrame(loop);
  // slow game loop to 15 fps instead of 60 (60/15 = 4)
  if (++count < 4) {
    return;
  }
  count = 0;
  context.clearRect(0,0,canvas.width,canvas.height);
  // move snake by it's velocity
  snake.x += snake.dx;
  snake.y += snake.dy;
  // wrap snake position horizontally on edge of screen
  if (snake.x < 0) {
    snake.x = canvas.width - grid;
  }
  else if (snake.x >= canvas.width) {
    snake.x = 0;
  }
  
  // wrap snake position vertically on edge of screen
  if (snake.y < 0) {
    snake.y = canvas.height - grid;
  }
  else if (snake.y >= canvas.height) {
    snake.y = 0;
  }
  // keep track of where snake has been. front of the array is always the head
  snake.cells.unshift({x: snake.x, y: snake.y});
  // remove cells as we move away from them
  if (snake.cells.length > snake.maxCells) {
    snake.cells.pop();
  }
  // draw apple
  context.fillStyle = 'red';
  context.fillRect(apple.x, apple.y, grid-1, grid-1);
  // draw snake one cell at a time
  context.fillStyle = 'green';
  snake.cells.forEach(function(cell, index) {
    
    // drawing 1 px smaller than the grid creates a grid effect in the snake body so you can see how long it is
    context.fillRect(cell.x, cell.y, grid-1, grid-1);  
    // snake ate apple
    if (cell.x === apple.x && cell.y === apple.y) {
      snake.maxCells++;
	  score+=10;
	  //max=score;
	  document.getElementById('score').innerHTML=score;
	
      // canvas is 400x400 which is 25x25 grids 
      apple.x = getRandomInt(0, 25) * grid;
      apple.y = getRandomInt(0, 25) * grid;
    }
    // check collision with all cells after this one (modified bubble sort)
    for (var i = index + 1; i < snake.cells.length; i++)
	{
      
      // snake occupies same space as a body part. reset game
      if (cell.x === snake.cells[i].x && cell.y === snake.cells[i].y) 
	 { 
	 
	    if(score>max)
	    {
	     max=score;
	    }
    	snake.x = 160;
        snake.y = 160;
        snake.cells = [];
        snake.maxCells = 4;
        snake.dx = grid;
        snake.dy = 0;
		score=0;
        apple.x = getRandomInt(0, 25) * grid;
        apple.y = getRandomInt(0, 25) * grid;
	    document.getElementById('high').innerHTML=max;
      }
    }
  }
  
  );
  
}
// listen to keyboard events to move the snake
document.addEventListener('keydown', function(e) {
  // prevent snake from backtracking on itself by checking that it's 
  // not already moving on the same axis (pressing left while moving
  // left won't do anything, and pressing right while moving left
  // shouldn't let you collide with your own body)
  
  // left arrow key
  if (e.which === 37 && snake.dx === 0) {
    snake.dx = -grid;
    snake.dy = 0;
  }
  // up arrow key
  else if (e.which === 38 && snake.dy === 0) {
    snake.dy = -grid;
    snake.dx = 0;
  }
  // right arrow key
  else if (e.which === 39 && snake.dx === 0) {
    snake.dx = grid;
    snake.dy = 0;
  }
  // down arrow key
  else if (e.which === 40 && snake.dy === 0) {
    snake.dy = grid;
    snake.dx = 0;
  }
});
// start the game
requestAnimationFrame(loop);
</script>
</body>
</html>
@yagizher

This comment has been minimized.

Copy link

@yagizher yagizher commented Dec 23, 2019

How to make this work in our gcphone?

@scientist-hub

This comment has been minimized.

Copy link

@scientist-hub scientist-hub commented Dec 26, 2019

Wow!!! so amazing

@beto03d

This comment has been minimized.

Copy link

@beto03d beto03d commented Jan 8, 2020

how do you run the code`

@jordan7mitchell

This comment has been minimized.

Copy link

@jordan7mitchell jordan7mitchell commented Feb 8, 2020

I embedded this into a website of mine, but now on mobile none of the links on my page work. Do you know why or how I could fix that?

@straker

This comment has been minimized.

Copy link
Owner Author

@straker straker commented Feb 10, 2020

@jordan7mitchell I'm not sure. The code shouldn't interfere with the website, especially the links.

@ronnyiscoding

This comment has been minimized.

@perplexiumboi

This comment has been minimized.

Copy link

@perplexiumboi perplexiumboi commented Feb 19, 2020

cool thx

@Epic4773

This comment has been minimized.

Copy link

@Epic4773 Epic4773 commented Feb 28, 2020

joe

@Pro496951

This comment has been minimized.

Copy link

@Pro496951 Pro496951 commented Mar 24, 2020

I have made a flappy bird gist plz check it out Link:
https://gist.github.com/Pro496951/a7537d2f313fbc6ebad1f74b83f84244

@Matriarchy

This comment has been minimized.

Copy link

@Matriarchy Matriarchy commented Apr 7, 2020

How do you make the border visible i'd like to have an outline?

@kapidsai000

This comment has been minimized.

Copy link

@kapidsai000 kapidsai000 commented Apr 8, 2020

this is another game

<style> canvas { border:1px solid #d3d3d3; background-color: #f1f1f1; } </style> <script>

var myGamePiece;
var myObstacles = [];

function startGame() {
myGamePiece = new component(30, 30, "red", 10, 120);
myGameArea.start();
}

var myGameArea = {
canvas : document.createElement("canvas"),
start : function() {
this.canvas.width = 480;
this.canvas.height = 270;
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
this.frameNo = 0;
this.interval = setInterval(updateGameArea, 20);
},
clear : function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
},
stop : function() {
clearInterval(this.interval);
}
}

function component(width, height, color, x, y) {
this.width = width;
this.height = height;
this.speedX = 0;
this.speedY = 0;
this.x = x;
this.y = y;
this.update = function() {
ctx = myGameArea.context;
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
this.newPos = function() {
this.x += this.speedX;
this.y += this.speedY;
}
this.crashWith = function(otherobj) {
var myleft = this.x;
var myright = this.x + (this.width);
var mytop = this.y;
var mybottom = this.y + (this.height);
var otherleft = otherobj.x;
var otherright = otherobj.x + (otherobj.width);
var othertop = otherobj.y;
var otherbottom = otherobj.y + (otherobj.height);
var crash = true;
if ((mybottom < othertop) || (mytop > otherbottom) || (myright < otherleft) || (myleft > otherright)) {
crash = false;
}
return crash;
}
}

function updateGameArea() {
var x, height, gap, minHeight, maxHeight, minGap, maxGap;
for (i = 0; i < myObstacles.length; i += 1) {
if (myGamePiece.crashWith(myObstacles[i])) {
myGameArea.stop();
return;
}
}
myGameArea.clear();
myGameArea.frameNo += 1;
if (myGameArea.frameNo == 1 || everyinterval(150)) {
x = myGameArea.canvas.width;
minHeight = 20;
maxHeight = 200;
height = Math.floor(Math.random()(maxHeight-minHeight+1)+minHeight);
minGap = 50;
maxGap = 200;
gap = Math.floor(Math.random()
(maxGap-minGap+1)+minGap);
myObstacles.push(new component(10, height, "green", x, 0));
myObstacles.push(new component(10, x - height - gap, "green", x, height + gap));
}
for (i = 0; i < myObstacles.length; i += 1) {
myObstacles[i].x += -1;
myObstacles[i].update();
}
myGamePiece.newPos();
myGamePiece.update();
}

function everyinterval(n) {
if ((myGameArea.frameNo / n) % 1 == 0) {return true;}
return false;
}

function moveup() {
myGamePiece.speedY = -1;
}

function movedown() {
myGamePiece.speedY = 1;
}

function moveleft() {
myGamePiece.speedX = -1;
}

function moveright() {
myGamePiece.speedX = 1;
}

function clearmove() {
myGamePiece.speedX = 0;
myGamePiece.speedY = 0;
}
</script>

UP

LEFT RIGHT

DOWN
@Pro496951

This comment has been minimized.

@Pro496951

This comment has been minimized.

@kikme

This comment has been minimized.

Copy link

@kikme kikme commented Apr 13, 2020

how can control this in my phone

@SKULLCODER1303

This comment has been minimized.

Copy link

@SKULLCODER1303 SKULLCODER1303 commented Apr 21, 2020

Hi,
Great game
Now a challenge for all. ~

  1. create a mobile version for 2 player at a time playing in same screen (from different devices)
  2. users add their username
  3. mention scores for both the players on top against their name, scores should be updated whenever the snake eats the food.
  4. Game should run for specific time say 3 minutes (player eating most food will win)
  5. Add multiple foods at a time in a screen seen to the player,
  6. Players can cross each other.
  7. the game over logic for a player is actually score reset to 0 but player plays again since the timer is still left.
  8. Game is over once timer is 0.
  9. Return the winner - winner screen showing the scores.

paste your code in reply.

@obrni

This comment has been minimized.

Copy link

@obrni obrni commented Apr 23, 2020

The game is so good! How can I add score?

@Filesnake

This comment has been minimized.

Copy link

@Filesnake Filesnake commented May 27, 2020

Hello all! i'm wondering if you can teach me how to make a HTML game thanks!

@NOPROD

This comment has been minimized.

Copy link

@NOPROD NOPROD commented Jun 6, 2020

Hi,
Great game
Now a challenge for all. ~

1. create a mobile version for 2 player at a time playing in same screen (from different devices)

2. users add their username

3. mention scores for both the players on top against their name, scores should be updated whenever the snake eats the food.

4. Game should run for specific time say 3 minutes (player eating most food will win)

5. Add multiple foods at a time in a screen seen to the player,

6. Players can cross each other.

7. the game over logic for a player is actually score reset to 0 but player plays again since the timer is still left.

8. Game is over once timer is 0.

9. Return the winner -  winner screen showing the scores.

paste your code in reply.

It looks like you want code for your site, do it yourself ^^

@TahirMurata

This comment has been minimized.

Copy link

@TahirMurata TahirMurata commented Jun 10, 2020

Hey guys how to make the snake move slow?

@straker

This comment has been minimized.

Copy link
Owner Author

@straker straker commented Jun 10, 2020

@asimo10 to slow the snake you'll need to slow the game speed down. You'll need to experiment to find the sped you want. https://gist.github.com/straker/ff00b4b49669ad3dec890306d348adc4#file-snake-html-L60-L63

@TahirMurata

This comment has been minimized.

Copy link

@TahirMurata TahirMurata commented Jun 10, 2020

I found it just to change the 4.
function loop() { requestAnimationFrame(loop); // slow game loop to 15 fps instead of 60 (60/15 = 4) if (++count < 4) { return; }

@TahirMurata

This comment has been minimized.

Copy link

@TahirMurata TahirMurata commented Jun 10, 2020

Thx

@MaffiSux

This comment has been minimized.

Copy link

@MaffiSux MaffiSux commented Jun 15, 2020

I don't know how to code this, but i think i figured out a way to make it so the snake dies when it hits a wall. For it to work, the starting position of the snake has to be in the middle of the screen instead of the edge. You need to make it so it resets when x or y is less than zero instead of it wrapping the edge. I hope this helps somebody because I'll feel stupid if it doesn't.

@VPTT-webD

This comment has been minimized.

Copy link

@VPTT-webD VPTT-webD commented Jun 15, 2020

how do you calculate the grid of the canvas like: 400x400 = 25x25

@VPTT-webD

This comment has been minimized.

Copy link

@VPTT-webD VPTT-webD commented Jun 15, 2020

please, can you teach me this code : if (snake.x < 0) {
snake.x = canvas.width - grid;
}
else if (snake.x >= canvas.width) {
snake.x = 0;
}

@straker

This comment has been minimized.

Copy link
Owner Author

@straker straker commented Jun 15, 2020

@StLoveCodingAndLoveARVN the code allows the snake to wrap the screen. When the snake is outside the bounds of the canvas (so the x position is below 0 or above the canvas width) then the code makes the snakes position "wrap" by setting it to the opposite side of the canvas.

@VPTT-webD

This comment has been minimized.

Copy link

@VPTT-webD VPTT-webD commented Jun 16, 2020

@staker tks, and one more question: how to calculate the grid of canvas. pls help me

@straker

This comment has been minimized.

Copy link
Owner Author

@straker straker commented Jun 16, 2020

@StLoveCodingAndLoveARVN grid size is whatever size you want it to be so long as it even divides into the canvas size. If you want the snake to be bigger and have less squares per row, choose a larger grid size. If you want the snake to be smaller and have more square per row, choose a smaller one. I choose 16 as that's a common size for games (32x32 being another one).

@Rabios

This comment has been minimized.

Copy link

@Rabios Rabios commented Jun 27, 2020

I made a version for my game framework Pancake

Plus:

  1. Canvas resized to fit all screen when toggling fullscreen,Else it resized to fit the document of the window
  2. Added toggling fullscreen mode when player clicks on canvas
  3. Added swiping for mobile and added gamepad controls
  4. Added highscore system
  5. Better collision between snake and food
  6. Better game speed

See the game runs here

You can also see source code here

Hope you like it!

@Python3-8

This comment has been minimized.

Copy link

@Python3-8 Python3-8 commented Aug 10, 2020

This game is awesome!

@MaxDamonte

This comment has been minimized.

Copy link

@MaxDamonte MaxDamonte commented Sep 4, 2020

works great!!

@SamDamonte

This comment has been minimized.

Copy link

@SamDamonte SamDamonte commented Sep 4, 2020

awesome!

@SamDamonte

This comment has been minimized.

Copy link

@SamDamonte SamDamonte commented Sep 4, 2020

heres a different one
`

<title>SnakeGame</title> <style> .game-box { text-align:center; } .game-info { text-align:center; font-family:arial; line-height:24px; } </style>

Snake Game

<script>
  var canvas, ctx, gameControl, gameActive;
  // render X times per second
  var x = 8;
 
  const CANVAS_BORDER_COLOUR = 'black';
  const CANVAS_BACKGROUND_COLOUR = "white";
  const SNAKE_COLOUR = 'lightgreen';
  const SNAKE_BORDER_COLOUR = 'darkgreen';


  window.onload = function() {
    canvas = document.getElementById("canvas");
    ctx = canvas.getContext("2d");

    document.addEventListener("keydown", keyDownEvent);

    gameControl = startGame(x);
  };
 
  /* function to start the game */
  function startGame(x) {
      // setting gameActive flag to true
      gameActive = true;
      document.getElementById("game-status").innerHTML = "<small>Game Started</small>";
      document.getElementById("game-score").innerHTML = "";
      return setInterval(draw, 1000 / x);
  }
 
  function pauseGame() {
      // setting gameActive flag to false
      clearInterval(gameControl);
      gameActive = false;
      document.getElementById("game-status").innerHTML = "<small>Game Paused</small>";
  }
 
  function endGame(x) {
      // setting gameActive flag to false
      clearInterval(gameControl);
      gameActive = false;
      document.getElementById("game-status").innerHTML = "<small>Game Over</small>";
      document.getElementById("game-score").innerHTML = "<h1>Score: " + x + "</h1>";
  }

  // game world
  var gridSize = (tileSize = 20); // 20 x 20 = 400
  var nextX = (nextY = 0);

  // snake
  var defaultTailSize = 3;
  var tailSize = defaultTailSize;
  var snakeTrail = [];
  var snakeX = (snakeY = 10);

  // apple
  var appleX = (appleY = 15);

  // draw
  function draw() {
    // move snake in next pos
    snakeX += nextX;
    snakeY += nextY;

    // snake over game world?
    if (snakeX < 0) {
      snakeX = gridSize - 1;
    }
    if (snakeX > gridSize - 1) {
      snakeX = 0;
    }

    if (snakeY < 0) {
      snakeY = gridSize - 1;
    }
    if (snakeY > gridSize - 1) {
      snakeY = 0;
    }

    //snake bite apple?
    if (snakeX == appleX && snakeY == appleY) {
      tailSize++;

      appleX = Math.floor(Math.random() * gridSize);
      appleY = Math.floor(Math.random() * gridSize);
    }

    //  Select the colour to fill the canvas
  ctx.fillStyle = CANVAS_BACKGROUND_COLOUR;
  //  Select the colour for the border of the canvas
  ctx.strokestyle = CANVAS_BORDER_COLOUR;

  // Draw a "filled" rectangle to cover the entire canvas
  ctx.fillRect(0, 0, canvas.width, canvas.height);
  // Draw a "border" around the entire canvas
  ctx.strokeRect(0, 0, canvas.width, canvas.height);

    // paint snake
    ctx.fillStyle = SNAKE_COLOUR;
    ctx.strokestyle = SNAKE_BORDER_COLOUR;
    for (var i = 0; i < snakeTrail.length; i++) {
      ctx.fillRect(
        snakeTrail[i].x * tileSize,
        snakeTrail[i].y * tileSize,
        tileSize,
        tileSize
      );
     
      ctx.strokeRect(snakeTrail[i].x * tileSize , snakeTrail[i].y* tileSize, tileSize, tileSize);

      //snake bites it's tail?
      if (snakeTrail[i].x == snakeX && snakeTrail[i].y == snakeY) {
        if(tailSize > 3) {
            endGame(tailSize);
        }
        tailSize = defaultTailSize;
      }
    }

    // paint apple
    ctx.fillStyle = "red";
    ctx.fillRect(appleX * tileSize, appleY * tileSize, tileSize, tileSize);

    //set snake trail
    snakeTrail.push({ x: snakeX, y: snakeY });
    while (snakeTrail.length > tailSize) {
      snakeTrail.shift();
    }
  }

  // input
  function keyDownEvent(e) {
    switch (e.keyCode) {
      case 37:
        nextX = -1;
        nextY = 0;
        break;
      case 38:
        nextX = 0;
        nextY = -1;
        break;
      case 39:
        nextX = 1;
        nextY = 0;
        break;
      case 40:
        nextX = 0;
        nextY = 1;
        break;
      case 32:
        if(gameActive == true) {
            pauseGame();
        }
        else {
            gameControl = startGame(x);
        }
        break;
    }
  }
</script>
`
@Ram895

This comment has been minimized.

Copy link

@Ram895 Ram895 commented Sep 23, 2020

i add some features like pausing the game and using localStorage to save the score
and also slowing little bit the snake .

<title>Snake Game</title> <script src="https://code.jquery.com/jquery-1.11.3.js"></script> <style> html, body { height: 100%; margin: 0; } body { background: black; display: flex; align-items: center; justify-content: center; } canvas { border: 1px solid white; background-color:gold; } #p1 { color:red; position:absolute; left:100px; top:10px; } #p2 { color:red; position:absolute; left:100px; top:30px; } #score { color:yellow; position:absolute; left:155px; top:10px; } #high { color:yellow; position:absolute; left:195px; top:30px; } #btn_stop { color:brown; position:absolute; left:100px; top:80px; } #end_msg { color:brown; position:absolute; left:100px; top:100px; } </style>

SCORE:

HIGHSCORE:

Stop Snake Game

<script> var canvas = document.getElementById('game'); var context = canvas.getContext('2d'); var grid = 16; var count = 0; var score=0; //reading last score value if(localStorage.score){ document.getElementById('score').innerHTML=localStorage.score; }

var max=0;

var snake = {
x: 160,
y: 160,

// snake velocity. moves one grid length every frame in either the x or y direction
dx: grid,
dy: 0,

// keep track of all grids the snake body occupies
cells: [],

// length of the snake. grows when eating an apple
maxCells: 4
};
var apple = {
x: 320,
y: 320
};

// get random whole numbers in a specific range
// @see https://stackoverflow.com/a/1527820/2124254
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}

// game loop
function loop() {

requestAnimationFrame(loop);
// slow game loop to 15 fps instead of 60 (60/15 = 4)
if (++count < 10) {
return;
}
count = 0;
context.clearRect(0,0,canvas.width,canvas.height);
// move snake by it's velocity
snake.x += snake.dx;
snake.y += snake.dy;
// wrap snake position horizontally on edge of screen
if (snake.x < 0) {
snake.x = canvas.width - grid;
}
else if (snake.x >= canvas.width) {
snake.x = 0;
}

// wrap snake position vertically on edge of screen
if (snake.y < 0) {
snake.y = canvas.height - grid;
}
else if (snake.y >= canvas.height) {
snake.y = 0;
}
// keep track of where snake has been. front of the array is always the head
snake.cells.unshift({x: snake.x, y: snake.y});
// remove cells as we move away from them
if (snake.cells.length > snake.maxCells) {
snake.cells.pop();
}
// draw apple
context.fillStyle = 'red';
context.fillRect(apple.x, apple.y, grid-1, grid-1);
// draw snake one cell at a time
context.fillStyle = 'green';
snake.cells.forEach(function(cell, index) {

// drawing 1 px smaller than the grid creates a grid effect in the snake body so you can see how long it is
context.fillRect(cell.x, cell.y, grid-1, grid-1);  
// snake ate apple
if (cell.x === apple.x && cell.y === apple.y) {
  snake.maxCells++;
  score+=1;
//saving score for next playing.
localStorage.setItem('score',score);
  //max=score;
  document.getElementById('score').innerHTML=score;

  // canvas is 400x400 which is 25x25 grids 
  apple.x = getRandomInt(0, 25) * grid;
  apple.y = getRandomInt(0, 25) * grid;
}
// check collision with all cells after this one (modified bubble sort)
for (var i = index + 1; i < snake.cells.length; i++)
{
  
  // snake occupies same space as a body part. reset game
  if (cell.x === snake.cells[i].x && cell.y === snake.cells[i].y) 
 { 
 
    if(score>max)
    {
     max=score;
    }
	snake.x = 160;
    snake.y = 160;
    snake.cells = [];
    snake.maxCells = 4;
    snake.dx = grid;
    snake.dy = 0;
	//score=0;
    apple.x = getRandomInt(0, 25) * grid;
    apple.y = getRandomInt(0, 25) * grid;
    document.getElementById('high').innerHTML=max;
  }
}

}
);
}
// listen to keyboard events to move the snake
document.addEventListener('keydown', function(e) {
// prevent snake from backtracking on itself by checking that it's
// not already moving on the same axis (pressing left while moving
// left won't do anything, and pressing right while moving left
// shouldn't let you collide with your own body)

// left arrow key
if (e.which === 37 && snake.dx === 0) {
snake.dx = -grid;
snake.dy = 0;
}
// up arrow key
else if (e.which === 38 && snake.dy === 0) {
snake.dy = -grid;
snake.dx = 0;
}
// right arrow key
else if (e.which === 39 && snake.dx === 0) {
snake.dx = grid;
snake.dy = 0;
}
// down arrow key
else if (e.which === 40 && snake.dy === 0) {
snake.dy = grid;
snake.dx = 0;
}
});
// start the game
requestAnimationFrame(loop);

function myFunction() {
document.getElementById('end_msg').innerHTML="";
alert('Press confirm to continue');
}

//stop playing
$(document).ready(function(){
$('#btn_stop').click(function(){
document.getElementById('end_msg').innerHTML="Game stoped by player" ;
setTimeout(myFunction, 1000);
});
});

</script>
@LuigiDude647

This comment has been minimized.

Copy link

@LuigiDude647 LuigiDude647 commented Oct 16, 2020

I know that this is old, but can someone make a version that works on apple script editor?

@Kingybu

This comment has been minimized.

Copy link

@Kingybu Kingybu commented Oct 20, 2020

Hey i made a own multiplayer game and id like to knew if its good. can you watch? Game 1 Game 2

@straker

This comment has been minimized.

Copy link
Owner Author

@straker straker commented Oct 21, 2020

@Kingybu those are some amazing games! Love the graphics and music. Great job.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.