Reputation: 5429
I am trying to create a simple snake game.
(function() {
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
x = 0,
y = 0,
speed = 2;
x_move = speed,
y_move = 0,
food_position_x = Math.floor(Math.random() * canvas.width / 10) * 10,
food_position_y = Math.floor(Math.random() * canvas.height / 10) * 10,
size_x = 10;
function eat() {
console.log('food_x:' + food_position_x + ' x:' + x + ' / food_y:' + food_position_y + ' y:' + y);
if (Math.floor(y / 10) * 10 == food_position_y && Math.floor(x / 10) *10 == food_position_x) {
size_x += 2;
//throw new Error("MATCH!"); // This is not an error. Just trying to stop the script
}
}
// Drawing
function draw() {
eat();
requestAnimationFrame(function() {
draw();
});
// Draw the snake
ctx.beginPath();
ctx.rect(Math.floor(x/10)*10, Math.floor(y/10)*10, size_x, 10);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#ffffff';
ctx.fill();
ctx.closePath();
// Draw the food
ctx.beginPath();
ctx.rect(Math.floor(food_position_x/10)*10, Math.floor(food_position_y/10)*10, 10, 10);
ctx.fillStyle = "blue";
ctx.fill();
ctx.closePath();
// Increase the value of x and y in order to animate
x = x + x_move;
y = y + y_move;
}
draw();
// Key Pressing
document.addEventListener('keydown', function(event) {
switch(event.keyCode) {
case 40: // Moving down
if (x_move != 0 && y_move != -1) {
x_move = 0;
y_move = speed;
}
break;
case 39: // Moving right
if (x_move != -1 && y_move != 0) {
x_move = speed;
y_move = 0;
}
break;
case 38: // Moving top
if (x_move != 0 && y_move != 1) {
x_move = 0;
y_move = -speed;
}
break;
case 37: // Moving left
if (x_move != 1 && y_move != 0) {
x_move = -speed;
y_move = 0;
}
break;
}
});
})();
canvas { background-color: #000022 }
<canvas id="canvas" width="400" height="400"></canvas>
The problem
Every time when I catch the food, the snake becomes longer but when you press the down or up key, it moves horizontally.
Maybe a solution
This is what I believe the solution could be: The snake should be an array! Every time when the key is pressed, define the position of HEAD of snake and move the snake step by step, because it is an array. So the body follows the head. But in this case, I have no idea how to make an array from it.
Maybe there are other solutions. Any helps would be appreciated!
Upvotes: 23
Views: 684
Reputation:
I make the game using C++ soi can advice make a new object for every snake tile and on move set it to parent position
function Tile(x, y)
{
this.x = x;
this.y = y;
}
Upvotes: 1
Reputation: 1286
Have a length variable and make that the x or y size based on direction, like this:
(function() {
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
x = 0,
y = 0,
speed = 2,
x_move = speed,
y_move = 0,
food_position_x = Math.floor(Math.random() * canvas.width / 10) * 10,
food_position_y = Math.floor(Math.random() * canvas.height / 10) * 10,
size_x = 10,
size_y = 10,
snake_length = 10;
function eat() {
console.log('food_x:' + food_position_x + ' x:' + x + ' / food_y:' + food_position_y + ' y:' + y);
if (Math.floor(y / 10) * 10 == food_position_y && Math.floor(x / 10) *10 == food_position_x) {
snake_length += 2;
//throw new Error("MATCH!"); // This is not an error. Just trying to stop the script
}
}
// Drawing
function draw() {
eat();
requestAnimationFrame(function() {
draw();
});
// Draw the snake
ctx.beginPath();
ctx.rect(Math.floor(x/10)*10, Math.floor(y/10)*10, size_x, size_y);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#ffffff';
ctx.fill();
ctx.closePath();
// Draw the food
ctx.beginPath();
ctx.rect(Math.floor(food_position_x/10)*10, Math.floor(food_position_y/10)*10, 10, 10);
ctx.fillStyle = "blue";
ctx.fill();
ctx.closePath();
// Increase the value of x and y in order to animate
x = x + x_move;
y = y + y_move;
}
draw();
// Key Pressing
document.addEventListener('keydown', function(event) {
switch(event.keyCode) {
case 40: // Moving down
if (x_move != 0 && y_move != -1) {
x_move = 0;
y_move = speed;
size_x = 10;
size_y = snake_length;
}
break;
case 39: // Moving right
if (x_move != -1 && y_move != 0) {
x_move = speed;
y_move = 0;
size_x = snake_length;
size_y = 10;
}
break;
case 38: // Moving top
if (x_move != 0 && y_move != 1) {
x_move = 0;
y_move = -speed;
size_x = 10;
size_y = snake_length;
}
break;
case 37: // Moving left
if (x_move != 1 && y_move != 0) {
x_move = -speed;
y_move = 0;
size_x = snake_length;
size_y = 10;
}
break;
}
});
})();
canvas { background-color: #000022 }
<canvas id="canvas" width="400" height="400"></canvas>
Upvotes: 1
Reputation: 3277
Well as I had some free time to spare I created my own JS snake to demonstrate you how it can be done. Most important parts are in this.snakeBody where array of body is stored and this.moveForward() where you can see how body is updated.
https://jsfiddle.net/nooorz24/p8xtdv3h/13/
moveForward: function() {
var next = this.getNextfieldValue();
if (next == "frame" || next == "body") {
console.log("You lose!")
this.isAlive = false;
} else {
var newHead = this.getNextfieldCoords();
this.draw.snake(newHead.x, newHead.y);
this.body.unshift(newHead);
if (next == "food") {
this.generateFood();
this.snakeSize++;
} else {
var last = this.body.pop();
this.draw.empty(last.x, last.y);
}
}
},
I tried to make it as readable as I could, but note that this is unfinished example and would need need loads of improvements to be a playable game
Upvotes: 7
Reputation: 2899
To debug your down or up problem, I would add some console.log('message') calls in your code for debugging.
Specifically, add some console messages in the switch statement so that you know the correct event and branch is firing. For Example:
switch(event.keyCode) {
case 40:
console.log('down');
...
case 39:
console.log('right');
...
}
Then add more and more debugging log messages until you find your problem.
You can view the console messages in the F12 developer tools in your browser of choice while running your game.
Also make sure you are not calling ctx.translate(...) on the canvas context to flip the canvas, this would change the direction of the x and/or y axis.
Upvotes: 0
Reputation: 17556
You need to maintain an array
of the points currently occupied by the snake body, and add new point (unshift
) to the array as the snake approaches and remove point from the back of the array (pop
). The following code is a starter, you need to make it your own :).
(function () {
const COLORS={ SNAKE:'#ff7bf5', FOOD:'blue' };
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d');
var snake=[], score=0;
var x, y, food_position_x, food_position_y, x_move, y_move;
var frameCount=0, framesRequiredToMove=10;
//the less the framesToMove the faster the sname moves
function draw(){
if(++frameCount==framesRequiredToMove){
frameCount=0;
move();
}
requestAnimationFrame(draw);
}
function init(){
snake = [{x:3,y:0},{x:2,y:0},{x:1,y:0},{x:0,y:0}];
snake.forEach((p)=>{plot(p.x,p.y,COLORS.SNAKE)})
x=snake[0].x;y=snake[0].y;
score=0;x_move=1;y_move=0;
scoreboard.innerText=score;
newfood();
setTimeout(draw,1000);
}
function plot(x,y,color){
ctx.beginPath();
ctx.rect(x * 10, y * 10, 10, 10);
ctx.fillStyle = color;
ctx.fill();
ctx.closePath();
}
function move(){
snakepx.innerText = x;
snakepy.innerText = y;
x = x + x_move;
y = y + y_move;
// Advance The Snake
plot(x,y,COLORS.SNAKE);
snake.unshift({x:x,y:y});
// Check food encounter
if(x==food_position_x && y==food_position_y){
scoreboard.innerText=++score;
newfood();
}
else{
var last=snake.pop();
ctx.clearRect(last.x * 10, last.y * 10, 10, 10);
}
}
function newfood(){
food_position_x=Math.floor(Math.random() * canvas.width / 10);
food_position_y=Math.floor(Math.random() * canvas.height / 10);
plot(food_position_x,food_position_y,COLORS.FOOD);
foodpx.innerText = food_position_x;
foodpy.innerText = food_position_y;
}
init();
// Key Pressing
document.addEventListener('keydown', function (event) {
event.preventDefault();
switch (event.keyCode) {
case 40: // Moving down
if (x_move != 0 && y_move != -1) {
x_move = 0;
y_move = 1;
}
break;
case 39: // Moving right
if (x_move != -1 && y_move != 0) {
x_move = 1;
y_move = 0;
}
break;
case 38: // Moving top
if (x_move != 0 && y_move != 1) {
x_move = 0;
y_move = -1;
}
break;
case 37: // Moving left
if (x_move != 1 && y_move != 0) {
x_move = -1;
y_move = 0;
}
break;
}
});
})();
canvas {
background-color: #000022;
float: left;
}
<canvas id="canvas" width="400" height="180"></canvas>
<div style="margin-left: 410px">
Snake: (<span id="snakepx"></span>, <span id="snakepy"></span>)<br>
Food: (<span id="foodpx"></span>, <span id="foodpy"></span>)<br>
Score: <span id="scoreboard"></span>
</div>
Upvotes: 12
Reputation: 49
I think that you have hit on the answer with an array. In the past, I have found that Snake works best with an array, tracking each block of the snake and checking for any two blocks being in the same position. For movement, however, you must directly control the head, and have the body follow based on the position of the array space one ahead of it. The snake head would be the first item in the array. I am not sure what you mean about not understanding the implementation of the array, but the coordinates for each block would be an item in the array.
Upvotes: 3