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.

Easiest way to solve the problem without dramatically changing your code would be changing all the ifs except the first one in outer layer of the if statement sequence to else ifs. 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;
 }

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.