Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 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 KnightsHouseGames · Jun 25, 2015 at 12:53 PM · movementfootstepsfixedgridmovestep

Fixed Step Movement

I'm designing a game that requires movement to be very precise. I want each step to take you the exact same distance, so the player can count footsteps in order to judge distance, as the game will take place in total darkness.

I've seen other answers to this problem that involve using coroutines, but those don't seem to work for me, and the original posters seem to be long gone without giving the real answer.

Heres where I am with this so far based on those solutions.

 public class Movement : MonoBehaviour {
 
     public GameObject player;
     public float speed;
 
     // Use this for initialization
     void Start () {
         //Coroutine for movement
         StartCoroutine(CoUpdate());
     }
 
     IEnumerator CoUpdate()
     {
         if(Input.GetKey(KeyCode.UpArrow))
         {
             move(Vector3.forward);
             yield return null;
         }
         else if(Input.GetKey(KeyCode.DownArrow))
         {
             move (Vector3.back);
             yield return null;
         }
     }
 
     void move(Vector3 direction)
     {
         transform.Translate (direction * speed, Space.Self);
     }
 
 }

I intend to make left and right do exact 90 degree turns in those directions, thats why those directions aren't currently present.

Help with this problem would be greatly appreciated

Comment
Add comment
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

2 Replies

· Add your reply
  • Sort: 
avatar image
0

Answer by felixpk · Jun 25, 2015 at 02:46 PM

To make an exact movement every frame you could either do it in a CoRoutine:

 void Start(){
   StartCoroutine(CoUpdate());
 }
 
 IEnumator CoUpdate(){
    while(true){ //while true is needed to loop the CoUpdate() else it is just executed once
       if(Input.GetKey(KeyCode.UpArrow)){
           move(Vector3.forward);
           yield return new WaitForSeconds(0.1f); // this makes sure that each step is executed after 0.1 seconds
       }else if(Input.GetKey(KeyCode.DownArrow)){
           move (Vector3.back);
           yield return new WaitForSeconds(0.1f);
       }
    }
 }


But I think the way better solution would be:

 void Update(){
     if(Input.GetKey(KeyCode.UpArrow)){
         move(Vector3.forward * Time.deltaTime);
     }else if(Input.GetKey(KeyCode.DownArrow)){
         move (Vector3.back * Time.deltaTime);
     }
 }

With DeltaTime you compensate the amount of time between every Update. The result is a smooth and steady movement.

Comment
Add comment · Show 3 · 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 KnightsHouseGames · Jun 25, 2015 at 08:10 PM 0
Share

This just causes Unity to hang on an infinate loop and crash for me.

I'm aware of your second solution, I normally use something like that, I just want to articulate exact steps, so even if you just tap the button or let go of the button mid step, you always end up taking exact steps, like moving on a grid, so that if you were to take 2 steps forward and 2 steps back, you would be exactly where you were when you started.

The idea is that the player is completely blind and has to rely entirely on sound to find their way around, so I want you to be able to count the amount of footsteps you've taken as a reliable method of tracking one's progress.

avatar image Dave-Carlile · Jun 25, 2015 at 08:25 PM 1
Share

felixpk's CoUpdate function needs to handle the case where a key isn't held down to avoid the infinite loop...

 else
   yield return null; // yield until next frame

I'm not so sure felix's solution addresses your problem, but that should fix the loop regardless.

avatar image KnightsHouseGames · Jun 25, 2015 at 11:00 PM 0
Share

That did fix the infinate loop, and he does step pretty reliably now, but his movement is pretty jumpy...

I've tried changing out my transform.translate for a Lerp, but I don't totally understand lerps, so it's still really rigid.

Here is my move method now:

 void move(Vector3 direction)
     {
         Vector3 newPosition = transform.position + (direction * speed);
         transform.position = Vector3.Lerp(transform.position, newPosition, 0.3f);
     }

How do I make the movement smooth? Would Lerp even be a good choice for this?

avatar image
0

