I'm trying to replicate Silent Hill's mechanic where if you press a button, the character does a 180, but instead of getting a smooth turn around, my character is snapping from one rotation to another.

This is the code I have so far:

if (Input.GetKeyDown(KeyCode.Tab))
    transform.Rotate(0f, 180f, 0f);

I also have a Sprint(); function and I want to disable this feature if the character is sprinting. Here's the code for that:

private void Sprint() 
    float newTurnSpeed = _turnSpeed - 1.4f; 

    vertical = Input.GetAxis("Vertical");
    horizontal = Input.GetAxis("Horizontal");

    Vector3 direction = new Vector3(0f, 0f, vertical);
    Vector3 movement = transform.TransformDirection(direction) * _sprintSpeed;

    transform.Rotate(0f, horizontal * newTurnSpeed, 0f); //add the new turn speed
    isGrounded = _characterController.SimpleMove(movement);

Any help is appreciated!


1 Answer 1

public string sprintButton;
public string turnAroundButton;

public float rotationSpeed = 360.0f;

Quaternion _targetRotation;
Coroutine _rotation;

IEnumerator RotateToTargetOverTime() {
    // Keep running this behaviour every frame until we're within 1 degree of our goal.
    while(Quaternion.Angle(transform.rotation, _targetRotation) > 1f) {

        // Keep rotating toward the target orientation.
        transform.rotation = Quaternion.RotateTowards(
                                 rotationSpeed * Time.deltaTime

        // Wait till next frame.
        yield return null;

    // We're done rotating - clear out the coroutine.
    _rotation = null;

void Update() {
    if(Input.GetButton(sprintButton)) {
        // Abort the 180 turn in progress, if any.
        if(_rotation != null) {
            _rotation = null;

        // Call your existing sprint behaviour.

    // Check for turn around input if and only if we're not sprinting.
    } else if(Input.GetButtonDown(turnAroundButton)) {
        // Update our target rotation to move towards.
        _targetRotation = Quaternion.Euler(0, 180, 0) * transform.rotation;

        // If we're not already rotating, start a new coroutine to finish the rotation.
        if(_rotation == null)
            _rotation = StartCoroutine(RotateToTargetOverTime());

    // ...other Update stuff...
  • \$\begingroup\$ Hey thanks a lot, this actually works pretty well! I had no idea to use a while loop or a Coroutine for this kind of stuff \$\endgroup\$
    – ManofDog
    Jul 17, 2020 at 17:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .