2d GameObject moving through a grid code improvements

I have a code that moves a 2d sprite efficiently through a grid using Keyboard inputs.
it works, however, it uses around 300 lines of code. Is there a way to improve the code or at least better?

public enum PlayerDirection
{
  facingUp = 1,
  facingRight,
  facingDown,
  facingLeft,
}
public class PlayerController : MonoBehaviour
{   
  [SerializeField] float movementInputX;
  [SerializeField] float movementInputY;
  
    Vector2 movementX;
    Vector2 movementY;
public float speed = 1;
private int lineDirectionValue = (int) PlayerDirection.facingDown;
public float gridSnap = 0.9f;


    // Start is called before the first frame update+
    private void Awake() 
    {
        
    }
    private void Start()
    {
     
    }
    private void Update()
    {
      movementInputX = Input.GetAxisRaw("Horizontal");
      movementInputY = Input.GetAxisRaw("Vertical");
        movementX = new Vector2(movementInputX, 0);
        movementY = new Vector2(0, movementInputY);
     LineDirectionValue();
     LineDirectionGizmo();
     //GridCorrection();
    }
    private void FixedUpdate()
    {
     Movement();
     IsOnHorizontalGrid();
     IsOnVerticalGrid();
     Debug.Log(Mathf.Abs(transform.position.x % 1) + "," + Mathf.Abs(transform.position.y % 1));
    }
    
    private void Movement()
    {
      Vector2 gridCorrection = transform.position;
        if(IsFacingUp() && IsOnVerticalGrid())
        {
          if(movementInputY == 1 || movementInputX != 0)
          {
         transform.Translate(Vector2.up * speed * Time.deltaTime);
         
        }
        if(gridSnap < Mathf.Abs(gridCorrection.y % 1) && transform.position.y >= 0)
         {
          gridCorrection.y = Mathf.Round(gridCorrection.y);
          transform.position = gridCorrection;
         }
         else if((1 - gridSnap) > Mathf.Abs(gridCorrection.y % 1) && (gridCorrection.y % 1) != 0 && transform.position.y < 0)
         {
          gridCorrection.y = Mathf.Round(gridCorrection.y);
          transform.position = gridCorrection;
         }
        }

        else if(IsFacingRight() && IsOnHorizontalGrid())
        {
          if(movementInputY != 0 || movementInputX == 1)
          {
         transform.Translate(Vector2.right * speed * Time.deltaTime);
        }
        if(gridSnap < Mathf.Abs(gridCorrection.x % 1) && transform.position.x >= 0)
         {
          gridCorrection.x = Mathf.Round(gridCorrection.x);
          transform.position = gridCorrection;
         }
         else if((1 - gridSnap) > Mathf.Abs(gridCorrection.x % 1) && (gridCorrection.x % 1) != 0 && transform.position.x < 0)
         {
          gridCorrection.x = Mathf.Round(gridCorrection.x);
          transform.position = gridCorrection;
         }
        }
        
        else if(IsFacingDown() && IsOnVerticalGrid())
        {
          if(movementInputY == -1 || movementInputX != 0)
          {
         transform.Translate(Vector2.down * speed * Time.deltaTime);
        }
        if((1 - gridSnap) > Mathf.Abs(gridCorrection.y % 1) && (gridCorrection.y % 1) != 0 && transform.position.y >= 0)
         {
          gridCorrection.y = Mathf.Round(gridCorrection.y);
          transform.position = gridCorrection;
         }
         else if(gridSnap < Mathf.Abs(gridCorrection.y % 1) && transform.position.y < 0)
         {
          gridCorrection.y = Mathf.Round(gridCorrection.y);
          transform.position = gridCorrection;
         }
        }

        else if(IsFacingLeft() && IsOnHorizontalGrid())
        {
          if(movementInputY != 0 || movementInputX == -1)
          {
         transform.Translate(Vector2.left * speed * Time.deltaTime);
         }
        if((1 - gridSnap) > Mathf.Abs(gridCorrection.x % 1) && (gridCorrection.x % 1) != 0 && transform.position.x >= 0)
         {
          gridCorrection.x = Mathf.Round(gridCorrection.x);
          transform.position = gridCorrection;
         }
         else if(gridSnap < Mathf.Abs(gridCorrection.x % 1) && transform.position.x < 0)
         {
          gridCorrection.x = Mathf.Round(gridCorrection.x);
          transform.position = gridCorrection;
         }
        }
    }
    
