首页 理论教育实践结果:虚拟现实理论基础与应用开发

实践结果:虚拟现实理论基础与应用开发

【摘要】:图8-32Ball脚本创建1)概要前面创建了一个游戏项目,并且创建了玩家角色和小球这些游戏对象,还通过添加游戏脚本实现了小方块的弹跳。图8-33游戏开始状态图8-34Ball项文本变为蓝色图8-35多出一个小球对象将Player和Floor游戏对象也做成预设。图8-37创建文件夹并修改其名称图8-38移动Player预设和Floor预设至Prefabs文件夹将预设Ball Prefab拖拽到Prefabs文件夹下。图8-39保存文件夹回到Assets图8-40游戏对象命名5)发射小球在窗口顶部菜单中依次单击GameObject→Create Empty。

图8-32 Ball脚本创建

1)概要

前面创建了一个游戏项目,并且创建了玩家角色和小球这些游戏对象,还通过添加游戏脚本实现了小方块的弹跳。虽然功能比较简单,但是完整地表现了使用Unity开发游戏的大体流程。

为了让这个游戏变得更加有趣,下面要进一步完善玩家角色和小球的动作。

2)让小球飞起来(物理运动和速度)

目前小球是静止在空中的,下面来尝试让它朝玩家角色飞去。为了令小球能够模拟物理运动,需要添加Rigidbody组件。同时还需要创建一个Ball的脚本(见图8-32)。此操作见8.2小节中的步骤10)和步骤11)。

添加了Ball脚本以后,我们要对Start方法做如下修改:

游戏开始后,小球将向画面左侧飞去(见图8-33)。

3)创建大量小球(预设游戏对象)

为了能够随时创建出小球对象,首先需要对小球对象进行预设。

(1)请将层级视图中的Ball项文本拖拽到项目视图中。项目视图中将出现Ball项。同时,层级视图中的Ball项文本将会变为蓝色(见图8-34)。

(2)将项目视图中的Ball预设拖拽到场景视图中,可以看到场景中会多出一个小球对象(见图8-35)。预设了游戏对象后,就能够非常容易地创建出多个同样的物体。

图8-33 游戏开始状态

图8-34 Ball项文本变为蓝色

图8-35 多出一个小球对象

(3)将Player和Floor游戏对象也做成预设(见图8-36)。

图8-36 将Player和Floor游戏对象做成预设

4)整理项目视图

(1)用文件夹将这些项目归类整理。在项目视图左上角的菜单中单击Create→Folder按钮后,项目视图中将生成一个文件夹,将名字改为Prefabs(见图8-37)。

图8-37 创建文件夹并修改其名称

图8-38 移动Player预设和Floor预设至Prefabs文件夹

(2)将预设Ball Prefab拖拽到Prefabs文件夹下。单击Prefabs文件夹,可以看到刚才移动的Ball预设。接着把Player预设和Floor预设也移动到Prefabs文件夹下(见图8-38)。

(3)采用同样的方式创建Scenes、Scripts、Materials文件夹,并把各项目放到相应的文件夹下。注意在创建前务必先单击项目视图左侧的Assets图标以确保当前文件夹回到Assets(见图8-39)。

图8-39 保存文件夹回到Assets

图8-40 游戏对象命名

5)发射小球(通过脚本创建游戏对象)

(1)在窗口顶部菜单中依次单击GameObject→Create Empty。由于该游戏对象被用作发射台,因此命名为Launcher(见图8-40)。

(2)对游戏对象Launcher进行预设(见图8-41)。

(3)创建Launcher脚本(见图8-42)。

(4)将Launcher脚本添加到Launcher预设中去(另外一种方法)。

图8-41 对Launcher进行预设

图8-42 创建Launcher脚本

①在项目视图中切换到Prefabs文件夹,单击选中Launcher预设。此时检视面板上将显示Launcher的相关信息,然后单击最下方的Add Component按钮(见图8-43)。

图8-43 添加组件

②在标题为Component的下拉菜单中单击最下方的Script项。单击后菜单将向左移动,显示出所有创建好的脚本。找到Launcher脚本并单击(见图8-44)。

小结:现在已经知道在检视面板中也可以添加组件,除此之外,还可以使用窗口顶部菜单或者直接拖拽。

(5)编辑Launcher脚本。除了Update方法有变动之外,还增加了ballPrefab变量。Instantiate是通过预设生成游戏对象实例的方法。不过脚本中并没有对ballPrefab变量进行初始化的代码,所以在游戏运行前必须先在检视面板中对ballPrefab变量赋予预设对象值。

