alexo1001 alexo1001 - 19 days ago 6
C# Question

Stopping player from spamming movement keys which causes glitches

I wrote a script for the player movement in c#. Whenever the player presses A or D, it moves him/her to the left or right by 12 units and when the player presses W or S, it moves him/her up or down by 12 units. My script works fine, but if a person starts to spam all of the keys at once, it glitches out and the player object is not in line with the level anymore. I want to have the script check if there a movement is currently happening before executing the movement on the keypress. Here is my script:

void Update () {

transform.Translate(Vector3.forward * ForwardSpeed * Time.deltaTime);

if (Input.GetKeyDown (KeyCode.A) && side > maxSideLeft) {
MoveObjectTo(this.transform, new Vector3(this.transform.position.x - 12, this.transform.position.y, this.transform.position.z + 10), movementSpeed);
side -= 1;
} else if (Input.GetKeyDown (KeyCode.D) && side < maxSideRight) {
MoveObjectTo(this.transform, new Vector3(this.transform.position.x + 12, this.transform.position.y, this.transform.position.z + 10), movementSpeed);
side += 1;
}

if (Input.GetKeyDown (KeyCode.W) && level < maxLevelHeight) {
MoveObjectTo(this.transform, new Vector3(this.transform.position.x, this.transform.position.y + 12, this.transform.position.z + 10), movementSpeed);
level += 1;
} else if (Input.GetKeyDown (KeyCode.S) && level > minLevelHeight) {
MoveObjectTo(this.transform, new Vector3(this.transform.position.x, this.transform.position.y - 12, this.transform.position.z + 10), movementSpeed);
level -= 1;
}

if (Input.GetKeyDown (KeyCode.R) || Input.GetKeyDown(KeyCode.Space)) {
SceneManager.LoadScene ("Scene1");
Time.timeScale = 1;
}
}


private void MoveObjectTo(Transform objectToMove, Vector3 targetPosition, float moveSpeed)
{
StopCoroutine(MoveObject(objectToMove, targetPosition, moveSpeed));
StartCoroutine(MoveObject(objectToMove, targetPosition, moveSpeed));
}

public static IEnumerator MoveObject(Transform objectToMove, Vector3 targetPosition, float moveSpeed)
{
float currentProgress = 0;
Vector3 cashedObjectPosition = objectToMove.transform.position;

while (currentProgress <= 1)
{
currentProgress += moveSpeed * Time.deltaTime;

objectToMove.position = Vector3.Lerp(cashedObjectPosition, targetPosition, currentProgress);

yield return null;
}
}

Answer

You can use a simple isMoving variable for this. Don't move if the variable is true. Move if it is false. When the coroutine is done running set isMoving back to false. Also, I can't tell why MoveObject function is static. I removed the static keyword from it.

bool isMoving = false;

void Update()
{

    transform.Translate(Vector3.forward * ForwardSpeed * Time.deltaTime);

    if (Input.GetKeyDown(KeyCode.A) && side > maxSideLeft)
    {
        MoveObjectTo(this.transform, new Vector3(this.transform.position.x - 12, this.transform.position.y, this.transform.position.z + 10), movementSpeed);
        side -= 1;
    }
    else if (Input.GetKeyDown(KeyCode.D) && side < maxSideRight)
    {
        MoveObjectTo(this.transform, new Vector3(this.transform.position.x + 12, this.transform.position.y, this.transform.position.z + 10), movementSpeed);
        side += 1;
    }

    if (Input.GetKeyDown(KeyCode.W) && level < maxLevelHeight)
    {
        MoveObjectTo(this.transform, new Vector3(this.transform.position.x, this.transform.position.y + 12, this.transform.position.z + 10), movementSpeed);
        level += 1;
    }
    else if (Input.GetKeyDown(KeyCode.S) && level > minLevelHeight)
    {
        MoveObjectTo(this.transform, new Vector3(this.transform.position.x, this.transform.position.y - 12, this.transform.position.z + 10), movementSpeed);
        level -= 1;
    }

    if (Input.GetKeyDown(KeyCode.R) || Input.GetKeyDown(KeyCode.Space))
    {
        SceneManager.LoadScene("Scene1");
        Time.timeScale = 1;
    }
}


private void MoveObjectTo(Transform objectToMove, Vector3 targetPosition, float moveSpeed)
{
    //Don't do anything Object is already moving
    if (isMoving)
    {
        return;
    }
    //If not moving set isMoving to true
    isMoving = true;
    StartCoroutine(MoveObject(objectToMove, targetPosition, moveSpeed));
}

public IEnumerator MoveObject(Transform objectToMove, Vector3 targetPosition, float moveSpeed)
{
    float currentProgress = 0;
    Vector3 cashedObjectPosition = objectToMove.transform.position;

    while (currentProgress <= 1)
    {
        currentProgress += moveSpeed * Time.deltaTime;

        objectToMove.position = Vector3.Lerp(cashedObjectPosition, targetPosition, currentProgress);

        yield return null;
    }
    //Done moving. Set isMoving to false
    isMoving = false;
}
Comments