- Home /
2D Snake Movement
Hi guys, I'm trying to make simple 2d snake clone. My problem is about snake movement, here is my movement code
private void Movement2()
{
if (Input.GetKeyDown(KeyCode.W))
{
if(direction != Vector3.down)
direction = Vector3.up;
}
if (Input.GetKeyDown(KeyCode.S) )
{
if(direction != Vector3.up)
direction = Vector3.down;
}
if (Input.GetKeyDown(KeyCode.A) )
{
if(direction != Vector3.right)
direction = Vector3.left;
}
if (Input.GetKeyDown(KeyCode.D) )
{
if(direction != Vector3.left)
direction = Vector3.right;
}
if (timer >= timetogo)
{
this.transform.position = new Vector3(Mathf.Round(this.transform.position.x) + direction.x,Mathf.Round(this.transform.position.y) + direction.y) ;
timer = 0;
}
}
problem is as you know snake can't move opposite direction but whenever I press 2 inputs same time it can move, if I press one by one It can't.
So any idea will be helpful, thank you.
Answer by Earthshine · Jun 06, 2021 at 11:50 AM
Easiest way to solve the problem without dramatically changing your code would be changing all the if
s except the first one in outer layer of the if statement sequence to else if
s. I would also bring conditions from the inner layer of if statements to the outer layer and check for direction that matches the input too. Like this:
if (Input.GetKeyDown(KeyCode.W) && direction != Vector3.down && direction != Vector3.up)
{
direction = Vector3.up;
}
else if(Input.GetKeyDown(KeyCode.S) && direction != Vector3.down && direction != Vector3.up)
{
direction = Vector3.down;
}
else if(Input.GetKeyDown(KeyCode.A) && direction != Vector3.right && direction != Vector3.left)
{
direction = Vector3.left;
}
else if(Input.GetKeyDown(KeyCode.D) && direction != Vector3.right && direction != Vector3.left)
{
direction = Vector3.right;
}
Edit: blocking simultaneous inputs didn't solve the problem however. It became clear that the main issue is that the game passes input to direction
more often than it should.
This is the actual answer: You call Movement2()
in Update()
every frame and pass new value to direction
every frame. Then when time is >= timetogo the snake moves in direction
direction.
It means you can feed several inputs to snake between two moves. It shouldn't even be simultaneous to pass. And it may be opposite to previous direction if there is an allowed input between the previous move and previously unallowed input.
It can be fixed by adding another variable for the next direction so the direction
variable is constant between moves. It should work like this:
if (Input.GetKeyDown(KeyCode.W) && direction != Vector3.down && direction != Vector3.up)
{
nextDirection = Vector3.up;
}
else if(Input.GetKeyDown(KeyCode.S) && direction != Vector3.down && direction != Vector3.up)
{
nextDirection = Vector3.down;
}
else if(Input.GetKeyDown(KeyCode.A) && direction != Vector3.right && direction != Vector3.left)
{
nextDirection = Vector3.left;
}
else if(Input.GetKeyDown(KeyCode.D) && direction != Vector3.right && direction != Vector3.left)
{
nextDirection = Vector3.right;
}
if (timer >= timetogo)
{
direction = nextDirection;
this.transform.position = new Vector3(Mathf.Round(this.transform.position.x) + direction.x,Mathf.Round(this.transform.position.y) + direction.y) ;
timer = 0;
}
thanks for answering, I already tried to else if statemant but result was same as here, now I tried to your code but still not working.
What exactly do you mean by still not working? The next if else
condition wouldn't even be checked in case the previous one were met. It makes me think there's another error outside of Movement2()
function. I'll test the script several hours later to be sure.
In classic snake the level is divided into squares and the game listens for the input once every time the snake's head moves to the next square. Is it the case in your project?
I mean its still have that bug, if snake moving right side, I press "S" and "A" same time and snake moves to left side.
Movement2 there is no error.
not exactly, but I made up something like that, I mean my player moves one by one and borders line is x 10 y 10.
Answer by DenisIsDenis · Jun 07, 2021 at 10:39 AM
As I understand it, it is necessary that the snake cannot turn more than 90 degrees in one step. To do this, you need to introduce a variable that will store the last direction of movement of the snake. Also we need to modify the conditions.
Sample code:
Vector3 lastDirection = Vector3.up; // "Vector3.up" if the snake looks up at the start
private void Movement2()
{
if (Input.GetKeyDown(KeyCode.W) && Vector3.Angle(Vector3.up, lastDirection) == 90)
{
direction = Vector3.up;
}
if (Input.GetKeyDown(KeyCode.S) && Vector3.Angle(Vector3.down, lastDirection) == 90)
{
direction = Vector3.down;
}
if (Input.GetKeyDown(KeyCode.A) && Vector3.Angle(Vector3.left, lastDirection) == 90)
{
direction = Vector3.left;
}
if (Input.GetKeyDown(KeyCode.D) && Vector3.Angle(Vector3.right, lastDirection) == 90)
{
direction = Vector3.right;
}
if (timer >= timetogo)
{
lastDirection = direction;
this.transform.position = new Vector3((int)this.transform.position.x + direction.x,
(int)this.transform.position.y + direction.y);
timer = 0;
}
}
By the way, using (int)
is easier than using Mathf.Round ()
and differs slightly in this case.
Your answer
Follow this Question
Related Questions
Enemy shakes on Y-axis when is moving straight on the X-axis 0 Answers
Unity 2D movement and rotate sprite to the direction it is moving in 1 Answer
Player Movement doesn't work, but Debug.Log shows that it should 1 Answer
How do i make a cube move (Continuosly without stopping) when i press a button once in unity 2D 2 Answers
How To Make a Snake-like Movement without Food ? [UNITY 2D] 1 Answer