Unity 3D脚本编程与游戏开发(2.6)

这篇具有很好参考价值的文章主要介绍了Unity 3D脚本编程与游戏开发(2.6)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

4.5.2 四元数的概念

        四元数包含⼀个标量分量和⼀个三维向量分量,四元数Q可以记作Q=[w,(x,y,z)]
        在3D数学中使⽤单位四元数表⽰旋转,下⾯给出四元数的公式定义。对于三维空间中旋转轴为n,旋转⾓度为a的旋转,如果⽤四元数表⽰,则4个分量分别为
w=cos(α/2)
x=sin(α/2 )cos (βx)
y=sin(α/2 )cos (βy)
z=sin( α/2 )cos (βz)
        ⽤四元数表⽰旋转⼀点也不直观,4个分量w、x、y和z与绕各轴的旋转⾓度并没有直接的对应关系。在实际游戏开发中不要试图获取和修改某⼀个分量,应当只做整体处理。
        前⾯提到,矩阵也可以表⽰旋转,⽽且矩阵也不存在万向节锁定问题。其实,旋转还可以⽤欧拉⾓和四元数表⽰,但是每⼀种表⽰⽅法都有其各⾃的优缺点,表4-5对这3种⽅式进⾏了对⽐。
表4-5 3种表⽰旋转的⽅法对⽐。

Unity 3D脚本编程与游戏开发(2.6),Unity实战开发指南,unity,3d,游戏引擎,3D游戏开发,Unity四元数的概念,Quaternion结构体,Unity四元数的插值

        ⼀⽅⾯,由于3种表⽰旋转的⽅法都有各⾃的优势和缺点,因此在实际中会根据具体需求进⾏考虑。另⼀⽅⾯,由于旋转的表⽰⽅法⾮常重要,因此应当尽可能在引擎层⾯进⾏统⼀,这样才能尽可能减少开发游戏时的问题。
⼩提⽰
        编辑器⾥显⽰欧拉⾓是为了使⽤⽅便Unity内部旋转是⽤四元数,即结构体Quaternion表⽰的,但是在界⾯上很多地⽅会转为更直观的欧拉⾓,以便设计师直接指定旋转的⾓度。这种⽅式兼顾了准确性和便利性。

4.5.3 Quaternion结构体

        下表详细介绍了Quaternion(四元数)结构体的属性(表4-6)和⽅法(表4-7)。

Unity 3D脚本编程与游戏开发(2.6),Unity实战开发指南,unity,3d,游戏引擎,3D游戏开发,Unity四元数的概念,Quaternion结构体,Unity四元数的插值

Unity 3D脚本编程与游戏开发(2.6),Unity实战开发指南,unity,3d,游戏引擎,3D游戏开发,Unity四元数的概念,Quaternion结构体,Unity四元数的插值

4.5.4 理解和运⽤四元数

        在“位置与向量的关联”⼩节中,详细讲解了“位置”与“向量”的区别。接下来引出与之对应的另⼀对概念——“朝向”与“旋转”。就好⽐“位置”是⼀个具体的坐标,“朝向”也是具体的状态,如朝南、朝北、朝欧拉⾓(30, 30, 0),都是表达物体的⼀个固定⽅向。只要A物体朝向世界坐标系的后⽅,就可以确定它的欧拉⾓为(0, 180, 0)。
        由于欧拉⾓允许超过360°或者是负⾓度,因此严谨地说欧拉⾓应当是(360×n, 180+360×n, 360×n),其中n为整数。“旋转”有点像前⽂提到的“向量”,指的是⼀个旋转的变化量。例如“右转90°”就是⼀个旋转,如果⾯朝南,右转90°就是朝⻄;如果⾯朝东,右转90°就是朝南。将位置、向量与朝向、旋转类⽐,可以形成清晰的概念。
        前⽂提到,位置和向量都是⽤Vector3表⽰。不出意料,朝向和旋转都是⽤四元数(Quaternion)表⽰。理解了Vector3加法的意义,就可以类⽐出四元数的旋转操作,只是加法变成了乘法。表4-8说明了四元数乘法的含义。

