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

Unity3D中控制角色旋转路径的技术问题求助

Custom Rotation Path for Top-Down 2.5D Shooter

Got it, let's work through this custom rotation behavior you need. The default Quaternion.LookRotation() takes the shortest path, but we need to force that specific detour: rotate X to ±90°, flip Y instantly, then rotate X to the final target. Here's a step-by-step implementation using a state machine to control each phase:

Core Approach

We'll split the rotation into 3 distinct phases and track progress with a state enum. This lets us enforce the exact path instead of letting Unity take the shortest route:

  1. Phase 1: Smoothly rotate the X-axis to either +90° or -90° (we'll pick the direction based on the target to keep movement logical)
  2. Phase 2: Instantly snap the Y-axis to the target's Y rotation (one-frame flip)
  3. Phase 3: Smoothly rotate the X-axis from ±90° to the final target X rotation

Implementation Code

Here's a complete C# script you can attach to your player character:

using UnityEngine;

public class CustomPlayerRotation : MonoBehaviour
{
    [Header("Rotation Settings")]
    public float rotationSpeed = 5f;
    public float angleThreshold = 0.5f; // How close we need to be to consider a phase complete

    private enum RotationPhase
    {
        Idle,
        RotateToXExtreme,
        FlipY,
        RotateToTargetX
    }

    private RotationPhase currentPhase = RotationPhase.Idle;
    private Vector3 targetWorldPosition;
    private Quaternion targetRotation;
    private float targetXExtreme; // Will be +90 or -90

    void Update()
    {
        // Handle mouse click to set target position
        if (Input.GetMouseButtonDown(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            if (Physics.Raycast(ray, out RaycastHit hit))
            {
                targetWorldPosition = hit.point;
                StartCustomRotation();
            }
        }

        // Process rotation phases
        switch (currentPhase)
        {
            case RotationPhase.RotateToXExtreme:
                RotateToXExtreme();
                break;
            case RotationPhase.FlipY:
                CompleteYFlip();
                break;
            case RotationPhase.RotateToTargetX:
                RotateToFinalX();
                break;
        }
    }

    private void StartCustomRotation()
    {
        // Calculate target rotation using LookRotation first, then extract Euler angles
        Vector3 directionToTarget = targetWorldPosition - transform.position;
        directionToTarget.y = 0; // Keep it horizontal for top-down perspective
        targetRotation = Quaternion.LookRotation(directionToTarget);
        Vector3 targetEuler = targetRotation.eulerAngles;

        // Decide whether to rotate to +90 or -90 on X-axis (adjust logic to match your game)
        // Example: Use +90 if target is to the right, -90 if to the left
        targetXExtreme = targetEuler.y > 180 ? -90f : 90f;

        currentPhase = RotationPhase.RotateToXExtreme;
    }

    private void RotateToXExtreme()
    {
        // Create a temp rotation with current Y, target X extreme, 0 Z
        Quaternion targetPhaseRotation = Quaternion.Euler(targetXExtreme, transform.rotation.eulerAngles.y, 0);
        
        // Smoothly rotate towards this phase target
        transform.rotation = Quaternion.Lerp(transform.rotation, targetPhaseRotation, rotationSpeed * Time.deltaTime);

        // Check if we've reached the X extreme (handle 360° wrap-around)
        float currentX = transform.rotation.eulerAngles.x;
        float adjustedCurrentX = currentX > 180 ? currentX - 360 : currentX;
        if (Mathf.Abs(adjustedCurrentX - targetXExtreme) < angleThreshold)
        {
            currentPhase = RotationPhase.FlipY;
        }
    }

    private void CompleteYFlip()
    {
        // Instantly set Y rotation to target Y, keep X at extreme, Z at 0
        Vector3 currentEuler = transform.rotation.eulerAngles;
        transform.rotation = Quaternion.Euler(targetXExtreme, targetRotation.eulerAngles.y, 0);
        
        currentPhase = RotationPhase.RotateToTargetX;
    }

    private void RotateToFinalX()
    {
        // Smoothly rotate from X extreme to target X rotation
        transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);

        // Check if we've reached the final target
        if (Quaternion.Angle(transform.rotation, targetRotation) < angleThreshold)
        {
            currentPhase = RotationPhase.Idle;
        }
    }
}

Key Explanations

  • State Machine: The RotationPhase enum ensures we follow the exact rotation sequence, no shortcuts allowed.
  • X Extreme Selection: The code picks between +90° and -90° based on the target's Y rotation—adjust this logic if you want to force a specific direction, or tie it to the target's position relative to the player.
  • Euler Angle Handling: We convert quaternions to Euler angles to isolate X/Y rotations, and handle 360° wrap-around (like 270° being equivalent to -90°) to avoid bugs.
  • Threshold Check: Using a small angleThreshold prevents infinite loops, since Quaternion.Lerp approaches the target asymptotically and never hits it exactly.

Adjustments for Your Game

  • Tweak rotationSpeed to make X-axis rotations faster or slower.
  • Modify the targetXExtreme logic if you want to always use +90° or -90°, regardless of the target position.
  • If your character uses a different axis setup (e.g., Z instead of X for tilt), swap the axis references in the Euler angle code.

内容的提问来源于stack exchange,提问作者Fabio S.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:56:26