Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by coolbird22 · Oct 03, 2014 at 08:41 AM · movementarraygrid

[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 HERE

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;
         
     }
 }


gridmovement.zip (395.1 kB)
Comment
Add comment · Show 4
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Baste · Oct 03, 2014 at 09:04 AM 2
Share

A hint for your code: replace walkup/down/right/left with a walk-method, that takes a Vector3, and use that Vector3 to give directions.

Now you have four methods that are identical with the exception of some coordinates. That means that whenever you want to change your walk-methods, you have to change all of them, and make sure that you change exactly the same thing every time. I can guarantee that you will mess up doing that, trust me.

If you do that and repost your code, it will be much easier for us (and you) to find the problems.

avatar image Kiwasi · Oct 03, 2014 at 09:18 AM 0
Share

DRY code is worth ai$$anonymous$$g for. Could certainly reduce this long post to a short one.

avatar image coolbird22 · Oct 03, 2014 at 09:33 AM 0
Share

Thanks for the replies, @Baste and @Bored$$anonymous$$ormon.

Actually I wanted to have a single method as well, but I'm not aware of how to code such a behavior :( I believe that the discrepencies are arising because of some logic in these four methods that I currently have.

I apologize for not being able to edit the code and hereby assist users here to help me find the problem. I've been stuck on this exact issue for 3 weeks now despite posting on various different forums.

To be a bit more clear, below is the previous version of my code, which allows for movement to happen only when a key is pressed. If no key is pressed, the movement doesn't happen anymore.

avatar image coolbird22 · Oct 03, 2014 at 09:33 AM 0
Share
 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)     // tile with value 2 is the starting position of the player
                 {
                     playerPos = new Vector3(i,ii,0);
                 }
             }
         }
  
         transform.position = new Vector3(playerPos.x,playerPos.y,0);
     }
  
 void Update () {
         if (inhibitPlayerInput) return;
         getInput();
     }
  
 void getInput()
     {
         bool inputPressed = false;
         Vector3 newPlayerPos = playerPos;
  
         if(Input.Get$$anonymous$$ey($$anonymous$$eyCode.W))
         {
             inputPressed = true;
             newPlayerPos += new Vector3(-1,0,0);
         } 
         else if (Input.Get$$anonymous$$ey($$anonymous$$eyCode.S))
         {
             inputPressed = true;
             newPlayerPos += new Vector3(1,0,0);
         } 
         else if(Input.Get$$anonymous$$ey($$anonymous$$eyCode.A))
         {
             inputPressed = true;
             newPlayerPos += new Vector3(0,-1,0);
         }
         else if(Input.Get$$anonymous$$ey($$anonymous$$eyCode.D))
         {
             inputPressed = true;
             newPlayerPos += new Vector3(0,1,0);
         } 
  
         if (!inputPressed) return;
  
         if (mapArray[(int)newPlayerPos.x,(int)newPlayerPos.y] == 1)      // Unwalkable tile check
         {
             return;
         }
         playerPos = newPlayerPos;
  
         if(mapArray[(int)playerPos.x,(int)playerPos.y] == 0 || mapArray[(int)playerPos.x,(int)playerPos.y] >= 2)
         {
             inhibitPlayerInput = true;
             transform.DO$$anonymous$$ove(playerPos, TweenWpDuration).OnComplete(() => inhibitPlayerInput = false).SetEase(Ease.Linear);
             return;
         }
     }

1 Reply

· Add your reply
  • Sort: 
avatar image
1

Answer by Baste · Oct 03, 2014 at 01:23 PM

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;
     }
 }
 



Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image coolbird22 · Oct 03, 2014 at 04:38 PM 0
Share

Thanks for the quick reply @Baste. That code seems to work. I needed to add the following code inside Start in order to place the player object inside the array grid.

 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);
                 }
             }
         }
         transform.position = new Vector3(playerPos.x,playerPos.y,0);

However the movement doesn't move with a smooth linear speed. Currently, it moves, and pauses, and moves, and pauses, each time it reaches a new cell. I changed the WaitForSeconds from .5f to .005f, to make the movement smoother, but that makes the input virtually disabled. Also, sometimes when input is pressed in the direction of a wall, ins$$anonymous$$d of continuing in its' current direction, the player object moves in reverse. To better understand this, kindly check the project linked here (390kb) - ProjectLink Also, there seems to be some glitch when if the object goes to a corner, it keeps doing a to and fro oscillatory movement in the adjacent tiles in that corner and gets stuck in some loop. A video grab of the same can be found Here(80kbs)

avatar image Baste · Oct 04, 2014 at 11:24 PM 0
Share

The move/pause is due to you shifting the transform's position directly to a spot.

The correct way to move a thing is to set a destination, and then move the thing over time towards that destination - usually combining Vector3.$$anonymous$$oveTowards to get the next position and Time.deltaTime to make the movement framerate independent.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

28 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Touch and Drag 3D Objects on a Grid (for Android) 0 Answers

Push into Two-Dimensional Array 2 Answers

Access a specific element in GridLayoutGroup by script ? 1 Answer

help with direction 1 Answer

Creating a 2d array with the Array class 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges