在 Unity 中沿其移动方向旋转对象

Posted

技术标签:

【中文标题】在 Unity 中沿其移动方向旋转对象【英文标题】:Rotate object in the direction it's moving in Unity 【发布时间】:2020-05-04 22:47:30 【问题描述】:

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

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

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

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

【问题讨论】:

他在问题标题中说Unity。 Unity 在 C# 中 @jwdonahue 对不起,我现在修好了。 【参考方案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
        
    

【讨论】:

这仅适用于应该指向行进方向的本地方向是本地右...

以上是关于在 Unity 中沿其移动方向旋转对象的主要内容,如果未能解决你的问题,请参考以下文章

在 3d 中沿贝塞尔路径移动对象:旋转问题

在 Unity 中沿光线投射实例化预定义数量的对象

根据相机方向移动

当对象经过特定旋转时播放声音

如何旋转对象沿着矢量Unity3D指向

使用四元数的Unity3D相对偏移对象旋转