    private void GridCorrection()
    {
      Vector2 gridCorrection = transform.position;
      if(IsOnHorizontalGrid() == false)
      {
        gridCorrection.y = Mathf.Round(gridCorrection.y);
        transform.position = gridCorrection;
      }
      if(IsOnVerticalGrid() == false)
      {
        gridCorrection.x = Mathf.Round(gridCorrection.y);
        transform.position = gridCorrection;
      }
    }
    private bool IsOnVerticalGrid()
    {
        if(transform.position.x % 1 != 0)
        {
            //Debug.Log("Is not Y grid");
            return false;
        }
        else
        {
            //Debug.Log(" Is on Y grid");
            return true;
        }
     }   
     private bool IsOnHorizontalGrid()
    {
      if(transform.position.y % 1 != 0)
        {
            //Debug.Log("Is not X grid");
            return false;
        }
        else
        {
            //Debug.Log(" Is on X grid");
            return true;
        }
    }
    
private void LineDirectionValue()
{
  switch(movementInputX, movementInputY)
  {
   case(0,1):
   if(IsOnVerticalGrid())
   {
   lineDirectionValue = (int)PlayerDirection.facingUp;
   }
   break;
   case(1,1):
   if(IsOnVerticalGrid())
   {
   lineDirectionValue = (int) PlayerDirection.facingUp;
   }
   else if(IsOnHorizontalGrid())
   {
    lineDirectionValue = (int) PlayerDirection.facingRight;
   }
   break;
   case(1,0):
   if(IsOnHorizontalGrid())
   {
   lineDirectionValue = (int)PlayerDirection.facingRight;
   }
   break;
   case(1,-1):
   if(IsOnHorizontalGrid())
   {
   lineDirectionValue = (int)PlayerDirection.facingRight;
   }
   else if(IsOnVerticalGrid())
   {
    lineDirectionValue = (int)PlayerDirection.facingDown;
   }
   break;
   case(0,-1):
   if(IsOnVerticalGrid())
   {
   lineDirectionValue = (int)PlayerDirection.facingDown;
   }
   break;
   case(-1,-1):
   if(IsOnHorizontalGrid())
   {
   lineDirectionValue = (int)PlayerDirection.facingLeft;
   }
   else if(IsOnVerticalGrid())
   {
   lineDirectionValue = (int)PlayerDirection.facingDown;
   }
   break;
   case(-1,0):
   if(IsOnHorizontalGrid())
   {
   lineDirectionValue = (int)PlayerDirection.facingLeft;
   }
   break;
   case(-1,1):
   if(IsOnHorizontalGrid())
   {
   lineDirectionValue = (int)PlayerDirection.facingLeft;
   }
   else if(IsOnVerticalGrid())
   {
   lineDirectionValue = (int)PlayerDirection.facingUp;
   }
   break;
  }
}

private bool IsFacingUp()
{
 if(IsOnVerticalGrid())
 {
  if(lineDirectionValue == (int)PlayerDirection.facingUp)
  {
    //Debug.Log("Is facing up");
    return true;
  }
  else
  {
    return false;
  }
 }
 else
{
  return false;
}
}
private bool IsFacingRight()
{
 if(IsOnHorizontalGrid())
 {
  if(lineDirectionValue == (int)PlayerDirection.facingRight)
  {
    //Debug.Log("Is facing right");
    return true;
  }
  else
  {
    return false;
  }
 }
 else
{
  return false;
}
}

private bool IsFacingDown()
{
 if(IsOnVerticalGrid())
 {
  if(lineDirectionValue == (int)PlayerDirection.facingDown)
  {
    //Debug.Log("Is facing down");
    return true;
  }
  else
  {
    return false;
  }
 }
 else
{
  return false;
}
}
private bool IsFacingLeft()
{
 if(IsOnHorizontalGrid())
 {
  if(lineDirectionValue == (int)PlayerDirection.facingLeft)
  {
    //Debug.Log("Is facing left");
    return true;
  }
  else
  {
    return false;
  }
 }
 else
{
  return false;
}
}

private void LineDirectionGizmo()
{
  if(IsFacingUp())
  {
   Debug.DrawRay(transform.position, Vector2.up);
  }
  else if(IsFacingRight())
  {
   Debug.DrawRay(transform.position, Vector2.right);
  }
  else if(IsFacingDown())
  {
   Debug.DrawRay(transform.position, Vector2.down);
  }
  else if(IsFacingLeft())
  {
   Debug.DrawRay(transform.position, Vector2.left);
  }
}
}

*make it better?
typo.

oops. I left the unused “gridcorrection” function in. ignore that :slight_smile:

I dont even know where to begin with this. This is some yandare-dev level of if else statement use. If I were you I would spend some time reimagining this system. Instead of checking “Are we on the grid, are we moving down?”

I would create a vector 2, check if we can move up, if we can move up we set the y to whatever velocity you want (By multiplying the vertical input by whatever factors you want). Then do the same for x. At the end of the fixedUpdate we just apply that to our character.

also,I dont think you need to be rounding the gridcorrection every time and then applying it to our transform every step. Why dont you wait till the very end to round and apply the transform?

also, why arent you just getting the rotation of the character and casting in that exact direction?

I am already making improvements.
but I don’t know what you mean in the 2nd paragraph. How would that make player to move efficiently through unity’s grid gizmo? (I am making a top down maze game). Also I meant to put tag this as beginner instead of intermediate. my bad.

Because I don’t know how to rotate the 2d Object’s sprite and not the GameObject itself. rotating the object messes up movements. I am still making improvements.

Make an empty object . This class holds your movement. its rotation will never change.

Then move your character with the sprite to be a child of that empty object. It will inheret the movement, but you can just reference its rotation whenever you want to. Now, you can rotate your child object and it doesnt mess up your movement, but it will rotate the sprite.

A sprite is not a component, its an asset. You cannot change the rotation of a sprite. You can however change the rotation of what it is attatched to.

wow… it was that obvious. I am facepalming myself right now. Thanks!

happens to everyone constantly. To get better at C#/Unity, you need to literally start thinking of everything in terms of objects, and properties. Everything (almost everything) in unity acts as an object you can reference.

If you have any other questions, Im constantly on this topic (Trying to steal ideas from people).

using UnityEngine;
public class GridMovement : MonoBehaviour   // Move and restrict an object to a grid with a 1 meter cell size
{   
float speed=5;
Vector3 last; // last input direction. 
    void Update()
    {
        Vector3 move=new Vector3(Input.GetAxisRaw("Horizontal"),Input.GetAxisRaw("Vertical"),0);
        Vector3 pos=transform.position;
        if ((Mathf.Abs(pos.y%1)>0.1f && Mathf.Abs(pos.y%1)<0.9f)) // not at a vertical intersection?
        {
            if (move.x!=0 && move.y==0) // trying to move across a cell?
                move.y=last.y;  // divert and continue to move vertically along the edge
            move.x=0;
            pos.x=Mathf.Round(pos.x); // snap to the edge
        }
        if ((Mathf.Abs(pos.x%1)>0.1f && Mathf.Abs(pos.x%1)<0.9f)) // not at a horizontal intersection?
        {
            if (move.y!=0 && move.x==0)
                move.x=last.x;
            move.y=0;
            pos.y=Mathf.Round(pos.y);
        }
        transform.position=pos;
        
        if (move.x!=0)
            last.x=move.x;
        if (move.y!=0)
            last.y=move.y;
        
        transform.Translate(move*speed*Time.deltaTime,Space.World);
    }
}

I knew it had to be simple. Appreciate it!

Although, there is odd behavior in which the object could goes into the grid, but i’ll fix it.

Congratulations on recognizing this might be unusual. Yes, it’s a bit excessive, particularly from violating “Don’t Repeat Yourself” (DRY) principles…

Here is my reference move-in-a-2-grid reference, for what I consider “moving in a 2D grid.” Your idea of it may be fundamentally different, eg, something like Bomberman, for instance.

Most of those lines are comments explaining what is going on, how to extend it, etc…

Full setup available in the repo itself if you clone it.

1 Like

If wanting to lerp in 1 meter steps:

using UnityEngine;
public class GridMovement : MonoBehaviour   // Move and restrict an object to a grid with a 1 meter cell size
{   
float speed=5;
Vector2 goal;
	void Update()
	{
        if (Vector3.Distance(transform.position,goal)<0.01f) // are we nearly there yet?
            goal+=new Vector2(Input.GetAxisRaw("Horizontal"),Input.GetAxisRaw("Vertical"));
        Vector2 newGoal=goal;
        Vector2 dir=(goal-(Vector2)transform.position);
        if (dir.x!=0 && dir.y!=0) // final goal on a diagonal?
            newGoal.y=transform.position.y; // temporarily adjust the goal so we move horizontally towards the next available grid position before moving on to the final goal 
        transform.position=Vector3.MoveTowards(transform.position,newGoal,speed*Time.deltaTime);
	}
}