如何根据玩家方向调整对象旋转?

How to adjust object rotation based on player direction?

我正在尝试创建一个 2D 俯视射击游戏。我想设置一种方式让玩家在他移动的方向上拿着枪。例如,如果玩家按住 W 和 A 键,他的枪指向右上方向。随着他方向的切换,枪也顺畅地切换。如果玩家直线上升(例如按住W键),则整个玩家切换方向。

我已经设法复制了这个,但只在 6 个方向上复制。但是,我想让它随着玩家的移动和所有其他方向变得平滑。 我知道对此必须有一个简单的答案,我就是想不通。这是我的代码,函数以它们的用途命名:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    [Header("Character Attributes:")]
    public float movementBaseSpeed = 1.0f;

    [Space]
    [Header("Weapon Statistics:")]
    public float upwardSideAngle = 30f;
    public float downwardSideAngle = -30f;
    public float idleAngle = -10f;

    [Space]
    [Header("Character Statistics:")]
    public Vector2 currentMovementDirection;
    public float currentMovementSpeed;

    [Space]
    [Header("References:")]
    public Rigidbody2D rb;
    public Animator animator;
    public GameObject weapon;

    // Update is called once per frame
    void Update()
    {
        ProcessInputs();
        Move();
        Animate();
        MoveAim();
    }

    void ProcessInputs()
    {
        currentMovementDirection = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
        currentMovementSpeed = Mathf.Clamp(currentMovementDirection.magnitude, 0.0f, 1.0f);
        currentMovementDirection.Normalize();
    }

    void Animate()
    {
        if (currentMovementDirection != Vector2.zero)
        {
            animator.SetFloat("Horizontal", currentMovementDirection.x);
            animator.SetFloat("Vertical", currentMovementDirection.y);
        }
        animator.SetFloat("Magnitude", currentMovementDirection.magnitude);
    }

    void Move()
    {
        rb.velocity = currentMovementDirection * currentMovementSpeed * movementBaseSpeed;
    }

    void MoveAim()
    {
        //When player is moving left
        if(currentMovementDirection.x < 0)
        {
            weapon.transform.rotation = Quaternion.Euler(0, 180, 0);
        }
        //When player is moving right
        else if(currentMovementDirection.x > 0)
        {
            weapon.transform.rotation = Quaternion.identity;
        }
        //When player is moving top right
        if(currentMovementDirection.y > 0 && currentMovementDirection.x > 0)
        {
            weapon.transform.rotation = Quaternion.Euler(0f, 0f, upwardSideAngle);
        }
        //When player is moving bottom right
        if(currentMovementDirection.y < 0 && currentMovementDirection.x > 0)
        {
            weapon.transform.rotation = Quaternion.Euler(0f, 0f, downwardSideAngle);
        }
        //When player is moving top left
        if(currentMovementDirection.y > 0 && currentMovementDirection.x < 0)
        {
            weapon.transform.rotation = Quaternion.Euler(0, 180, upwardSideAngle);
        }
        //When player is moving bottom left
        if (currentMovementDirection.y < 0 && currentMovementDirection.x < 0)
        {
            weapon.transform.rotation = Quaternion.Euler(0, 180, downwardSideAngle);
        }
        //When player is standing still
        if (currentMovementDirection.y == 0 && currentMovementDirection.x == 0)
        {
            weapon.transform.rotation = Quaternion.Euler(0f, 0f, idleAngle);
        }
    }
}

另一种描述您想要的方式是您希望枪支的本地 right 指向您移动的方向,而本地 upVector3.up 尽可能接近尽可能。 (出于数学目的,您可以互换使用 Vector3 和 Vector2。)

如果你能解决你想要的枪支变换的向前和向上的方向,你可以使用Quaternion.LookRotation(Vector3 forwardDirection, Vector3 upDirection)来计算枪支变换的旋转。

这是一种使用矢量数学求解方向并使用 Quaternion.LookRotation 分配旋转的方法。

void MoveAim()
{
    Vector3 gunRight = currentMovementDirection;
    Vector3 gunForward = Vector3.Cross(gunRight, Vector3.up);
    // Handle cases where the gun is pointing directly up or down
    if (gunForward == Vector3.zero)
    {
        gunForward = Vector3.forward;
    }

    Vector3 gunUp = Vector3.Cross(gunForward, gunRight);

    weapon.transform.rotation = Quaternion.LookRotation(gunForward, gunUp);

    //When player is standing still
    if (currentMovementDirection == Vector2.zero)
    {
        weapon.transform.rotation = Quaternion.Euler(0f, 0f, idleAngle);
    }
}