Unity 3D脚本编程与游戏开发(2.6),Unity实战开发指南,unity,3d,游戏引擎,3D游戏开发,Unity四元数的概念,Quaternion结构体,Unity四元数的插值

        向量加法中,向量a+b和向量b+a没有什么不同,但在旋转问题中,q1×q2与q2×q1的结果⼀般不相等。也就是说,四元数相乘不满⾜交换律,这也印证了三维空间中物体的旋转不是⼀个简单的问题。更有意思的是,四元数乘法可以直接作⽤于向量,这样就可以⽅便地直接旋转向量了,如表4-9所⽰。

Unity 3D脚本编程与游戏开发(2.6),Unity实战开发指南,unity,3d,游戏引擎,3D游戏开发,Unity四元数的概念,Quaternion结构体,Unity四元数的插值

        注意四元数乘以向量时,必须四元数在前,向量在后。不存在“向量*四元数”的操作,代码中写“向量*四元数”会报错。下⾯补充⼀个演⽰程序,实际演⽰⼀下四元数旋转。
01 新建⼀个场景,然后在场景中新建⼀个㬵囊体,位置归0。
02 给㬵囊体新建⼀个⽴⽅体作为⼦物体,可以给⼦物体赋予有颜⾊的材质。
03 将⽴⽅体移动到㬵囊体前⽅,这是为了⽅便区分㬵囊体的⽅向,模拟⼈形⾓⾊,如图4-17所⽰。
04 新建脚本QuatTest,其内容如下。

Unity 3D脚本编程与游戏开发(2.6),Unity实战开发指南,unity,3d,游戏引擎,3D游戏开发,Unity四元数的概念,Quaternion结构体,Unity四元数的插值

using UnityEngine;
public class QuatTest : MonoBehaviour
{
void Update()
{
float v = Input.GetAxis("Vertical");
float h = Input.GetAxis("Horizontal");
// 将横向输⼊转化为左右旋转,将纵向输⼊转化为俯仰旋转,得到⼀个
很⼩的旋转四元数
Quaternion smallRotate = Quaternion.Euler(v, h, 0);
// 将这个⼩的旋转叠加到当前旋转位置上
if (Input.GetButton("Fire1"))
{
// 按住⿏标左键或Ctrl键时,沿世界坐标轴旋转
transform.rotation = smallRotate *
transform.rotation;
}
else
{// 不按⿏标左键和Ctrl键时,沿局部坐标轴旋转
transform.rotation = transform.rotation *
smallRotate;
}
}
}

        05 将脚本挂载到㬵囊体上,进⾏测试。
        运⾏游戏,按W、A、S、D键或⽅向键可以看到㬵囊体沿⾃⾝的坐标轴转动;如果按住攻击键(默认为⿏标左键或Ctrl键)再旋转,则会发现㬵囊体沿世界坐标轴转动。
        仔细观察代码,会发现⽤四元数表⽰旋转很⽅便。通过transform.rotation可以获取物体当前的朝向,通过Quaternion.Euler()⽅法可以借⽤⾓度创建出任意的旋转量。未来与旋转有关的操作都可以套⽤这两种基本⽅法。
        但是细⼼的读者可能会发现⼀个问题:沿世界坐标轴旋转时,⽤的是“朝向=旋转*朝向”的操作,这⼀操作不符合前⽂所说的“朝向*旋转=新的旋转”的解释。
        这⾥⼜再次体现出了三维空间中旋转的复杂性:⾸先,四元数相乘不符合交换律,相乘顺序不同会影响结果;其次,也可以认为相乘顺序的不同导致“旋转轴”不同。这样⼜了解到⼀个技巧:通过交换四元数相乘的顺序,可以让物体沿不同坐标系的坐标轴进⾏旋转。

