如何让角色转向相机的方向? [Unity3D]

Posted

技术标签:

【中文标题】如何让角色转向相机的方向? [Unity3D]【英文标题】:How to get a character to turn in the direction of the camera? [Unity3D] 【发布时间】:2021-11-01 23:58:00 【问题描述】:

我遇到了一个障碍,当我移动相机时,在移动时,角色会在原地旋转,但是当我更新左摇杆时,他们前进的方向会改变。

这很奇怪,因为在 Update 中更新它不起作用并强制角色绕圈移动并将其放置在一些脚本中,使用右摇杆进行更新会导致角色旋转和移动非常不同我希望它进入的方向。这在我移动左摇杆时暂时固定,更新角色的移动。

对此的控制是:左拇指 - 移动玩家,右拇指 - 移动相机,东按钮 - 跳跃,北按钮 - 运行。

我们的目标是让角色在我移动相机时旋转自己以及他们的方向,而不是只在我移动左摇杆时更新他们的方向。

在代码之前,这些是我目前在 Unity 中使用的影响这一点的包:Cinemachine & Input System。

这是正在影响的移动代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Cinemachine;
using UnityEngine.AI;
using UnityEngine.InputSystem;

public class PlayerMovement : MonoBehaviour

    private DefaultControls controls;

    [Header("Unity General")]
    [SerializeField]
    private CharacterController controller;
    public Transform cameraTransform;
    public InputActionReference cameraControl;

    [Header("General Settings")]//Player movement.
    public bool canMovePlayer;
    private Vector2 currentMovementInput;
    private Vector3 currentMovement;
    private Vector3 currentRunMovement;
    private bool isMovementPressed;
    private bool isRunPressed;
    [Space]//Animator stuff.
    public Animator characterAnimator;
    private int isWalkingHash;
    private int isRunningHash;
    [Space]//Player running speed & how fast the player will turn when going left or right.
    public float rotationFactorPerFrame = 15.0f;
    public float runMultiplier = 3.0f;
    [Space]//Default gravity for when the player is falling and gravity for when the player is grounded.
    public float gravity = -9.81f;
    public float groundedGravity = -0.05f;
    [Space]//Playing jumping.
    public float initialJumpVelocity;
    private bool isJumpPressed = false;
    private float maxJumpHeight = 1f;
    private float maxJumpTime = 0.5f;
    private bool isJumping = false;
    private int isJumpingHash;
    private bool isJumpAnimating = false;

    private void Start()
    
        Cursor.lockState = CursorLockMode.Locked;

        npcInteraction = GetComponent<NPCInteraction>();
    

    private void Awake()
    
        controls = new DefaultControls();
        controller = GetComponent<CharacterController>();

        isWalkingHash = Animator.StringToHash("isWalking");
        isRunningHash = Animator.StringToHash("isRunning");
        isJumpingHash = Animator.StringToHash("isJumping");

        controls.Movement.Walking.started += OnMovementInput;
        controls.Movement.Walking.canceled += OnMovementInput;
        controls.Movement.Walking.performed += OnMovementInput;
        controls.Movement.Run.started += OnRun;
        controls.Movement.Run.canceled += OnRun;
        controls.Movement.Jump.started += OnJump;
        controls.Movement.Jump.canceled += OnJump;

        SetupJumpVariables();
    

    private void SetupJumpVariables()
    
        float timeToApex = maxJumpTime / 2;
        gravity = (-2 * maxJumpHeight) / Mathf.Pow(timeToApex, 2);
        initialJumpVelocity = (2 * maxJumpHeight) / timeToApex;
    

    private void HandleJump()
    
        if (!isJumping && controller.isGrounded && isJumpPressed)
        
            characterAnimator.SetBool(isJumpingHash, true);
            isJumpAnimating = true;
            isJumping = true;
            currentMovement.y = initialJumpVelocity * 0.5f;
            currentRunMovement.y = (initialJumpVelocity + 0.5f) * 0.5f;
        
        else if (!isJumpPressed && isJumping && controller.isGrounded)
        
            isJumping = false;
        
    

    private void OnJump(InputAction.CallbackContext context)
    
        isJumpPressed = context.ReadValueAsButton();
    

    private void OnRun(InputAction.CallbackContext context)
    
        isRunPressed = context.ReadValueAsButton();
    

    private void HandleRotation()
    
        Vector3 positionToLookAt;

        //Change in position our character should point to.
        positionToLookAt.x = currentMovement.x;
        positionToLookAt.y = 0.0f;
        positionToLookAt.z = currentMovement.z;

        //Current rotation of our character.
        Quaternion currentRotation = transform.rotation;

        if (currentMovementInput != Vector2.zero)
        
            //Creates a new rotation based on where the player is currently pressing.
            float targetAngle = Mathf.Atan2(currentMovementInput.x, currentMovementInput.y) * Mathf.Rad2Deg + cameraTransform.eulerAngles.y;
            Quaternion targetRotation = Quaternion.Euler(0f, targetAngle, 0f);
            transform.rotation = Quaternion.Lerp(currentRotation, targetRotation, rotationFactorPerFrame * Time.deltaTime);
        
    

    private void OnMovementInput(InputAction.CallbackContext context)
    
        currentMovementInput = context.ReadValue<Vector2>();
        currentMovement = new Vector3(currentMovementInput.x, 0f, currentMovementInput.y);
        currentRunMovement.x = currentMovementInput.x * runMultiplier;
        currentRunMovement.z = currentMovementInput.y * runMultiplier;
        MovementDirection();
        isMovementPressed = currentMovementInput.x != 0 || currentMovementInput.y != 0;
    

    private void MovementDirection()
    
        currentMovement = cameraTransform.forward * currentMovement.z + cameraTransform.right * currentMovement.x;
        currentMovement.y = 0f;

        currentRunMovement = cameraTransform.forward * currentRunMovement.z + cameraTransform.right * currentRunMovement.x;
        currentRunMovement.y = 0f;
    

    private void HandleAnimation()
    
        bool isWalking = characterAnimator.GetBool(isWalkingHash);
        bool isRunning = characterAnimator.GetBool(isRunningHash);

        if (isMovementPressed && !isWalking)
        
            characterAnimator.SetBool(isWalkingHash, true);
        
        else if (!isMovementPressed && isWalking)
        
            characterAnimator.SetBool(isWalkingHash, false);
        

        if ((isMovementPressed && isRunPressed) && !isRunning)
        
            characterAnimator.SetBool(isRunningHash, true);
        
        else if ((!isMovementPressed || !isRunPressed) && isRunning)
        
            characterAnimator.SetBool(isRunningHash, false);
        
    

    private void HandleGravity()
    
        bool isFalling = currentMovement.y <= 0.0f;
        float fallMultiplier = 1.5f;

        if (controller.isGrounded)
        
            characterAnimator.SetBool(isJumpingHash, false);
            isJumpAnimating = false;
            currentMovement.y = groundedGravity;
            currentRunMovement.y = groundedGravity;
        
        else if (isFalling)
        
            float previousYVelocity = currentMovement.y;
            float newYVelocity = currentMovement.y + (gravity * fallMultiplier * Time.deltaTime);
            float nextYVelocity = (previousYVelocity + newYVelocity) * 0.5f;
            currentMovement.y = nextYVelocity;
            currentRunMovement.y = nextYVelocity;
        
        else
        
            float previousYVelocity = currentMovement.y;
            float newYVelocity = currentMovement.y + (gravity * Time.deltaTime);
            float nextYVelocity = (previousYVelocity + newYVelocity) * 0.5f;
            currentMovement.y = nextYVelocity;
            currentRunMovement.y = nextYVelocity;
        
    

    // Update is called once per frame
    public void Update()
    
        HandleRotation();
        HandleAnimation();

        controller.Move(currentMovement * Time.deltaTime);

        characterAnimator.SetFloat("Speed", controls.Movement.Walking.ReadValue<Vector2>().magnitude);

        if (isRunPressed)
        
            controller.Move(currentRunMovement * Time.deltaTime);
        
        else
        
            controller.Move(currentMovement * Time.deltaTime);
        

        HandleGravity();
        HandleJump();

        if (cameraControl.action.triggered)
        
            MovementDirection();
        

        LockOnTarget();
        Interaction();
    

    private void OnEnable()
    
        controls.Movement.Enable();
    

    private void OnDisable()
    
        controls.Movement.Disable();
    