Answer by KnightsHouseGames · Jun 29, 2015 at 10:38 AM

OK, so I have the solution, it's probably not the best solution to this problem because it is insanely complicated, but this is often the case with any solution I find.

I followed a series of videos about grid based movement for a Civ/dungeon crawler movement system that relies on pathfinding algorithms and a procedurally generated map system, you can find that video here

https://www.youtube.com/watch?v=au6_95iI_gE

Don't bother watching all the videos unless you have an entire day to waste, as he never actually covers the animation part. Download the project from the link in the description of that video to save yourself a lot of time. In there, you'll get the algorithm and all that good stuff, but it will be click based rather than d-pad based like I had in mind for my project.

I followed the videos rather than downloading the project, so I made a few customizations here and there, and wrote out a character movement system based on his platform.

It runs sorta like tank controls, with forward and backward steps, and 90 degree rotation on left and right button presses.

Here is my player code. This would replace the "Unit" class in his system. It's important you include system.collections.generic, as he uses that to manage his data structures.

 using UnityEngine;
 using System.Collections;
 using System.Collections.Generic;
 
 public class Player : MonoBehaviour {
 
     public int tileX;
     public int tileY;
     public TileMap map;
 
     public bool moving = false;
     public bool rotating = false;
 
     public enum Direction{North, South, East, West}
 
     Direction currentDirection = Direction.North;
     Quaternion newRotation = new Quaternion();
 
 
     public List<Node> currentPath = null;
 
     void Update() {
         if(Vector3.Distance(transform.position, map.TileCoordToWorldCoord( tileX, tileY )) < 0.2f)
             AdvancePathing();
         
         // Smoothly animate towards the correct map tile.
         transform.position = Vector3.Lerp(transform.position, map.TileCoordToWorldCoord( tileX, tileY ), 3f * Time.deltaTime);
 
         //Smoothly animate turns
         transform.rotation = Quaternion.Slerp(transform.rotation, newRotation, 4f * Time.deltaTime);
 
 
 
         //Step Forward
         if(Input.GetKey(KeyCode.UpArrow))
         {
             if(!moving)
             {
                 StartCoroutine(StepForward());
             }
         }
         //Step Backward
         if(Input.GetKey(KeyCode.DownArrow))
         {
             if(!moving)
             {
                 StartCoroutine(StepBackward());
             }
         }
         //Turn Right
         if(Input.GetKey(KeyCode.RightArrow))
         {
             if (!rotating) 
             {
                 StartCoroutine(RotateRight());
             }
         }
 
         //Turn Left
         if(Input.GetKey(KeyCode.LeftArrow))
         {
             if (!rotating) 
             {
                 StartCoroutine(RotateLeft());
             }
         }
     }
     
     // Advances our pathfinding progress by one tile.
     void AdvancePathing() {
         if(currentPath==null)
             return;
         
         // Teleport us to our correct "current" position, in case we
         // haven't finished the animation yet.
         transform.position = map.TileCoordToWorldCoord( tileX, tileY );
         
         // Move us to the next tile in the sequence
         tileX = currentPath[1].x;
         tileY = currentPath[1].y;
         
         // Remove the old "current" tile from the pathfinding list
         currentPath.RemoveAt(0);
         
         if(currentPath.Count == 1) {
             // We only have one tile left in the path, and that tile MUST be our ultimate
             // destination -- and we are standing on it!
             // So let's just clear our pathfinding info.
             currentPath = null;
         }
     }
 
     IEnumerator StepForward()
     {
         if (currentDirection == Direction.North) {
             moving = true;
             if (tileY < map.mapSizeY - 1)
                 map.GeneratePathTo (tileX, tileY + 1);
             yield return new WaitForSeconds (0.3f);
             moving = false;
         }
         if (currentDirection == Direction.South) {
             moving = true;
             if (tileY > 0)
                 map.GeneratePathTo (tileX, tileY - 1);
             yield return new WaitForSeconds (0.3f);
             moving = false;
         }
         if (currentDirection == Direction.East) {
             moving = true;
             if (tileX < map.mapSizeX - 1)
                 map.GeneratePathTo (tileX + 1, tileY);
             yield return new WaitForSeconds (0.3f);
             moving = false;
         }
         if (currentDirection == Direction.West) {
             moving = true;
             if (tileX > 0)
                 map.GeneratePathTo (tileX - 1, tileY);
             yield return new WaitForSeconds (0.3f);
             moving = false;
         }
 
     }
 
     IEnumerator StepBackward()
     {
         if (currentDirection == Direction.North) {
             moving = true;
             if (tileY > 0)
                 map.GeneratePathTo (tileX, tileY - 1);
             yield return new WaitForSeconds (0.3f);
             moving = false;
         }
         if (currentDirection == Direction.South) {
             moving = true;
             if (tileY < map.mapSizeY - 1)
                 map.GeneratePathTo (tileX, tileY + 1);
             yield return new WaitForSeconds (0.3f);
             moving = false;
         }
         if (currentDirection == Direction.East) {
             moving = true;
             if (tileX > 0)
                 map.GeneratePathTo (tileX - 1, tileY);
             yield return new WaitForSeconds (0.3f);
             moving = false;
         }
         if (currentDirection == Direction.West) {
             moving = true;
             if (tileX < map.mapSizeX - 1)
                 map.GeneratePathTo (tileX + 1, tileY);
             yield return new WaitForSeconds (0.3f);
             moving = false;
         }
     }
     IEnumerator RotateRight()
     {
         rotating = true;
         float yRotation = transform.eulerAngles.y;
         newRotation = Quaternion.Euler(0,yRotation+90,0);
         switch(currentDirection)
         {
         case(Direction.West):
             currentDirection = Direction.North;
             Debug.Log ("Direction is now North");
             break;
         case(Direction.East):
             currentDirection = Direction.South;
             Debug.Log ("Direction is now South");
             break;
         case(Direction.South):
             currentDirection = Direction.West;
             Debug.Log ("Direction is now West");
             break;
         case(Direction.North):
             currentDirection = Direction.East;
             Debug.Log ("Direction is now East");
             break;
         }
         yield return new WaitForSeconds(1f);
         rotating = false;
 
 
     }
 
     IEnumerator RotateLeft()
     {
         rotating = true;
         float yRotation = transform.eulerAngles.y;
         newRotation = Quaternion.Euler(0,yRotation-90,0);
         switch(currentDirection)
         {
         case(Direction.West):
             currentDirection = Direction.South;
             Debug.Log ("Direction is now South");
             break;
         case(Direction.East):
             currentDirection = Direction.North;
             Debug.Log ("Direction is now North");
             break;
         case(Direction.South):
             currentDirection = Direction.East;
             Debug.Log ("Direction is now East");
             break;
         case(Direction.North):
             currentDirection = Direction.West;
             Debug.Log ("Direction is now East");
             break;
         }
         yield return new WaitForSeconds(1f);
         rotating = false;
     }
 
 }

My additions should compensate for the array size and should lead to a quite accurate grid movement system. Mine was built for a first person camera (only out of nessessity, I hate first person otherwise), but I would imagine it wouldn't be difficult to modify for a 3rd person camera like some sort of NES style Zelda game in 3D or something. Frankly it almost completely puts that pathfinding algorithm to waste, but I can't figure out how to simplify it right now

Next time someone searches for Fixed Step Movement, now there will at least be some sort of solution to be found.

Comment
Add comment · 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

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

3 People are following this question.

avatar image avatar image avatar image

Related Questions

Mouse Aiming + Fixed Camera + Independent Keyboard Movement 3 Answers

Footstep sounds system with a Vr touchpad movement system 1 Answer

2D Game, Player Not to move if a wall is next to it C# 1 Answer

Player moving/rotating along a single axis 1 Answer

How to let player move for specific number of times in gird base system.,Implement a move system in grid where player can move for specific number then dies if he did not meet game end/ 0 Answers


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