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:

  1. Move Forward, Backward
  2. Strafe Left, Right
  3. 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:


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

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.