图8-44 找到Launcher脚本

图8-45 public成员变量

从项目视图中选择Launcher预设。可以看到在检视面板中的Launcher(Script)标签下显示有Ball Prefab项。脚本代码中声明的所有public成员变量都将在这里列出(见图8-45)。

往类中新添加的变量默认表示为None(GameObject),意味着该变量还未被赋值。请将项目视图中的Ball预设拖拽到这里(鼠标左键按着不要松手),如图8-46和图8-47所示。

(6)运行游戏。每次单击鼠标右键时,都会射出一个小球(见图8-48)。这里,为了和预设对象分开,我们把脚本中通过Instantiate方法生成的游戏对象称为实例,把产生实例的过程称为实例化。

图8-46 Ball预设拖拽(1)

6)删除画面外的小球(通过脚本删除游戏对象)

游戏现在出现了一个Bug:发射出去的小球永远不会消失(见图8-49)。游戏运行时由脚本动态生成的游戏对象也会显示在层级地图中。每单击一次鼠标,层级视图中都会增加一个Ball(Clone)游戏对象。因此即使小球已经跑出游戏画面之外,这些游戏对象也并未消失。

跑出画面之外的小球不会再回到画面中,所以完全可以删除。在脚本Ball.cs中添加OnBecameInvisible方法,该方法可以被添加到Ball类定义范围内的任意位置。OnBecameInvisible方法是在游戏对象移动到画面之外不再被绘制时被调用的方法。Destroy(this.gameObject)则是删除游戏对象的方法。

图8-47 Ball预设拖拽(2)

图8-48 运行游戏

图8-49 小球不会消失

注意:如果把参数设置成this的话,删除的就不是游戏对象,而是Ball脚本组件。

7)防止玩家角色在空中起跳(发生碰撞时的处理)

为了防止玩家角色在空中再次起跳,我们来添加下列处理:①添加着陆标记;②着陆标记值为false时不允许起跳;③将起跳瞬间的着陆标记设为false;④将着陆瞬间的着陆标记设为true;⑤修改Player脚本,代码如下。

当一个游戏对象同其他对象发生碰撞时,OnCollisionEnter方法将被调用。这是为了检查玩家角色是否着陆而添加的。在该方法中把着陆标记的值设为true。这样玩家角色就不能在空中再次起跳了。

8)禁止玩家角色旋转(抑制旋转)

在某种程度上完成了玩家角色和小球的脚本编程后,让我们来调整各相关参数,以使角色在起跳后能和小球发生碰撞。这里我们采用下列值:玩家角色的位置:(-2.0,1.0,0.0);玩家角色的起跳速度(Player.cs脚本中jump_speed的值):8.0;小球的位置:(5.0,2.0,0.0);小球的初始速度(Ball.cs脚本中使用Start方法设定的值):(-7.0,6.0,0.0)。

(1)选择项目视图中的Player并打开检视面板中的Rigidbody标签下的Constraints项。(www.chuimin.cn)

(2)单击左边的三角形图标,下面会进一步显示Freeze Position和Freeze Rotation。其中Freeze Position对于将游戏对象的位置坐标固定在某些方向上,Freeze Rotation则用于固定其角度(见图8-50)。由于我们希望玩家角色只上下跳跃而不做左右和前后的移动,因此:

(3)把Freeze Position的“X”“Z”前面的复选框选中。Freeze Rotation方面则把“X”“Y”“Z”全部选中(见图8-51)。

图8-50 Freeze Position和Freeze Rotation(1)

图8-51 Freeze Position和Freeze Rotation(2)

9)让玩家角色不被弹开(设置重量)

选择项目视图中的Ball预设,打开Rigidbody标签,将Mass项的值由1改为0.01(见图8-52)。Mass项用于设定游戏对象的重量。两个游戏对象发生碰撞时,Mass值较大的物体将保持原速度继续运动,相反Mass值较小的物体则容易因受到冲击而改变移动的方向。

图8-52 Mass项设置

10)让小球强烈反弹(设置物理材质)

(1)创建物理材质。从项目视图的Create菜单中选择Physic Material,创建一个新材质并将其名称改为Ball Physic Material(见图8-53)。相对于用来指定颜色等可以看见的属性材质,物理材质则是用于设定弹性系数和摩擦系数等与物理运动相关的属性。

图8-53 创建新材质并设置名称