⼩提⽰
回忆⼀下前⽂⽤到的向量插值之前⽤过的Vector3.Lerp⽅法是取两个位置坐标(或者向量)之间的某个值。四元数的插值与之类似,就是在两个朝向(或者旋转)之间取⼀个值。

4.5.5 四元数的插值

        前⽂通过介绍“万向节锁定”,解释了使⽤四元数的必要性。其实四元数还有⼀个“绝活”,那就是做动画与插值。物体的转向动画应该是直接的、均匀的,不能给⼈“绕远”的感觉。⼏何上,在球⾯上的两点之间移动,沿“⼤圆”的路径是最短的。⼤圆的定义是“过球⼼的平⾯与球⾯相交形成的圆”,换句话说就是能在球⾯上画出的最⼤的那⼀类圆。
        以地球的经纬线为例,所有纬线中只有⾚道是⼤圆,其他纬线都不是⼤圆,⽽所有的经线都是⼤圆,如图4-18所⽰。两个朝向之间的旋转动画,当旋转的路径符合⼤圆时,旋转路径就是最短的,看起来也最舒服。

Unity 3D脚本编程与游戏开发(2.6),Unity实战开发指南,unity,3d,游戏引擎,3D游戏开发,Unity四元数的概念,Quaternion结构体,Unity四元数的插值

        欧拉⾓在制作旋转动画时具有很⼤缺陷。如果仅沿⼀个轴旋转,例如从朝南转向朝东,则⽤欧拉⾓的⾓度的线性变化也能做出正确的动画,⽽当旋转较为复杂,x轴、y轴和z轴都有旋转时,物体则不会按照“⼤圆”的路径运动,得到的效果会很奇怪。矩阵在表现旋转动画时,也很难计算正确的插值点。⽽四元数就很擅⻓插值运算,在实际游戏开发中Unity提供了Quaternion.Slerp()⽅法,⽤于旋转的插值。它的函数定义如下。

⼩提⽰
四元数有两种插值函数
四元数除了有Slerp⽅法,也有Lerp⽅法。
由于Lerp⽅法不是严格的球⾯插值,因此⼀般情况下使⽤Slerp
⽅法。
static Quaternion Slerp(Quaternion a, Quaternion b, float t);

        Quaternion的第1个参数是第1个朝向(或旋转),第2个参数是第2个朝向(或旋转),t取0到1之间的值。调⽤Quaternion.Slerp⽅法后就可以获得前⾯两者之间的⼀个四元数。
代码举例如下。

// 前⽅
Quaternion q = Quaternion.identity; // identity相当于Eular(0,
0, 0),不旋转
// 改变物体的朝向,取当前朝向与正前⽅之间10%的位置transform.rotation = Quaternion.Slerp(transform.rotation, q,
0.1f);

4.5.6 朝向与向量

        朝向代表着空间中的⼀个⽅向,⽽向量也可以表⽰⼀个⽅向,因此有时也可⽤向量直接表⽰物体的朝向。例如,最常⽤的transform.forward表⽰指向物体前⽅(世界坐标系)。
        不仅可以通过transform.forward属性获得指向物体前⽅的向量(已标准化,⻓度为1⽶),⽽且可以直接设置它以改变物体的朝向。例如在第2.6节的实例中,物体的转向是通过键盘控制的,这⾥可以很容易地改为⿏标控制。其步骤简单介绍如下。
        01 搭建⼀个类似第2.6节的简单场景和⾓⾊。
        02 为⾓⾊添加⿏标控制旋转的脚本MouseRotation。

using UnityEngine;
public class MouseRotation : MonoBehaviour
{
void Update()
{
Ray ray =
Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
transform.forward = hit.point -
transform.position;
}
}
}

        这个脚本删除了所有不必要的代码,⽤最简单的⽅式实现了射线检测与专项,读者可以逐句分析。其中射线的原理可参考第3章物理系统的相关内容。
03 将脚本挂载到⾓⾊上,运⾏游戏,移动⿏标指针指向地⾯的不同位置,⾓⾊就会转向⿏标指针指向的位置,如图4-19所⽰。

