【问题标题】:Rotate object in the direction it's moving in Unity在 Unity 中沿其移动方向旋转对象
【发布时间】:2023-04-05 00:37:01
【问题描述】:

我有一个 2D 对象,它直接向前移动,直到撞到另一个对象,其中物理材料导致对象从另一个对象反弹。

我不是最擅长绘图,但这里有一个我想要它做的说明:(球体中的箭头表示球体当前面向的方向)

我把它的物理部分写得很好,但是物理材料不会旋转游戏对象,所以实际结果看起来更像这样:

我知道你可以很容易地通过变换设置对象的旋转,但是你如何获得游戏对象的移动方向,然后将旋转设置为该方向?

【问题讨论】:

  • 他在问题标题中说Unity。 Unity 在 C# 中
  • @jwdonahue 对不起,我现在修好了。

标签: c# unity3d 2d


【解决方案1】:

首先,你需要知道图像的局部方向应该是指向运动的方向。这取决于您的设置,并且该问题不包含足够的信息来准确了解。可能是Vector3.upVector3.right。当然,世界方向是从速度得知的。

Vector3 worldDirectionToPointForward = rb2d.velocity.normalized;
Vector3 localDirectionToPointForward = Vector3.right;

然后,您希望围绕 z 轴旋转精灵,以使局部方向指向该方向。您可以使用transform.TransformDirection 找到球当前“指向”的方向,然后使用Vector3.SignedAngle 计算角度:

Vector3 currentWorldForwardDirection = transform.TransformDirection(
        localDirectionToPointForward);
float angleDiff = Vector3.SignedAngle(currentWorldForwardDirection, 
        worldDirectionToPointForward, Vector3.forward);

然后,使用 transform.Rotate 将其绕 z 轴旋转该量。

transform.Rotate(Vector3.forward, angleDiff);

我会在与墙壁发生碰撞后执行此操作。另一种方法是将其放在LateUpdate 中,尽管这可能会干扰其他单一行为中LateUpdate 中发生的其他事情。但是,LateUpdate 方法最容易演示,因此我将在此处演示:

void LateUpdate()
{
    Vector3 worldDirectionToPointForward = rb2d.velocity.normalized;
    Vector3 localDirectionToPointForward = Vector3.right;

    Vector3 currentWorldForwardDirection = transform.TransformDirection(
            localDirectionToPointForward);
    float angleDiff = Vector3.SignedAngle(currentWorldForwardDirection, 
            worldDirectionToPointForward, Vector3.forward);

    transform.Rotate(Vector3.forward, angleDiff, Space.World);
}

【讨论】:

    【解决方案2】:

    我目前无法对此进行测试,但以下应该可以工作。

    Vector3 prevPosition = Vector3.zero;
    
    void Update()
    {
        if(prevPosition != Vector3.zero)
        {
            Vector3 movementDir = transform.position - prevPosition;
            transform.rotation = Quaternion.LookRotation(movementDir, Vector3.Up);
        }
        prevPosition = transform.position;
    }
    

    我们所做的只是将上一帧的对象位置与这一帧的位置进行比较,减去这些位置以获得一个向量,然后沿着该向量旋转面对。

    在更新方法中,每帧都会调用它,如果你只有一个球,没问题,但如果你有数千个,你可能想进入一个只在碰撞后调用的方法。

    【讨论】:

      【解决方案3】:

      希望这个脚本能帮到你

      using System.Collections;
      using System.Collections.Generic;
      using UnityEngine;
      
      public class Reflect : MonoBehaviour
      {
      //3d Project
          public int reflections;
          public float maxLenght;
      
          private Ray ray;
          private RaycastHit hit;
          private Vector3 direction;
          Vector3 pos;
      
          private void Awake()
          {
      
              reflections = 5;
              maxLenght = 200;
              pos = gameObject.transform.position;
              GetNextPoint(1);
          }
      
          private void Update()
          {
              if (Vector3.Distance(gameObject.transform.position, pos) >0.7f)
              {
                  //move
                  transform.position += transform.forward/10;
              }
              else
              {
                  GetNextPoint(2);
              }
      
          }
      
          void GetNextPoint(int num)
          {
              ray = new Ray(transform.position, transform.forward);
              float remaningLength = maxLenght;
              int t = 0;
              for (int i = 0; i < reflections; i++)
              {
                  if (Physics.Raycast(ray.origin, ray.direction, out hit, remaningLength))
                  {
                      ray = new Ray(hit.point, Vector3.Reflect(ray.direction, hit.normal));
                      t++;
                      if (t == num)
                      {
                          gameObject.transform.LookAt(hit.point);
                          pos = hit.point;
                          break;
                      }
                  }
              }
          }
      }
      

      【讨论】:

        【解决方案4】:

        在物理处于活动状态时手动旋转可能会给你一些古怪的结果,但这里是

        public class FaceVelocity : MonoBehaviour
        {
            private Rigidbody rigidBody;
            void Awake()
            {
                rigidBody = getComponent<RigidBody2D>();
            }
            //Apply rotation in late update to make sure it's not undone by physics
            void LateUpdate()
            {
                transform.right = rigidBody.velocity.normalized
            }
        }
        

        如果您的对象在与某物(也就是最有可能发生的位置)接触时旋转,它可能会扰乱物理学。对物理使用父对象,对视觉使用子对象可能会更好。

        public class FaceVelocity : MonoBehaviour
        {
            private Rigidbody rigidBody;
            void Awake()
            {
                rigidBody = transform.parent.getComponent<RigidBody2D>();
            }
            //Apply rotation in late update to make sure it's not undone
            void LateUpdate()
            {
                transform.right = rigidBody.velocity.normalized
            }
        }
        

        虽然对我来说听起来你甚至不需要刚体,粒子物理学就足够了。如果不使用刚体,请自行计算速度方向:

        public class FaceVelocity : MonoBehaviour
            {
                private Vector3 prevPos;
                void Awake()
                {
                    prevPos = transform.position;
                }
                //Apply rotation in late update to make sure it's not undone 
                void LateUpdate()
                {
                    transform.right = (transform.position - prevpos).normalized
                }
            }
        

        【讨论】:

        • 这仅适用于应该指向行进方向的本地方向是本地右...
        猜你喜欢
        • 2017-01-11
        • 1970-01-01
        • 1970-01-01
        • 2013-01-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多