65.9K
CodeProject 正在变化。 阅读更多。
Home

VR 100 天挑战第 63 天:在 Unity 中旋转向量并朝玩家朝向移动

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2018 年 5 月 27 日

CPOL

4分钟阅读

viewsIcon

2070

如何在 Unity 中旋转向量并朝玩家朝向移动

引言

在之前的文章中,我们添加了一些简单的代码,允许我们的角色使用触摸板移动。很简单,没那么复杂。

现在,我们可能会发现一个问题,这取决于我们希望游戏中的移动如何工作。

我们可以很好地向前移动,但是当我们尝试在转身后移动我们的角色时会发生什么?

我们仍然会朝着相同的方向移动,无论我们从哪里开始!

对于玩家在我们的游戏中的玩法,有一些假设。玩家可以是

  • 坐着,这样我们总是面对相同的方向
  • 站着,这样他们可以在 360 度的角度转动,并且向前移动就是他们所看到的

我们的解决方案适用于第一种情况,但对于第二种情况,它不起作用。

在与这个问题斗争了很长时间后,我提出的解决方案是我们将不得不使用老式的数学和向量乘法!我们将学习如何旋转向量!

主要问题是,当我们更新我们的位置时,我们是根据持有摄像机的父游戏对象进行更新的,而不是根据我们所看的方向(主摄像机)。而且我们不能直接删除父容器,因为我们需要它来持有我们的摄像机。

我们必须做的是根据玩家所看的方向来旋转我们之前计算的向量。

添加基于玩家方向的移动

这花了很多时间来解决,但这是我们 TouchpadMovement 脚本的更新代码:

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

public class TouchpadMovement : MonoBehaviour
{
    private float _speedSlowDown;
    private Camera _mainCamera;

    void Start()
    {
        _speedSlowDown = 0.1f;
        _mainCamera = Camera.main;
    }

    void Update()
    {
        if (GvrControllerInput.IsTouching)
        {
            Vector2 touchPos = GvrControllerInput.TouchPos;
            Vector3 movementVector = new Vector3(touchPos.x - 0.5f, 0, 
                    touchPos.y - 0.5f);                 //adjust for center to be at 0.5, 0.5
            Vector3 rotatedVector = 
                       RotateVector(movementVector, _mainCamera.transform.eulerAngles.y);
            transform.Translate(rotatedVector.x * _speedSlowDown, 0, 
                    -rotatedVector.z * _speedSlowDown); // negative to adjust for the vector speed   
        }
    }

    // Given a direction and a degree, 
    // we'll rotate the direction vector by the given degree amount
    private Vector3 RotateVector(Vector3 direction, float degree)
    {
        float radian = Mathf.Deg2Rad * degree;          // convert our degree to be in radians

        // calculate our rotation vector using matrix multiplication
        // source: https://en.wikipedia.org/wiki/Rotation_matrix
        float cos = Mathf.Cos(radian);
        float sin = Mathf.Sin(radian);
        float newX = direction.x * cos - direction.z * sin;
        float newZ = direction.x * sin + direction.z * cos;
        return new Vector3(newX, 0, newZ);
    }
}

浏览代码

你不会相信我花了多少工夫才推导出这个公式!

尝试了很多次才弄对。我首先尝试使用 Quaternion.AngleAxis() 来计算旋转四元数以旋转我们的向量。但是,在玩了很长时间之后,结果并没有得到正确的值。

由于 Unity API 对我不起作用,我决定我别无选择,只能使用三角学来弄清楚我们如何旋转向量。结果在 RotateVector() 中。

理解 RotateVector()

我们试图解决的问题是,我们用来移动的向量是基于我们前进的方向,但是如果我们想朝着玩家所面对的方向移动,那么我们从触摸板创建的向量就不再正确了。

我们必须做的是旋转我们的向量,使“向前”成为我们主摄像机的前进方向。

我们目前拥有的信息是

  • 我们的主摄像机所面对的角度
  • 玩家输入移动向量

有了这些信息和我的高中毕业证书,我仍然不知道我应该怎么做!

我知道我必须对 Sin(X)Cos(X) 做些什么,这已经是我记忆能帮我的极限了!

幸运的是,我们有互联网!特别是 Youtube!这个关于 旋转向量 的视频,讨论了我们如何计算旋转向量的新 XY 值,内容非常丰富。

维基百科 也有一个关于旋转矩阵来旋转我们的向量的很好的页面。

但是,TLDR 是这样的

X’ = X * Cos(radian) – Y * Sin(radian)

Y’ = X * Sin(radian) – Y * Cos(radian)

需要注意的是,将我们的角度转换为弧度很重要,查看 Mathf.Cos()Mathf.Sin() 的文档

“返回角度 f(以弧度为单位)的余弦。”

我犯了一个错误,认为我们会传入角度,他们会给我们一个以弧度为单位的值……不……我犯了一个可怕的错误。这个函数的意思是给出一个转换为弧度形式的角度。

我如何确认这一点?谁还记得单位圆?

没错,我将这些值插入到 Unity 中,我发现我们必须将我们的度数转换为弧度。

回想起高中数学课,你的老师总是告诉你确保你处于度数模式。我让你失望了,老师!

总之。请随意尝试在 Unity 模拟器上使用该脚本。环顾四周,尝试通过按以下方式滑动您的触摸板:Shift + Ctrl + 鼠标移动。无论你面对哪个方向,我们现在都能够移动到正确的位置。

有了这个成就,我们就可以继续研究其他与游戏控制器交互的方式了!

结论

呼,这比我最初认为的移动所需的数学知识要多!

如果你曾经想过你是否需要编程的数学知识,这是一个例子(提示:不经常)。

现在,我们可以使用触摸板来移动我们的角色,但不仅如此,如果我们要在游戏中转过身来并移动,我们将朝着我们所看的方向移动。

完成此操作后,我们正式完成了移动。接下来,我们将研究如何使用我们的控制器拾取和投掷物体,以及如何使用我们的运动来投掷它!在下一篇文章中再见!

© . All rights reserved.