(2)修改属性值。在项目视图中选择Ball Physic Material后,在检视面板中选择Bounciness,将其值由0改为1。这个值越大,游戏对象越容易被“弹开”(见图8-54)。

图8-54 修改属性值

(3)将新创建的材质拖拽到Ball预设下的Material。从项目视图中选择Ball预设,接着把Ball Physic Material拖拽到检视面板中Sphere Collider标签下的Material(见图8-55),或者可以单击Ball Physic Material右侧的圆形图标。这时Select Physic Material窗口将被打开,在这个“物理材质选择窗口”中也可以进行选择设定(见图8-56)。

图8-55 将新创建的材质拖拽到Ball预设下的Material

图8-56 物理材质选择窗口

11)消除“漂浮感”(调整重力大小)

(1)在窗口顶部菜单中依次单击Edit→Project Settings→Physics按钮(见图8-57),检视面板中将切换显示PhysicsMana(见图8-58)。

图8-57 窗口顶部菜单

图8-58 窗口菜单

(2)将Gravity项的“Y”值稍微提高一些,在此设为-20(见图8-59)。

(3)调整参数。通过增强重力可以减弱物体在运动时的“漂浮感”,不过跳跃的高度和小球的轨道也显得比原来低了。这种情况下,我们可以考虑调整为下列数值:玩家角色的起跳速度(Player.cs脚本中的jump_speed的值):12.0;小球的初始速度(Ball.cs脚本中使用Start方法设定的值):(-10.0,9.0,0.0)。

图8-59 Gravity项Y值设置

12)调整摄像机的位置

(1)选择摄像机后,场景视图右下角将出现一个小窗口。这是从摄像机看到的画面。如果无法看到这个窗口,请在检视面板中展开Camera标签(见图8-60)。

图8-60 场景视图

(2)为了能够俯视地面,需要使摄像机在往上偏移的同时绕X轴旋转,调整角度时需把移动工具切换为旋转工具(见图8-61)。用移动工具调整摄像机的位置,用旋转工具调整摄像机的角度(见图8-62)。

(3)在检视面板中输入数值(可根据自己喜好进行设置)(见图8-63)。

(4)对比效果。调整摄像机前如图8-64所示,调整摄像机后如图8-65所示。

图8-61 工具切换栏(1)

图8-62 工具切换栏(2)

图8-63 数值输入

图8-64

图8-65

13)修复空中起跳的bug(区分碰撞对象)

(1)bug的发现。试玩游戏后,我们注意到玩家角色和小球碰撞后还可以再次起跳。这可能是因为防止空中跳跃的代码存在bug。

(2)bug的证明。

①游戏启动后,在层级视图中选择Player。可以在检视面板中的Player(Script)标签下看到Is_landing项。这就是在Player脚本中定义过的is_landing变量(见图8-66)。

图8-66 游戏启动、看到Is_landing

②游戏刚开始时画面上还没有小球。随着玩家角色起跳,可以看到Is_landing复选框由取消变为了选中状态,跳跃过程中Is_landing为取消状态(值为false),如图8-67所示。着陆后Is_landing为选中状态(值为true),如图8-68所示。

图8-67 Is_landing变为取消

图8-68 Is_landing变为选中

③修改Player.Update方法如下:

修改后仅添加了Debug.Break方法的调用。在玩家角色起跳时的瞬间暂停游戏的运行。按下播放控制工具条最右边的按钮,在逐帧模式下可以看到玩家角色在一直上升。在玩家角色和小球碰撞的瞬间,Is_landing的值变成了true(此处无法截图,见谅)。搞清楚了bug的原因,接下来就考虑解决bug的对策。

(3)bug的解决如下:

①首先需要区分开碰撞对象是地面还是小球,此处我们可以利用标签。需要对游戏对象的种类进行大致区分时,可以使用标签来分组。添加标签到项目中,在项目视图中选择Floor预设→单击Untagged→单击Add Tag→单击Tags左侧的三角形→单击“+”→输入Floor→再次在项目视图中选择Floor预设→单击Untagged→单击Floor(见图8-69—图8-73)。

图8-69 选择Floor预设

图8-70 选择“+”

图8-71 输入Floor

图8-72 选择Floor

图8-73 单击Floor

②修改脚本。修改Player.OnCollisionEnter方法。在这里提醒下:记得删除了之前在Player.Update方法中添加的Debug.Break()。

使用了标签后就可以区分碰撞对象了。这样一来就只有在和地面碰撞时,也就是着陆时Is_landing的值才会变为true。