Unity 3D脚本编程与游戏开发(2.6),Unity实战开发指南,unity,3d,游戏引擎,3D游戏开发,Unity四元数的概念,Quaternion结构体,Unity四元数的插值

        这⾥想说明的是,只要获取了前⽅向量,并将transform.forward赋值,就可以实现直接转向。向量没有标准化也没关系,赋值时会⾃动将它标准化。
        这段代码有⼀个⼩问题,主⾓在旋转时会低头。这是因为⾓⾊有⼀定⾼度,地⾯上的点低于⾓⾊,因此⾓⾊会向下看。解决⽅案是将结果向量的y轴设置为与⾓⾊⾼度⼀致,其代码修改如下。

if (Physics.Raycast(ray, out hit))
{
// 防⽌⾓⾊低头的代码
Vector3 v = hit.point - transform.position;
v.y = transform.y;
transform.forward = v;
}

        向量可以代表朝向,四元数也可以代表朝向,那么向量也就可以转化为四元数。向量转化为四元数(朝向)的⽅法定义如下。

Quaternion Quaternion.LookRotation(Vector3 forward);
Quaternion Quaternion.LookRotation(Vector3 forward, Vector3
up);

        在之前介绍的四元数使⽤⽅法中,都是借⽤物体的transform.rotation获取⼀个朝向,然后以它为基准继续旋转。Quaternion.LookRotation()则提供了直接获得朝向的⼀种⽅法。
        仔细思考会发现问题——难道四元数可以⽤向量代替吗?应该不可以,如果能代替就不需要发明四元数这种复杂的表⽰⽅法了。其实向量代表朝向有很⼤的局限性,例如,⼀个⼈躺在床上,⾯朝上,他的前⽅是世界坐标系的上⽅。这时候,他可以在保持⾯朝上的情况下在床上⽔平旋转,让头部朝东或朝⻄。⽽⽆论他的头部朝向哪⾥,他的前⽅都可以保持向上。
        这说明,代表某个向量⽅向的四元数不是唯⼀的。如果只⽤⼀个向量代表前⽅,理论上有⽆数种四元数都指向该⽅向,但它们的“上⽅”不同。如果仅指定前⽅,即使使⽤LookRotation()⽅法只有⼀个参数的形式,Unity也会⽤某种规则假定⼀个合适的“上⽅”;⽽如果要精确地控制,则需要⽤Quaternion的另⼀种形式,⽤两个参数分别指定前⽅向量和上⽅向量,这样就可以得到更符合要求的结果。

4.6 实例:第⼀⼈称视⾓的⾓⾊控制器

        为了对前⾯所讲解的数学知识进⾏实践,本节做⼀个完整的FPS(第⼀⼈称射击)游戏⾓⾊控制器。整个过程尽可能⽤简单的脚本代码实现,避免使⽤插件,从⽽充分体现出向量、四元数等知识在实践中的运⽤⽅法。

4.6.1 搭建简单场景

01 新建⼀个场景,放置⼀个平⾯作为地板,将地板放⼤5倍。
02 创建⼀个新的材质挂载在地板上,给地板⼀个较深的颜⾊。
03 在地板上放置⼀些⽴⽅体,主要是为了在测试时作为参照物使⽤,如图4-20所⽰。

Unity 3D脚本编程与游戏开发(2.6),Unity实战开发指南,unity,3d,游戏引擎,3D游戏开发,Unity四元数的概念,Quaternion结构体,Unity四元数的插值

