Soy novato aquí, pero intentaré describirlo lo más claro que pueda. (no es tan importante, solo para aclarar) Entonces, quiero rotar un objeto 405 grados en 1 segundo solo una vez , cuando se presiona el espacio. Pensé que debería hacerse usando rutinas, así que escribí algo como esto:
private void Update() { if (Input.GetKeyDown(KeyCode.Space)) { StopAllCoroutines(); //to prevent overlapping StartCoroutine(Rotate()); } } IEnumerator Rotate() { //where final finalRotation is a rotation i want to get in a result Quaternion finalRotation = Quaternion.Euler(0, 0, 405) * transform.rotation; /* using do..while to make sure that object will rotate even in case it's in same rotation as finalRotation */ do { //should smoothly rotate an object for 405deg in 1 sec but it doesnt transform.Rotate(Vector3.forward, 405f * Time.deltaTime / 1f); } while (transform.rotation != finalRotation); yield return 1; }El código anterior funciona bien y todo está bien, excepto uno, gira un objeto al instante y no sin problemas . Quiero decir, si uso esa línea de código en Update, todo sale bien.
transform.Rotate(Vector3.forward, 405f * Time.deltaTime / 1f);Entonces mis preguntas:
¿Por qué gira suavemente en Update, pero instantáneamente en la rutina?
y como se puede arreglar eso?
Gracias de antemano, una vez más, perdón si cometí algunos errores al hacer un tema.
Se actualiza instantáneamente en la rutina porque solo cedes cuando se completa la rotación. El marco no se renderizará hasta que cada corrutina pendiente/en ejecución ceda o se complete, por lo que aquí se completa la rotación y finalmente se renderiza el fotograma, lo que lo convierte en una rotación instantánea.
En su lugar, debe ceder en el bucle.
También debe tener en cuenta que Quaternion finalRotation = Quaternion.Euler(0, 0, 405) * transform.rotation; y transform.Rotate(Vector3.forward, 405f); puede tener diferentes resultados dependiendo de las rotaciones del objeto principal, porque rotan en diferentes espacios, el primero rotando en global y el segundo rotando en local. Esto puede resultar en que el ciclo, como está escrito, en realidad nunca termine.
Otro problema es que no hay garantía de que la suma de los valores de Time.deltaTime alguna vez sume 1f. Supongamos que en el primer fotograma se produce un retraso, lo que provoca que Time.deltaTime sea enorme, 2f . Puedes ver cómo nunca podría terminar como resultado. Como alternativa, debe recordar la rotación de inicio, luego, en cada cuadro, calcular la rotación de ese cuadro y luego aplicarla a ese cuadro.
En total:
IEnumerator Rotate() { Quaternion startRotation = transform.rotation; float endZRot = 405f; float duration = 1f; float t = 0; while (t < 1f) { time = Mathf.Min(1f, t + Time.deltaTime/duration); Vector3 newEulerOffset = Vector3.forward * (endZRot * t); // global z rotation transform.rotation = Quaternion.Euler(newEulerOffset) * startRotation; // local z rotation // transform.rotation = startRotation * Quaternion.Euler(newEulerOffset); yield return null; } }yield return null esperará un cuadro dentro de una rutina. Ahora mismo has colocado el yield return 1; fuera del bucle while, por lo que no hará nada. En esta situación, me perdería entre las dos rotaciones en un bucle while que va de 0->1
o (si no quiere hacer nada de esto y no le importa un poco la hinchazón) use leantween, https://assetstore.unity.com/packages/tools/animation/leantween-3595
En el lugar donde lo gira un incremento, debe esperar un tiempo. Tratar
yield return new WaitForSeconds(0.1);Además, mientras estaba escribiendo esto, alguien más respondió.