Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Question Open/Close Door in coroutine

Discussion in 'Scripting' started by liccardi, Sep 23, 2023.

  1. liccardi

    liccardi

    Joined:
    Dec 6, 2018
    Posts:
    16
    I don't quite understand how to manage rotations in coroutines, I manage them via coroutines because every interactive object passes through a general interactive script, I tried like this but the desired effect is not what I was hoping for, I would like a simple smooth movement for opening and closing of the door, but with my script it only goes slow once, then you have to wait for the time for it to reset and then it goes slow again, if I repeatedly click the button to interact, the door closes/opens quickly.. could you help me?

    Code (CSharp):
    1. using System.Collections;
    2. using UnityEngine;
    3.  
    4. public class DoorsWithoutKey : MonoBehaviour
    5. {
    6.  
    7.     public bool open = false;
    8.  
    9.     [SerializeField] private float smooth = 2.0f;
    10.     [SerializeField] private float DoorOpenAngle = 90.0f;
    11.     private Vector3 defaulRot;
    12.     private Vector3 openRot;
    13.     [SerializeField] public float lerpDuration = 0;
    14.  
    15.     void Start()
    16.     {
    17.         defaulRot = transform.eulerAngles;
    18.         openRot = new Vector3(defaulRot.x, defaulRot.y + DoorOpenAngle, defaulRot.z);
    19.     }
    20.  
    21.  
    22.     public void NewOpenClosed()
    23.     {
    24.         open = !open;
    25.         StartCoroutine(OpenDoor());
    26.     }
    27.  
    28.     private IEnumerator OpenDoor()
    29.     {
    30.         float timeElapsed = 0;
    31.  
    32.         while (timeElapsed < lerpDuration)
    33.         {
    34.  
    35.             if (open)
    36.             {
    37.                 gameObject.transform.eulerAngles = Vector3.Slerp(transform.eulerAngles, openRot, timeElapsed / lerpDuration);
    38.             }
    39.             else
    40.             {
    41.                 gameObject.transform.eulerAngles = Vector3.Slerp(transform.eulerAngles, defaulRot, timeElapsed / lerpDuration);
    42.             }
    43.             timeElapsed += Time.deltaTime;
    44.             yield return null;
    45.  
    46.         }      
    47.     }
    48. }
    49.  
     
  2. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    6,008
    I think the reason you're getting sped up animations is you probably have multiple coroutines trying to rotate the door.

    If you want to use a coroutine, then you probably want to prevent the door from being interacted with during its duration, which you can easily do by guarding your
    NewOpenClosed
    method with a boolean you flip during the beginning and end of the coroutine.

    Otherwise, if you still want the door to be interacted with during opening/closing, then a coroutine won't suffice. You'll want to probably rotate the door via Update towards a target rotation, and interacting with it merely swaps between two (or maybe three, depending on what side the player is on) target rotations.

    Then once the door is at it's target it can turn itself off until interacted with again.
     
    Bunny83 likes this.
  3. liccardi

    liccardi

    Joined:
    Dec 6, 2018
    Posts:
    16
    let's say that the approach was already wrong, I was just testing, since I use them the time to calculate while instead I should use a position, calculate a position to reach, but how?
    yes, I would like to interact with the door even during its Closing/Opening
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,951
    I use this pattern for all kinds of things: fading, moving, levers, sliders, doors, inputs, etc.

    Smoothing movement between any two particular values:

    https://forum.unity.com/threads/beginner-need-help-with-smoothdamp.988959/#post-6430100

    You have currentQuantity and desiredQuantity.
    - only set desiredQuantity
    - the code always moves currentQuantity towards desiredQuantity
    - read currentQuantity for the smoothed value

    Works for floats, Vectors, Colors, Quaternions, anything continuous or lerp-able.

    In your case you would set the door angle to either 0 (closed) or 90 (open) and let it take care of itself.

    The code: https://gist.github.com/kurtdekker/fb3c33ec6911a1d9bfcb23e9f62adac4

    Another approach would be to use a tweening package such as LeanTween, DOTween or iTween.

    OR... for a door, just make a simple canned animation... No code needed!
     
  5. liccardi

    liccardi

    Joined:
    Dec 6, 2018
    Posts:
    16
    I tried with the animation, but I don't like the final effect, when the door opens/closes during its cycle it makes strange movements, I changed the code a bit so as to work only on its y axis and not all the axes, but the door doesn't open

    Code (CSharp):
    1. using System.Collections;
    2. using UnityEngine;
    3.  
    4. public class DoorsWithoutKey : MonoBehaviour
    5. {
    6.     public bool open = false;
    7.  
    8.     [Header("New float")]
    9.     [SerializeField] private float openY;
    10.  
    11.     public void Toggle()
    12.     {
    13.         open = !open;
    14.         StopAllCoroutines();
    15.  
    16.         if (open)
    17.         {
    18.             StartCoroutine(OpenRoutine());
    19.         }
    20.         else
    21.         {
    22.             StartCoroutine(CloseRoutine());
    23.         }
    24.     }
    25.  
    26.     IEnumerator OpenRoutine()
    27.     {
    28.         var rot = gameObject.transform.eulerAngles;
    29.  
    30.         var currentY = gameObject.transform.eulerAngles.y;
    31.  
    32.         while (currentY < openY)
    33.         {
    34.             Debug.Log("Porta Aperta");
    35.             currentY = Mathf.Lerp(rot.x, openY, 0.05f);
    36.  
    37.             var newRot = Quaternion.Euler(rot.x, currentY, rot.z);
    38.             yield return null;
    39.         }    
    40.     }
    41.  
    42.     IEnumerator CloseRoutine()
    43.     {
    44.         var currentY = transform.localEulerAngles.y;
    45.  
    46.         var rot = transform.localRotation;
    47.  
    48.         while (currentY < openY)
    49.         {
    50.             currentY = Mathf.Lerp(currentY, openY, 0.05f);
    51.  
    52.             var newRot = Quaternion.Euler(rot.x, currentY, rot.z);
    53.             yield return null;
    54.         }      
    55.     }
    56. }
    57.  
     
  6. samana1407

    samana1407

    Joined:
    Aug 23, 2015
    Posts:
    76
    You can improve your script by adding some settings to the inspector, such as angles for the open and closed door positions, as well as the speed. I also think it's better to rotate the object along its local axes since the door itself may be initially positioned anywhere.

    Code (CSharp):
    1. using System.Collections;
    2. using UnityEngine;
    3.  
    4. public class DoorsWithoutKey : MonoBehaviour
    5. {
    6.     public float CloseY = 0f;
    7.     public float OpenY = 90f;
    8.  
    9.     [Space]
    10.     [Min(0.1f)] public float SpeedSec = 1f;
    11.  
    12.     [field: SerializeField]
    13.     public bool IsOpen { get; private set; }  // open/close state in inspector only
    14.  
    15.     private float _progress = 0;
    16.     private float _targetProgress = 0;
    17.  
    18.     // apply door state in editor mode
    19.     private void OnValidate()
    20.     {
    21.         var rotation = transform.localEulerAngles;
    22.  
    23.         if (IsOpen)
    24.         {
    25.             _progress = _targetProgress = 1f;
    26.             rotation.y = OpenY;
    27.         }
    28.         else
    29.         {
    30.             _progress = _targetProgress = 0f;
    31.             rotation.y = CloseY;
    32.         }
    33.  
    34.         transform.localEulerAngles = rotation;
    35.     }
    36.  
    37.     public void Toggle()
    38.     {
    39.         IsOpen = !IsOpen;
    40.         ApplyDoorState();
    41.     }
    42.  
    43.     public void Open()
    44.     {
    45.         IsOpen = true;
    46.         ApplyDoorState();
    47.     }
    48.  
    49.     public void Close()
    50.     {
    51.         IsOpen = false;
    52.         ApplyDoorState();
    53.  
    54.     }
    55.  
    56.     private void ApplyDoorState()
    57.     {
    58.         StopAllCoroutines();
    59.         StartCoroutine(DoorRoutine());
    60.     }
    61.  
    62.     IEnumerator DoorRoutine()
    63.     {
    64.         var speed = 1f / SpeedSec;
    65.         _targetProgress = 1f;
    66.  
    67.         if (IsOpen == false)
    68.         {
    69.             speed = -speed;
    70.             _targetProgress = 0;
    71.         }
    72.  
    73.         while (_progress != _targetProgress)
    74.         {
    75.             _progress += speed * Time.deltaTime;
    76.             _progress = Mathf.Clamp01(_progress);
    77.  
    78.  
    79.             var localRotation = transform.localEulerAngles;
    80.             localRotation.y = Mathf.Lerp(CloseY, OpenY, _progress);
    81.             transform.localEulerAngles = localRotation;
    82.  
    83.             yield return null;
    84.         }
    85.  
    86.     }
    87.  
    88. }
     
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,951
    Then fix it! You can do ANYTHING with animation. It's basically a time machine. Work through tutorials until you get the hang of it. Truly mastering animation will take you a lifetime. Get started now.