[Long Post] Constant linear movement in a 2d array grid with auto-turning on detecting a wall

I’m using a 2d array grid for my level with each grid assigned a value of either 0 (walkable grid) or 1 (unwalkable grid/wall). Every time an input button is pressed, it initiates a continuous movement in that respective direction, until it is supposed to turn to its’ right. This is pretty reminescent of Snake or Pacman.
I have managed to get the gist of the movement to work, however it is not optimized. The straight direction that it moves in, happens very fast. The object stops when it comes against an unwalkable grid instead of turning. Only when the input key is pressed then, that it detects the unwalkable grid and takes a turn.
If possible, it would be great if someone could take a look at my project [33238-gridmovement.zip|33238]

or if you wish to check my code, here it is

using UnityEngine;
using System.Collections;
using DG.Tweening;
using System.Collections.Generic;

public class Player : MonoBehaviour {
	
	const float TweenWpDuration = 0.2f;
	
	public GameObject levelCreator_;
	levelCreator temp;
	Vector3 playerPos;
	
	int[,] mapArray = new int[13,17];
	
	public bool inhibitPlayerInput;

	void Start () {
		DOTween.Init(true, true, LogBehaviour.Verbose).SetCapacity(6000, 6000);

		levelCreator_ = GameObject.Find ("LevelCreatorGameObject");
		temp = levelCreator_.gameObject.GetComponent<levelCreator>();
		mapArray = temp.mapArray;
		for(int i = 1; i<12; i++)
		{
			for(int ii = 1; ii < 16; ii++)
			{
				if( mapArray[i,ii] == 2)
				{
					playerPos = new Vector3(i,ii,0);
				}
			}
		}
		
		Debug.Log (GhostManager.ghostTweens.Count);
		
		transform.position = new Vector3(playerPos.x,playerPos.y,0);
	}
	
	void Update () {
		if (inhibitPlayerInput) return;
		getInput();
	}
	
	
	void getInput()
	{
		bool inputPressed = false;

		
		if(Input.GetKey(KeyCode.W) && inhibitPlayerInput == false)
		{
			inputPressed = true;
			walkup();
		} 
		else if (Input.GetKey(KeyCode.S))
		{
			inputPressed = true;
			walkdown();
		} 
		else if(Input.GetKey(KeyCode.A))
		{
			inputPressed = true;
			walkleft();
		}
		else if(Input.GetKey(KeyCode.D))
		{
			inputPressed = true;
			walkright();
		} 
	}

	void walkup ()
	{
		Vector3 newPlayerPos = playerPos;
		newPlayerPos += new Vector3(-1,0,0);
		if (mapArray[(int)newPlayerPos.x,(int)newPlayerPos.y] == 1)
		{
			if (mapArray[(int)playerPos.x,(int)playerPos.y + 1] == 0 || mapArray[(int)playerPos.x,(int)playerPos.y + 1] >= 2)
				walkright();
			else
				walkleft();
			return;
		}
		
		playerPos = newPlayerPos;
		
		if(mapArray[(int)playerPos.x,(int)playerPos.y] == 0 || mapArray[(int)playerPos.x,(int)playerPos.y] >= 2)
		{
			inhibitPlayerInput = true;
			transform.DOMove(playerPos, TweenWpDuration).OnComplete(() => inhibitPlayerInput = false).SetEase(Ease.Linear);
		}
		if (mapArray[(int)playerPos.x - 1,(int)playerPos.y] == 0 || mapArray[(int)playerPos.x - 1,(int)playerPos.y] >= 2)
		{
			playerPos = newPlayerPos;
			walkup();
		}
		return;
	}

	void walkright ()
	{
		Vector3 newPlayerPos = playerPos;
		newPlayerPos += new Vector3(0,1,0);
		if (mapArray[(int)newPlayerPos.x,(int)newPlayerPos.y] == 1)
		{
			if (mapArray[(int)playerPos.x + 1,(int)playerPos.y] == 0 || mapArray[(int)playerPos.x + 1,(int)playerPos.y] >= 2)
				walkdown();	
			else
				walkup();
			return;

		}
		
		playerPos = newPlayerPos;
		
		if(mapArray[(int)playerPos.x,(int)playerPos.y] == 0 || mapArray[(int)playerPos.x,(int)playerPos.y] >= 2)
		{
			inhibitPlayerInput = true;
			transform.DOMove(playerPos, TweenWpDuration).OnComplete(() => inhibitPlayerInput = false).SetEase(Ease.Linear);
		}
		if (mapArray[(int)playerPos.x,(int)playerPos.y + 1] == 0 || mapArray[(int)playerPos.x,(int)playerPos.y + 1] >= 2)
		{
			playerPos = newPlayerPos;
			walkright();
		}
		return;
	}

	void walkleft ()
	{
		Vector3 newPlayerPos = playerPos;
		newPlayerPos += new Vector3(0,-1,0);
		if (mapArray[(int)newPlayerPos.x,(int)newPlayerPos.y] == 1)
		{
			if (mapArray[(int)playerPos.x + 1,(int)playerPos.y] == 0 || mapArray[(int)playerPos.x + 1,(int)playerPos.y] >= 2)
				walkdown();
			else 
				walkup();
			return;
		}
		
		playerPos = newPlayerPos;
		
		if(mapArray[(int)playerPos.x,(int)playerPos.y] == 0 || mapArray[(int)playerPos.x,(int)playerPos.y] >= 2)
		{
			inhibitPlayerInput = true;
			transform.DOMove(playerPos, TweenWpDuration).OnComplete(() => inhibitPlayerInput = false).SetEase(Ease.Linear);
		}
		if (mapArray[(int)playerPos.x,(int)playerPos.y - 1] == 0 || mapArray[(int)playerPos.x,(int)playerPos.y - 1] >= 2)
		{
			playerPos = newPlayerPos;
			walkleft();
		}
		return;
	}