```

【问题讨论】:

【参考方案1】:

在深入了解有关相机运动的非常深入的代码之前,请先找到一种简单的方法,即游戏对象可以以一种简单的方式面向相机的方向。以防万一它有帮助。这直接回答了您的问题“如何让角色转向相机的方向?”

using UnityEngine;

public class LookToCamForward : MonoBehaviour

    
    void Start()
    
        transform.rotation = Quaternion.LookRotation(Camera.main.transform.forward, Camera.main.transform.up);
    

【讨论】:

这似乎根本不起作用,为了解决问题,我希望角色在角色四处移动时随相机转动。这只会在我移动左摇杆时更新(这会移动角色),但我希望它在我移动相机时也更新,因为我使用的是输入系统包,所以这会改变一些事情,因为我不能使用旧的输入系统。

以上是关于如何让角色转向相机的方向? [Unity3D]的主要内容,如果未能解决你的问题,请参考以下文章

unity3D:游戏分解之角色移动和相机跟随

Unity3D:实现人物转向与移动

[Unity3D/2D]实现相机对人物角色的跟随效果/相机在一定范围内移动/内置插件实现

怎么用unity3d模拟吃鸡中的摄像机跟随

OpenGL模拟波斯王子相机

unity3D中使角色朝着鼠标的方向