首页 > 解决方案 > Unity C#:transform.up 不会随着对象旋转而更新

问题描述

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

public class PlayerMovement : MonoBehaviour
{
    public GameObject player;
    public Rigidbody2D playerRB;
    public Transform playerTF;

    public float moveForce;
    public float rotateForce;

    private string currentMoveKey = "";
    private string currentRotateKey = "";

    void Update()
    {
        //move
        if(Input.GetKey("w") && currentMoveKey == "")
        {
            currentMoveKey = "w";

            playerRB.AddForce(transform.up * moveForce * Time.deltaTime);
        }

        if (Input.GetKeyUp("w") && currentMoveKey == "w")
        {
            playerRB.velocity = new Vector2(0, 0);//resets when keyup and not already reset

            currentMoveKey = "";
        }

        if (Input.GetKey("s") && currentMoveKey == "")
        {
            currentMoveKey = "s";

            playerRB.AddForce(transform.up * -moveForce * Time.deltaTime);
        }

        if (Input.GetKeyUp("s") && currentMoveKey == "s")
        {
            playerRB.velocity = new Vector2(0, 0);

            currentMoveKey = "";
        }
        //rotate
        if (Input.GetKeyDown("a") && currentRotateKey == "")
        {
            currentRotateKey = "a";
        }
        if (Input.GetKey("a") && currentRotateKey == "a")
        {
            playerTF.Rotate(transform.forward * rotateForce * Time.deltaTime);
        }
        if (Input.GetKeyUp("a") && currentRotateKey == "a")
        {
            currentRotateKey = "";
        }

        if (Input.GetKeyDown("d") && currentRotateKey == "")
        {
            currentRotateKey = "d";
        }
        if (Input.GetKey("d") && currentRotateKey == "d")
        {
            playerTF.Rotate(transform.forward * -rotateForce * Time.deltaTime);
        }
        if (Input.GetKeyUp("d") && currentRotateKey == "d")
        {
            currentRotateKey = "";
        }
    }
}

嘿!出于某种原因,在我将强制添加到 RigidBody2D 的行中,如果我在玩家移动的同时旋转玩家 - 从而改变 transform.up 指向的位置 - 玩家继续朝他最初指向的方向移动. 换句话说,他看起来像是在滑动,我必须停止移动并再次开始移动以更新他指向的方向。我能做些什么来解决这个问题,以便当他旋转时,他移动的方向会同时更新?

标签: c#unity3dtransform

解决方案


增加力只会不断增加刚体的动量;你已经明白了这一点,因为当你举起钥匙时你一直在重置你的速度。当您转动但继续向下移动时,您的刚体速度不会被重置,只是被附加地改变。

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

public class PlayerMovement : MonoBehaviour
{
    public GameObject player;
    public Rigidbody2D playerRB;
    public Transform playerTF;

    public float moveForce;
    public float rotateForce;

    private Vector3 movement;

    private string currentRotateKey = "";

    void Update()
    {
        //move in Local space
        if (Input.GetKeyDown(KeyCode.W))
        {
            movement += Vector3.up;
        }

        if (Input.GetKeyUp(KeyCode.W))
        {
            movement -= Vector3.up;
        }

        if (Input.GetKeyDown(KeyCode.S))
        {
            movement -= Vector3.up;
        }

        if (Input.GetKeyUp(KeyCode.S))
        {
            movement += Vector3.up;
        }

        //rotate
        if (Input.GetKeyDown("a") && currentRotateKey == "")
        {
            currentRotateKey = "a";
        }
        if (Input.GetKey("a") && currentRotateKey == "a")
        {
            playerTF.Rotate(transform.forward * rotateForce * Time.deltaTime);
        }
        if (Input.GetKeyUp("a") && currentRotateKey == "a")
        {
            currentRotateKey = "";
        }

        if (Input.GetKeyDown("d") && currentRotateKey == "")
        {
            currentRotateKey = "d";
        }
        if (Input.GetKey("d") && currentRotateKey == "d")
        {
            playerTF.Rotate(transform.forward * -rotateForce * Time.deltaTime);
        }
        if (Input.GetKeyUp("d") && currentRotateKey == "d")
        {
            currentRotateKey = "";
        }

        // Implicit cast from Vector3 to Vector2, takes X and Ys
        ApplyMovement(movement);
    }

    public void ApplyMovement(Vector2 movement)
    {
        playerRB.velocity = player.transform.TransformDirection(movement.x, movement.y, 0) * moveForce * Time.deltaTime;
    }
}

我发现使用KeyCode枚举而不是字符串值更简洁一些,而且我喜欢跟踪Vector3 movement类的本地而不是检查currentMovementKey. 这使您可以一次按下多个键,并在编译时捕获拼写错误。

将你“应用”你的动作的地方移动到它自己的方法中有助于在你想要的时候改变你的行为。

movement在本地空间中处理,使用Vector3.up而不是transform.up避免旋转时出现错误,然后当应用于 时,playerRB.velocity我们可以使用转换回世界空间player.transform.TransformDirection(movement.x, movement.y, 0)transform.TransformDirection(movement.x, movement.y, 0)如果此组件与 RigidBody2D 组件位于同一 GameObject 上也可能)。

如果您希望仍然有加速度,而不是在速度上跳跃和回落,但又不想像真实物体那样有任何漂移,事情会变得有点棘手,这是解决该问题的一种方法:

    public void ApplyMovement(Vector3 movement)
    {
        if (movement.sqrMagnitude > Mathf.Epsilon)
        {
            playerRB.drag = 0; // or some other small value
            if (playerRB.velocity.sqrMagnitude > Mathf.Epsilon)
            {
                playerRB.velocity = player.transform.TransformDirection(movement.normalized) * playerRB.velocity.magnitude;
            }

            playerRB.AddRelativeForce(movement * moveForce * Time.deltaTime);
        }
        else
        {
            playerRB.drag = 100f; // or some other value larger than the small one
        }
    }

我们现在正在做的是检查我们是否有不可忽略的(基本上为 0)的运动量来应用,如果是,那么我们不会施加阻力,因为那样我们会减慢我们的正加速度这使得在设置游戏时很难预测你应该拥有什么值。

由于我们现在对物体没有阻力,它应该根据物理学漂移。这就是你目前看到的。如果我们不希望这样,我们可以检查我们是否有不可忽略的(基本上为 0)速度量,并将其与我们想要的运动方向对齐。不要忘记它movement仍然在本地空间中,并且playerRB.velocity在世界空间中。

然后,由于我们要应用运动,我们应该将局部运动应用到我们的身体上,AddRelativeVelocity以继续朝着所需的方向加速。目前这会一直持续下去,但您可能希望最终限制您的最大速度。

如果我们不应用移动,我们希望物理应用拖动并减慢玩家的速度。如果我们让物理学做这项工作,你应该得到合理的(ish)加速来加速和减速(取决于你的阻力值和施加的力),但由于我们忽略了漂移,你应该立即转弯。


推荐阅读