4.6.2 创建主⾓物体

        这⾥依然⽤⼀个简单模型作为主⾓,能⽅便查看⽅向即可。
        01 创建⼀个㬵囊体,㬵囊体默认⾼度为2,代表⼀个⾓⾊。
        02 创建⼀个⽴⽅体作为㬵囊体的⼦物体,将⽴⽅体放在㬵囊体的“脸”部。给⽴⽅体挂上材质,材质要设为显眼的颜⾊。
        03 将㬵囊体命名为Player。
        04 重点:拖曳场景列表中的主摄像机,让主摄像机变成㬵囊体的⼦物体。
        05 将主摄像机的位置归0,也就是主摄像机与主⾓重合。然后微调主摄像机的位置到⾓⾊的脸部。
        这样主⾓和场景就准备完成了。第⼀⼈称射击游戏的摄像机会完全跟随主⾓移动和转动,因此设置为⼦物体是⼀种⽐较简单的做法。

4.6.3 编写控制脚本——移动部分

        (1)创建脚本FPSCharacter,将其挂载于㬵囊体Player上。
        (2)编写脚本内容。脚本内容是重点,下⾯分步介绍。
        ⾓⾊的控制分为两⼤块:⾓⾊移动和摄像机旋转。
        ⾓⾊移动⽅⾯,玩家可以按⽅向键进⾏前后左右平移。问题是:玩家按上⽅向键时,对应哪个⽅向;玩家按右⽅向键时,⼜对应哪个⽅向。
        图4-21所⽰的⾓⾊本⾝具有前⽅向量transform.forward和右⽅向量transform.right。右⽅向量与右⽅向的移动直接对应;前⽅向量⽐较⿇烦,因为存在抬头、低头的情况。如果玩家在抬头看天时直接向前⽅⾛,就会得到向天上⻜的结果。

Unity 3D脚本编程与游戏开发(2.6),Unity实战开发指南,unity,3d,游戏引擎,3D游戏开发,Unity四元数的概念,Quaternion结构体,Unity四元数的插值

        解决⽅案是得到前⽅向量后,略加修改,去除前⽅向量的y轴分量,这样就让前⽅向量保持⽔平了。完整代码在本章末尾,计算移动的部分代码如下。

void Move()
{
float x = Input.GetAxis("Horizontal"); // 输⼊左右
float z = Input.GetAxis("Vertical"); // 输⼊前后
// ⽅向永远平⾏地⾯,⾓⾊不能⾛到天上去
// 获得⾓⾊前⽅向量,将y轴分量设为0
Vector3 fwd = transform.forward;
Vector3 f = new Vector3(fwd.x, 0, fwd.z).normalized;// ⾓⾊的右⽅向量与右⽅向的移动直接对应,与抬头⽆关,可以直接⽤
Vector3 r = transform.right;
// ⽤f和r作向量的基,组合成移动向量
Vector3 move = f * z + r * x;
// 直接改变玩家位置
transform.position += move * speed * Time.deltaTime;
}

        这段代码中的“move=f*z+r*x”是⼀个很有⽤的技巧,f和r都是⻓度为1的⽅向向量。x是左右⽅向向量的⻓度,范围为-1~1;z是前后⽅向向量的⻓度,范围为-1~1。x控制着f的⻓度,z控制着r的⻓度。这样将前后与左右⽅向相加,就得到了移动向量。
 文章来源地址https://www.toymoban.com/news/detail-774925.html

