transform.rotation rotates object in two directions after button release

I’ve made an Isometric character controller so it can move and head on an isometric based perspective. The problem is that when I try to move using 2 keys (W + D, A + S…) and release those keys, the player tends to face the very last key that was released, so it is difficult to head a diagonal direction. This makes the character flip its rotation in the very last moment the keys are released.

I’ve been thinking of using a kind of sleep or coroutine checking if two keys were pressed and released in a short period of time just not rotate it.

There exist any not too rustic solution for this?

This is how I calculate the rotation.

private void CalculateDirection() {
Debug.Log(inputAxis.magnitude);
rotationAngle = Mathf.Atan2(inputAxis.x, inputAxis.y);
rotationAngle = Mathf.Rad2Deg * rotationAngle;
rotationAngle += cam.eulerAngles.y;
}

private void Rotate() {
if (inputAxis != Vector2.zero ) {
targetRotation = Quaternion.Euler(0, rotationAngle, 0);
transform.rotation = targetRotation;
}
}

The problem is that inputAxis changes after release one and two keys. I’ve tried changing input sensitivity and gravity.

You’re heading the right direction.Create a class field for storing holding the time when key was released. When a key is released check if current Time.time value minus that field is small enough and turn 45 instead of 90 then. After that, save Time.time value to this class field for next test.

I don’t know if I’ve understood you well.
This is what a did based on your comment.

private void SetLastKeyReleaseTime() {
if(Input.GetButtonUp(verticalButton) || Input.GetButtonUp(horizontalButton)) {
canRotate = (Time.time - lastKeyReleaseTime > 0.5f);
lastKeyReleaseTime = Time.time;
}
}

The problem is that the condition “Time.time - lastKeyReleaseTime > 0.5f” could never be passed if you smash all the buttons too fast, so the rotation keep locked in a certain direction.

That’s because youre checking if passed more than .5 seconds. Of course it won’t work when pressing keys fast. Interval should be less than approximately .1 to catch the moment when key were released almost at the same time.

if(Time.time - lastPressTime < .1f) turn45();
else turn90();
lastPressTime = Time.time;

I can not imagine how “turn45” and “turn90” works.

With turn45 i mean you put your character into diagonal direction and by turn90 i meant horizontal or vertical direction according to what key was released. From you starting post i suppose it is already done in your code.

I don’t use that methods to rotate, I just used:

Quaternion rot = Quaternion.LookRotation(movement);
transform.rotation = rot;

The problem is that in the very last moment, “movement” value’s is the result of release one key and then another, so it rotates in the very last released key’s direction.

No matter what small the time checker is, I just tried it with 0.001f and it continues locking other rotations when you hit them fast.

You can get average between two vectors with Vector3.lerp(movement, prevMovement, .5f);
Store prev vector along with time, thats it.

I’ve made a method with that advice but you can not assume a Lerp it’s valid or not, because the last rotation could be intentionally or not.
The result of doing Vector3.Lerp(movement, lastMovement, 0.1f).magnitude is 0.1 when the object rotates intentionally and ~= 0.97 when it’s done automatically. Perhaps, you can not do a condition like if (0.1) because both results are triggered at the same time.

I finally found a solution. Thanks to your advices I figured out a way to solve this problem.
I’ll post the solution just in case any one else need it:

I calculate the current rotation based on the movement.

private void SetRotation() {
        currentRotation = Quaternion.LookRotation(movement);
    }

Then, I created a second Quaternion to store the last rotation if is not the same than the current. I also use a counter to store the time a rotation has been faced before stoping the movement or changing the direction.

private void CheckSameRotation() {
        if (lastRotation != currentRotation || movement == Vector3.zero) {
            sameRotationTime = 0;
            lastRotation = currentRotation;
        }
        else {
            sameRotationTime += Time.deltaTime;
        }
    }

Then, I used a bool to check if the time is high enough to make the rotation happen.

private void TimeAtSameRotation() {
        canRotate = (sameRotationTime < 0.015f) ? false : true;
    }

And then, I finally rotate the object if the movement is not zero and the condition “canRotate” is true.

private void Rotate() {
        if (movement != Vector3.zero && canRotate) {
            transform.rotation = currentRotation;
        }
    }

I’m glad to help you, happy coding ^)

1 Like