- Home /
Tiled Movement Inputs are Inaccurate
Hey, good afternoon! I am currently working on a first-person dungeon-crawling game using Unity 3D. Right now, I have given the player the following inputs:
Move Forward, Backward
Strafe Left, Right
Change the direction they are facing w/o moving
What I need help with is the first 2 input types: moving and strafing. The player is supposed to only move a specific unit of distance per input, as if they were moving between spaces on a chessboard (tiled movement).
When run through Update, the player moves in strange intervals that sometimes change intermittently. (Example: The player will move 0.78 units for the first input @ runtime, but then only 0.3 units the next time I press the same input.)
When I run inputs through FixedUpdate, the intervals are what I want them to be (1 unit of distance/input), but inputs get lost/delayed far too often. It's my understanding that this is due to how Unity handles physics calculations - is that right?.
I've provided the following:
My code
The current view through my player
The tutorial I used to help me understand the movement
using System.Collections; using System.Collections.Generic; using UnityEngine; [RequireComponent(typeof(Rigidbody))] public class Movement : MonoBehaviour { public GameObject Player; Vector3 destination, currentDirection = Vector3.zero; public float Speed = 5f; float rayLength = 1; bool canMove; // Update is called once per frame void Update() { // PLAYER MOVEMENT IS HERE if (Input.GetKeyDown(KeyCode.W)) { transform.position += transform.forward * Time.deltaTime * Speed; //MOVE FORWARD } else if (Input.GetKeyDown(KeyCode.S)) { transform.position -= transform.forward * Time.deltaTime * Speed; //MOVE BACKWARD } else if (Input.GetKeyDown(KeyCode.A)) { transform.position -= transform.right * Time.deltaTime * Speed; //STRAFE LEFT } else if (Input.GetKeyDown(KeyCode.D)) { transform.position += transform.right * Time.deltaTime * Speed; //STRAFE RIGHT } // THESE CONTROLS DETERMINE WHICH DIRECTION THE PLAYER IS FACING; CAMERA IS CURRENTLY A CHILD OF THE PLAYER, SO IT ALSO MOVES ACCORDING TO THESE CONTROLS if (Input.GetKeyDown("q")) { Player.transform.rotation *= Quaternion.Euler(0, -90, 0); //TURN CAMERA/PLAYER LEFT } if (Input.GetKeyDown("e")) { Player.transform.rotation *= Quaternion.Euler(0, 90, 0); // } if (Vector3.Distance(destination, transform.position) <= 0.0001f) { transform.localEulerAngles = currentDirection; if (canMove) { if (Valid()) { destination = transform.position; canMove = false; } } } } bool Valid() { Ray myRay = new Ray(transform.position + new Vector3(0, 0.5f, 0), transform.forward); RaycastHit hit; Debug.DrawRay(myRay.origin, myRay.direction, Color.red); if (Physics.Raycast(myRay, out hit, rayLength)) { if (hit.collider.tag == "Wall") { return false; } } return true; } }
Answer by finnjwohner · Jul 11, 2020 at 11:23 PM
Okey dokey, this doesn't seem too difficult to fix,
First of all let's see why you are moving different amounts when you press your move keys. Take for example you press down W, you will move forward at a rate that if you managed to press it every frame for 1 second, you will have moved 5 units, what I gather from your question is that you instead want it to move 1 unit on the frame that you pressed it.
To do this, just remove the speed and Time.deltaTime variables from your statement, after that it should look like this;
if (Input.GetKeyDown(KeyCode.W)) {
transform.position += transform.forward;
}
else if (Input.GetKeyDown(KeyCode.S)) {
transform.position -= transform.forward;
}
else if (Input.GetKeyDown(KeyCode.A)) {
transform.position -= transform.right;
}
else if (Input.GetKeyDown(KeyCode.D)) {
transform.position += transform.right;
}
I'm unsure as to what line 50 and beyond is supposed to do, if you want to check if the player is blocked and can't move in that direction, you should probably call Valid() after each if statement and before moving the player, and change the direction of the ray to be whatever direction the player is moving in.
If not the above code should work, hope I could help.
Hey, thanks for replying! Removing Time.deltaTime and the Speed variable was exactly what I needed to do! I had presumed that I should always have Time.deltaTime attached to my input strings, so they weren't tied to framerate.
As for line 50+, that's supposed to be some basic collision detection to prevent me from hitting walls tagged as "Wall". It seems to not be working.
Your answer
Follow this Question
Related Questions
My player passes through walls 5 Answers
Input System Can't Catch Event on Update 0 Answers
Move Multiple Directions At Once (ex. forward and right) unity 3d 1 Answer
W key to move doesnt work,Movement Script doesnt do anything when i press w 0 Answers
Player rotating towards direction of movement in 3D 1 Answer