到了这里,关于Unity 3D脚本编程与游戏开发(2.6)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Unity 3D脚本编程与游戏开发【4.2】

    8.2.3 ⾳频管理器         在实际游戏开发中,⾳效既是⼀个相对独⽴的部分,⼜与其他游戏逻辑密切关联。也就是说,与⾳效相关的代码会插⼊很多细节代码中。         ⽽且在⾳效⾮常丰富的情况下,如果每⼀个游戏模块都单独播放⾳效,那么可能会带来⼀些问题。

    2024年04月24日
    浏览(43)
  • Unity 3D脚本编程与游戏开发【3.8】

    6.4.5 动画层         图6-42显⽰了动画层设置窗⼝。在动画状态机⾥可以添加很多层,层之间可以是覆盖关系也可以是叠加关系,当然也可以随时屏蔽⼀些层、启⽤另⼀些层。 每⼀个动画层可以有单独的设置,其选项解释如下。 ①Weight(权重),本层对总体动画效果的影

    2024年04月16日
    浏览(47)
  • Unity 3D脚本编程与游戏开发(2.8)

    5.1.2 矩形变换(Rect Transform)组件         如果选中界⾯上的控件,读者会发现每个物体并不带有基本的Transform组件,取⽽代之的是Rect Transform(矩形变换)组件。其实Rect Transform组件是Transform组件的⼦类,因此并不违反“每个物体必须有且只有⼀个Transform组件”的规定。

    2024年02月03日
    浏览(36)
  • Unity 3D脚本编程与游戏开发(3.2)

    5.3.4 制作背包界⾯         背包界⾯是此实例中的重点,因为它的屏幕适配⽐较有代表性。当屏幕⽐较“瘦⾼”时,道具列表中能显⽰更多道具项,⽽屏幕⽐较“矮胖”时,显⽰的道具项会变少。但这些都不影响玩家通过下拉滑动查看所有道具,如图5-37所⽰。       

    2024年04月12日
    浏览(57)
  • Unity 3D脚本编程与游戏开发【4.1】

    7.2.5 后期处理举例 Post Processing(后期处理)并不属于特效,但现代的特效表现离不开后期处理的⽀持。本⼩节以眩光(Bloom)为例,展⽰⼀种明亮的激光的制作⽅法,其效果如图7-13所⽰。 1. 安装后期处理扩展包         较新的Unity版本(如2018.4版本)已经内置了新版的后

    2024年04月26日
    浏览(40)
  • Unity 3D脚本编程与游戏开发(3.5)

    6.2.8 总结和拓展         本节利⽤Unity官⽅素材,以有限的篇幅解释了动画状态机的原理,以及动画制作中最基本但最重要的步骤。总的来看,⽬前的动画只做了4种状态——站⽴、⾛、跑和跳跃,还缺少下蹲、下蹲移动和落地缓冲等动作。好在这些动作只是对现有动作的

    2024年04月10日
    浏览(50)
  • Unity 3D脚本编程与游戏开发【3.7】

            在这个⾓⾊控制脚本中,可以看到很多新奇的写法。关键是,为什么要把移动量转化为转⾝量和前进量呢?要理解这个问题,⼀定要多进⾏游戏测试,体会转⾝与输⼊的关系。         当⾓⾊⾯朝前,输⼊朝后时,⾓⾊的前进量为0,转⾝量达到最⼤;⽽当⾓⾊

    2024年04月15日
    浏览(39)
  • Unity 3D游戏开发+脚本编程完整指南:Unity脚本概览-控制物体的运动

    教程相关资源 Unity 3D游戏开发+脚本编程完整指南(工程文件+PPT).zip Unity 脚本概览 脚本编写并不困难,但是如果直接从细节开始讲起,会让 读者难以看到脚本编程的全貌。因此本章不急于阐述脚本编写 的细节,只介绍简单的修改物体位置、处理用户输入和检测碰 撞的方法

    2024年02月21日
    浏览(71)
  • Unity 3D游戏开发+脚本编程完整指南:制作第一个游戏:3D滚球跑酷

    教程相关资源 Unity 3D游戏开发+脚本编程完整指南(工程文件+PPT).zip 本节利用前面的知识来实现第一个较为完整的小游戏,如 图 1-21 所示。 图1-21 3D滚球跑酷游戏完成效果 1. 功能点分析 游戏中的小球会以恒定速度向前移动,而玩家控制着小球 左右移动来躲避跑道中的黄色障

    2024年02月21日
    浏览(49)
  • 游戏引擎支持脚本编程有啥好处

    很多游戏引擎都支持脚本编程。Unity、Unreal Engine、CryEngine等大型游戏引擎都支持使用脚本编写游戏逻辑和功能。脚本编程通常使用C#、Lua或Python等编程语言,并且可以与游戏引擎的API进行交互来控制游戏对象、设置变量、执行行为等。使用脚本编程,游戏开发者可以更加灵活

    2024年02月03日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包