Jump to content

How to move snake in snake game javascript html5 canvas?

shivajikobardan

https://codepen.io/pelko/pen/bGjZxJy

 

document.addEventListener("keydown", callback);
function callback(e) {
  let k = e.keyCode;
  if (k == 37 && d != "right") {
    d = "left";

    console.log(d);
  }
  if (k == 38 && d != "down") {
    d = "up"
    console.log(d);
  }
  if (k == 39 && d != "left") {
    d = "right"
    console.log(d);
  }
  if (k == 40 && d != "up") {
    d = "down"
    console.log(d);

  }
}

if left is pressed, snakeX should decrease by gridSize. 

snakeX=snakeX-gridSize

But what is snakeX? because I've made an array of objects for snake.

 

Link to comment
Share on other sites

Link to post
Share on other sites

I would assume that's the X coordinate of the snake's head. It needs to move to the left, so its X coordinate needs to decrease, assuming a coordinate system the goes left to right for X.

Remember to either quote or @mention others, so they are notified of your reply

Link to comment
Share on other sites

Link to post
Share on other sites

what variable would you increase and decrease is the question. @Eigenvektor can you show sample code?  I know the logic but don't know which variable to change as  I can't see that variable.

Link to comment
Share on other sites

Link to post
Share on other sites

snakeX is an imaginary variable. There is no snakeX in tht code. I am just making it up. Nb actually looked at the code...:(

Link to comment
Share on other sites

Link to post
Share on other sites

Snake size not getting increased after eating food:


Relevant code:

  if (food.x === snake[0].x && food.y === snake[0].y) {
    // increase the size of the snake
    snake.push({
      x: snake[snake.length - 1].x,
      y: snake[snake.length - 1].y

    });

where snake is an array of objects. Each object is x and y coordinates of snake position and food is an object with x and y coordinates randomly placed.

Here's the full code:
https://codepen.io/pelko/pen/bGjZxJy


 

Link to comment
Share on other sites

Link to post
Share on other sites

6 hours ago, shivajikobardan said:

snakeX is an imaginary variable. There is no snakeX in tht code. I am just making it up. Nb actually looked at the code...:(

That's not a good way to ask such a question. We're not going to write the code for you. Show the code you have, then ask a specific question about it. Since you were talking about a variable that didn't exist, I could only tell you what such a variable name might be referring to.

 

The reason your snake doesn't seem to get any longer is that the new element initially has the exact same position as the head's current position. Notice how a red dot replaces the first yellow dot you eat? Afterwards you're placing every new dot at exactly the same position. You're also only ever updating the position of the snake's head (snake[0]).

 

Here's how I'd do it:

Whenever your snake moves, insert a new element at the start of the array, then remove its last element. When your snake eats something, skip the "remove" for one turn. This way you don't have to update the position of every element in the array. (fyi, I tried this approach and it works)

Remember to either quote or @mention others, so they are notified of your reply

Link to comment
Share on other sites

Link to post
Share on other sites

if (food.x === snake[0].x && food.y === snake[0].y) {
    // increase the size of the snake
    snake.unshift({
      x: snake[snake.length - 1].x,
      y: snake[snake.length - 1].y

    });

    snake.pop();
    
    // generate a new random position for the food
    food = {
      x: Math.floor(Math.random() * 10 + 1) * gridSize,
      y: Math.floor(Math.random() * 10 + 1) * gridSize
    };
  }

I tried this code, doesn't work. Please show the code you tried.

Link to comment
Share on other sites

Link to post
Share on other sites

just humble request, is it illegal to share the code in this forum or something? I've tried a lot and failed. So, would not it be good to share the code with me now? Or is stackoverflow the only place?
Those who are willing to learn will still learn even if you share code, those unwilling to learn won't even if you don't. Not sharing code in a programming problem where someone has gave that much try is just funny.

Link to comment
Share on other sites

Link to post
Share on other sites

3 hours ago, shivajikobardan said:

I tried this code, doesn't work. Please show the code you tried.

As I said above, instead of moving the snake, always increase its size (in the direction it is moving), then remove the last element, unless it has eaten something. Right now you're only adding an element when it has eaten something, but still only moving its head.

 

 

It is not illegal to share code, but if you're learning it's usually better if you figure out the problem yourself. In any case, here's my implementation.

 

Spoiler
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');

let gridSize = 32;

let food = {
  x: Math.floor(Math.random() * 10 + 1) * gridSize,
  y: Math.floor(Math.random() * 10 + 1) * gridSize
}

let snake = [
  {
    x: 10 * gridSize,
    y: 10 * gridSize
  }
]
function draw() {
  // add a new element based on the direction
  if (moveX || moveY) {
    snake.unshift({
      x: snake[0].x + moveX,
      y: snake[0].y + moveY,
    });
  }

  if (food.x === snake[0].x && food.y === snake[0].y) {
    // generate a new random position for the food
    food = {
      x: Math.floor(Math.random() * 10 + 1) * gridSize,
      y: Math.floor(Math.random() * 10 + 1) * gridSize
    };
  } else if (snake.length > 1) {
    // remove the last element (if moving), unless the snake ate something
    snake.pop();
  }
  
  // clear canvas
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  
  // food draw
  ctx.fillStyle = "yellow";
  ctx.fillRect(food.x, food.y, gridSize, gridSize);

  for (let i = 0; i < snake.length; i++) {
    // snake draw
    ctx.fillStyle = "red";
    ctx.fillRect(snake[i].x, snake[i].y, gridSize, gridSize);
  }
}

setInterval(draw, 150);

let moveX = 0;
let moveY = 0;
document.addEventListener("keydown", callback);
function callback(e) {
  let k = e.keyCode;

  if (k == 37 && moveX != gridSize) {
    moveX = -gridSize
    moveY = 0
  } else if (k == 38 && moveY != gridSize) {
    moveX = 0
    moveY = -gridSize
  } else if (k == 39 && moveX != -gridSize) {
    moveX = gridSize
    moveY = 0
  } else if (k == 40 && moveY != -gridSize) {
    moveX = 0
    moveY = gridSize
  }
}

 

 

Remember to either quote or @mention others, so they are notified of your reply

Link to comment
Share on other sites

Link to post
Share on other sites

hmm i didn't ask for your implementation. that'd take you lot of time. thank you for doing it though. but i want to solve it using my code.

Link to comment
Share on other sites

Link to post
Share on other sites

2 hours ago, shivajikobardan said:

hmm i didn't ask for your implementation. that'd take you lot of time. thank you for doing it though. but i want to solve it using my code.

I already posted my implementation in the spoiler. It modifies your code to work as expected.

 

The main changes I mentioned:

  • Add a new element to the snake's array every frame. You're only doing it when the snake ate something.
  • Remove the last element every frame, unless the snake ate something.

The key issue with your implementation is that you're only updating snake[0] x and y. As soon as your snake has more elements, that is not enough. You would need to update the position of every element.

 

Right now you're always adding new elements at the position the snake first ate something, then never updating the position of these elements.

Remember to either quote or @mention others, so they are notified of your reply

Link to comment
Share on other sites

Link to post
Share on other sites

The movement of the snake can be done by changing the coordinates of each node / cell / element  / whatever you want to call it of the snake.

for example let's say the snake has 3 pieces and it's one cell away from the left side of the play area

 

|   | H | B1 | B2 |  .... .

 

H is head, snake[0] , B1 and B2 are body parts, snake[1] and snake[2]

So if you move left, B1 will receive H's coordinates, and B2 will receive B1 coordinates, so you can start from the back and go towards the front

(not javascript)

for i = 2 to 1 

  snake[ i ].x = snake[i-1].x

  snake[ i ].y = snake[i-1].y

next i

snake[0].x and snake[0].y get the position of the cell

if user hit left or right, that would be x = snake[1].x -/+ 1 and y would be same as snake[1].y because you don't move vertically

if you go up/down same deal but with y, up means decrease, down is increase y

 

when you increase snake size, you could do it without unshift. Just add one node to the end with same x,y as the previous element and do the same updating of all cells' x and y like above

Link to comment
Share on other sites

Link to post
Share on other sites

49 minutes ago, mariushm said:

The movement of the snake can be done by changing the coordinates of each node / cell / element  / whatever you want to call it of the snake.

for example let's say the snake has 3 pieces and it's one cell away from the left side of the play area

If you look at my working solution (in the spoiler above), it can be done without changing coordinates at all. Insert a new element at the start of the list, pop the last element. No need to iterate over the list at all. If memory churn becomes an issue, it could be optimized by using a linked list instead, where you unlink the last element and re-use it as the first one.

Remember to either quote or @mention others, so they are notified of your reply

Link to comment
Share on other sites

Link to post
Share on other sites

It's more difficult to understand by a beginner (and he is a beginner) and in real world, it's so few cpu cycles that it doesn't really matter.

 

Anyway, to add more to this thread, all the code in your first post just updates the d variable every time a key is pressed

Somewhere else in your code, there's probably a function which runs every so many seconds or milliseconds and does the update on screen. It uses the direction to move the snake towards that direction, if possible (if there's a wall or the snake itself, game over)

So the function should determine where the snake head would move next, and then check if that cell defined by a x and y coordinates is a wall or part of the snake. If one of these conditions is met, you end the game or reset the game if you make a game that runs forever.

 

Optionally, you could add a mode where the snake doesn't die when it hits the walls, but instead pops on the opposite side of the game area. It's just a different sets of checks.

 

Link to comment
Share on other sites

Link to post
Share on other sites

9 minutes ago, mariushm said:

It's more difficult to understand by a beginner (and he is a beginner) and in real world, it's so few cpu cycles that it doesn't really matter.

Movement is actually much easier to figure out that way, because you really only need to think about where the head needs to move and you can completely forget about updating the other cells. Just add a new cell at the start of the list with the correct position, then remove the tail (and skip removing the tail when when you hit food)

 

The optimization with the d variable is already in the code I changed…

Remember to either quote or @mention others, so they are notified of your reply

Link to comment
Share on other sites

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×