#c# #unity3d
Вопрос:
Я довольно новичок в unity, и после того, как я просмотрел темы о поворотах кадров, мне удалось найти код, который помог бы мне получить тот вид, который я хотел для своей игры, вот код для движения:
public class Movement : MonoBehaviour { IEnumerator RotateOctagon(Vector3 byAngles, float inTime) { var fromAngle = transform.rotation; var toAngle = Quaternion.Euler(transform.eulerAngles byAngles); for(var t = 0f; t lt;= 1; t = Time.deltaTime / inTime) { transform.rotation = Quaternion.Lerp(fromAngle, toAngle, t); yield return null; } transform.rotation = toAngle; } // Update is called once per frame void Update() { if (Input.GetKeyDown("left")) { StartCoroutine(RotateOctagon(Vector3.forward * 45, 0.1f)); } if (Input.GetKeyDown("right")) { StartCoroutine(RotateOctagon(Vector3.forward * -45, 0.1f)); } if (Input.GetKeyDown("up")) { StartCoroutine(RotateOctagon(Vector3.forward * 180, 0.1f)); } } }
И это приводит к желаемым результатам — перемещению восьмиугольника на его следующую сторону, предполагая, что вы подождете, пока вращение не закончится…
Но проблема возникает, когда вы нажимаете влево или вправо в середине анимации, в которой восьмиугольник неправильно заканчивается на точке или странном угле (не кратном 45 градусам)…
My guess is that if the octagon is in the middle of the coroutine of rotating to the right say, at 30 degrees, any immediate key press will now rotate from that angle, ending up being 30 — 45 an unwanted angle.
I considered calculating the offset of the angle to the lower/higher 45 degree angle multiple, but I feel like there’s a more correct approach and something I’m missing about coroutines that would help this.
Any help on how to get the octagon to rotate properly under the condition that multiple keys are pressed would be greatly appreciated.
Desired behavior: Say the current z axis is 0. After right is pressed and in the middle of rotating, left is pressed at 30 degrees. The octagon should rotate back to z=0
Ответ №1:
Чтобы просто не разрешать новую процедуру до тех пор, пока предыдущая не завершится, просто введите флаг bool
private bool isRotating; IEnumerator RotateOctagon(Vector3 byAngles, float inTime) { if(isRotating) yield break; isRotating = true; var fromAngle = transform.rotation; var toAngle = Quaternion.Euler(transform.eulerAngles byAngles); for(var t = 0f; t lt;= 1; t = Time.deltaTime / inTime) { transform.rotation = Quaternion.Lerp(fromAngle, toAngle, t); yield return null; } transform.rotation = toAngle; isRotating = false; }
Таким образом, ваш ввод в основном игнорируется до завершения предыдущей процедуры.
Чтобы быть более эффективным, вы также можете добавить
void Update() { if(isRotating) return; ... }
Или «причудливая» альтернатива без дополнительного флага: сделайте Start
себе сопрограмму и сделайте
IEnumerator Start () { while(true) { if (Input.GetKeyDown("left")) { // This now rotates and waits at the same time until the rotation is finished yield return RotateOctagon(Vector3.forward * 45, 0.1f)); } else if (Input.GetKeyDown("right")) { yield return RotateOctagon(Vector3.forward * -45, 0.1f)); } else if (Input.GetKeyDown("up")) { yield return RotateOctagon(Vector3.forward * 180, 0.1f)); } else { // If none of the previous is true wait at least one frame yield return null; } } }
В качестве альтернативы, поскольку теперь мы знаем, что вы хотите скорее прервать текущую ротацию и начать новую, сохраните ее в поле, например
private float rotation; void Awake() { rotation = transform.localEulerAngles.z; } void Update() { if (Input.GetKeyDown("left")) { RotateAbout (45); } if (Input.GetKeyDown("right")) { RotateAbout (-45); } if (Input.GetKeyDown("up")) { RotateAbout (180); } } private void RotateAbout(float angle) { StopAllCoroutines (); rotation = angle; StartCoroutine(RotateOctagon(rotation, 0.1f)); }
и тогда скорее сделайте
IEnumerator RotateOctagon(float toAngle, float inTime) { var fromRotation = transform.localRotation; var toRotation = Quaternion.Euler(Vector3.forward * toAngle); for(var t = 0f; t lt;= 1; t = Time.deltaTime / inTime) { transform.localRotation = Quaternion.Lerp(fromRotation, toRotation, t); yield return null; } transform.localRotation = toRotation; }
Комментарии:
1. @derHugo Потрясающе! Я застрял на этом в течение последних двух дней, а ты так быстро придумал это! Протестировал его и отлично сработал — еще раз спасибо. Я надеюсь, что у меня будет такая интуиция, когда я узнаю больше о Unity 🙂