	void walkdown ()
	{
		Vector3 newPlayerPos = playerPos;
		newPlayerPos += new Vector3(1,0,0);
		if (mapArray[(int)newPlayerPos.x,(int)newPlayerPos.y] == 1)
		{
			if (mapArray[(int)playerPos.x,(int)playerPos.y + 1] == 0 || mapArray[(int)playerPos.x,(int)playerPos.y + 1] >= 2)
				walkright();
			else
				walkleft();
			return;
		}
		
		playerPos = newPlayerPos;
		
		if(mapArray[(int)playerPos.x,(int)playerPos.y] == 0 || mapArray[(int)playerPos.x,(int)playerPos.y] >= 2)
		{
			inhibitPlayerInput = true;
			transform.DOMove(playerPos, TweenWpDuration).OnComplete(() => inhibitPlayerInput = false).SetEase(Ease.Linear);
		}
		if (mapArray[(int)playerPos.x + 1,(int)playerPos.y] == 0 || mapArray[(int)playerPos.x + 1,(int)playerPos.y] >= 2)
		{
			playerPos = newPlayerPos;
			walkdown();
		}
		
		return;
		
	}
}

I found your walking really fast problem! At the end of your move methods, if you can keep moving in that direction, you call the move method again.

So in the end of moveUp, you call moveUp. This should cause the player to move as far as it can upwards instantly. Instead of doing that, you should do this:

  1. Have a variable remembering which input the player pressed last.
  2. At a regular interval (say .5 seconds), move the player in the last input direction.
  3. When the player hits a wall, change the input to either right or left

This is a code suggestion, make note that I haven’t tested it, as I don’t have access to all of your code. It does the three points above, and I’ve refactored your walkNorth/South/East/West into one walk method. Feel free to ask questions. It won’t work out of the box, but it should be a starting point to get you in the right direction.

public class Player : MonoBehaviour {

    const float TweenWpDuration = 0.2f;

    public GameObject levelCreator_;
    levelCreator temp;
    Vector3 playerPos;

    int[,] mapArray = new int[13, 17];

    public bool inhibitPlayerInput;

    //STORE INPUT!
    Vector3 currentMovementFront, currentMovementRight, currentMovementLeft, currentMovementBack;
    Vector3 upVector = new Vector3(-1, 0, 0);
    Vector3 downVector = new Vector3(1, 0, 0);
    Vector3 rightVector = new Vector3(0, 1, 0);
    Vector3 leftVector = new Vector3(0, -1, 0);

    void Start() {
        //start moving up
        currentMovementFront = upVector;
        currentMovementRight = rightVector;
        currentMovementLeft = leftVector;
        currentMovementBack = downVector;
        StartCoroutine(MovePlayer());
    }

    //moves the player every half second
    IEnumerator MovePlayer() {
        while (true) {
            yield return new WaitForSeconds(.5f);
            if (!inhibitPlayerInput)
                walk(currentMovementFront, currentMovementRight, currentMovementLeft, currentMovementBack);
        }
    }

    void Update() {
        if (inhibitPlayerInput)
            return;
        getInput();
    }

    void getInput() {
        if (!inhibitPlayerInput) {
            if (Input.GetKey(KeyCode.W)) {
                SetCurrentMovement(upVector, rightVector, leftVector, downVector);
            }
            else if (Input.GetKey(KeyCode.S)) {
                SetCurrentMovement(downVector, leftVector, rightVector, upVector);
            }
            else if (Input.GetKey(KeyCode.A)) {
                SetCurrentMovement(leftVector, downVector, upVector, rightVector);
            }
            else if (Input.GetKey(KeyCode.D)) {
                SetCurrentMovement(rightVector, upVector, downVector, leftVector);
            }
        }
    }

    private void SetCurrentMovement(Vector3 front, Vector3 right, Vector3 left, Vector3 down) {
        currentMovementFront = front;
        currentMovementRight = right;
        currentMovementLeft = left;
        currentMovementBack = down;
    }

    void walk(Vector3 movement, Vector3 relativeRight, Vector3 relativeLeft, Vector3 relativeBack) {
        Vector3 newPlayerPos = playerPos;
        //newPlayerPos += new Vector3(-1, 0, 0);
        newPlayerPos += movement;
        if (mapArray[(int)newPlayerPos.x, (int)newPlayerPos.y] == 1) {
            Vector3 rightPos = playerPos + relativeRight;
            if (mapArray[(int)rightPos.x, (int)rightPos.y] == 0 || mapArray[(int)rightPos.x, (int)rightPos.y] >= 2)
                walk(relativeRight, relativeBack, movement, relativeLeft);
            else
                walk(relativeLeft, movement, relativeBack, relativeRight);
            return;
        }

        playerPos = newPlayerPos;

        if (mapArray[(int)playerPos.x, (int)playerPos.y] == 0 || mapArray[(int)playerPos.x, (int)playerPos.y] >= 2) {
            inhibitPlayerInput = true;
            transform.DOMove(playerPos, TweenWpDuration).OnComplete(() => inhibitPlayerInput = false).SetEase(Ease.Linear);
        }
        if (mapArray[(int)playerPos.x - 1, (int)playerPos.y] == 0 || mapArray[(int)playerPos.x - 1, (int)playerPos.y] >= 2) {
            playerPos = newPlayerPos;
            //walkup(); //This recursive call caused really fast movement
        }
        return;
    }
}