You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中多次按键触发旋转导致八角形出现非预期角度问题求助

Fixing Mid-Rotation Button Spam for Your Unity Octagon

Hey there! Let's fix that wonky octagon rotation issue you're dealing with—you’re totally right about the problem being overlapping coroutines messing up your starting angles. Here’s a clean, robust way to handle it so your octagon always lands on those nice 45° increments, even if you spam the buttons mid-rotation:

Core Issues to Fix

  1. Multiple coroutines running at once: When you press a button mid-rotation, you’re starting a new coroutine that fights with the old one, leading to weird in-between angles.
  2. Using real-time rotation as the starting point: Instead of tracking your intended target angle, you’re basing new rotations on whatever the current half-rotated angle is.

The Solution Code

Here’s the revised script that addresses both problems:

using UnityEngine;

public class Movement : MonoBehaviour
{
    // Track the currently running rotation coroutine so we can stop it if needed
    private Coroutine _currentRotationCoroutine;
    // Maintain our intended target Z angle (always a multiple of 45°)
    private float _targetZAngle;
    // Make the rotation step a constant for easy tweaks (e.g., change to 60° for a hexagon)
    private const float RotationStep = 45f;

    void Start()
    {
        // Initialize our target angle to match the object's starting rotation (rounded to nearest 45°)
        _targetZAngle = Mathf.Round(transform.eulerAngles.z / RotationStep) * RotationStep;
        // Ensure the object starts exactly on a valid angle
        transform.eulerAngles = new Vector3(0, 0, _targetZAngle);
    }

    IEnumerator RotateOctagon(float angleDelta, float inTime)
    {
        float startAngle = transform.eulerAngles.z;
        // Update our target angle to the next valid increment
        _targetZAngle += angleDelta;
        // Normalize the target angle to stay within 0-360° (avoids negative angles or overflow)
        _targetZAngle = Mathf.Repeat(_targetZAngle, 360f);

        float elapsedTime = 0f;
        while (elapsedTime < inTime)
        {
            elapsedTime += Time.deltaTime;
            // Use a 0-1 t value for smooth interpolation
            float t = elapsedTime / inTime;
            // LerpAngle handles 360° wrap-around correctly (e.g., 350° → 10° takes the short path)
            float currentAngle = Mathf.LerpAngle(startAngle, _targetZAngle, t);
            transform.eulerAngles = new Vector3(0, 0, currentAngle);
            yield return null;
        }
        // Ensure we end exactly on the target angle (no tiny floating-point errors)
        transform.eulerAngles = new Vector3(0, 0, _targetZAngle);
        // Clear the coroutine reference once finished
        _currentRotationCoroutine = null;
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.LeftArrow))
        {
            // Stop any ongoing rotation before starting a new one
            if (_currentRotationCoroutine != null)
            {
                StopCoroutine(_currentRotationCoroutine);
            }
            _currentRotationCoroutine = StartCoroutine(RotateOctagon(RotationStep, 0.1f));
        }

        if (Input.GetKeyDown(KeyCode.RightArrow))
        {
            if (_currentRotationCoroutine != null)
            {
                StopCoroutine(_currentRotationCoroutine);
            }
            _currentRotationCoroutine = StartCoroutine(RotateOctagon(-RotationStep, 0.1f));
        }

        if (Input.GetKeyDown(KeyCode.UpArrow))
        {
            if (_currentRotationCoroutine != null)
            {
                StopCoroutine(_currentRotationCoroutine);
            }
            // 180° is 4x our 45° step
            _currentRotationCoroutine = StartCoroutine(RotateOctagon(RotationStep * 4, 0.1f));
        }
    }
}

How This Works

  • Stopping old coroutines: We store a reference to the active rotation coroutine. When a new button is pressed, we stop the old one immediately—no more overlapping rotation logic.
  • Target angle tracking: _targetZAngle always holds the valid, 45°-aligned angle we want to end up at. Even if we press a button mid-rotation, we just calculate the next valid target from this variable, not the object's current half-rotated angle.
  • Angle normalization: Mathf.Repeat keeps our target angle between 0-360°, so we don't get weird negative angles or values over 360° that can break Euler angle logic.
  • Smooth, correct interpolation: Mathf.LerpAngle ensures rotations take the shortest path around the circle, which is perfect for polygon rotations.

Example Behavior (Matching Your Request)

If your octagon starts at 0°, you press right (rotating toward -45°), and then press left when it’s at 30°:

  1. The right-rotation coroutine is stopped immediately.
  2. We calculate the new target angle: -45° + 45° = 0°.
  3. A new coroutine starts, smoothly rotating the octagon from its current 30° back to 0°—exactly what you wanted!

内容的提问来源于stack exchange,提问作者Daniel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 23:27:28