查看原文
其他

VR丨100天教程(三):通过Unity Space Shooter教程

2017-10-23 刘鸿 Gad-腾讯游戏开发者平台

译者:刘鸿(lewis2012)

审校:王玥亭(玥亭)


系列回顾:

VR100天教程(一):设置Unity Ball

VR100天教程(二):Unity Space Shooter教程


欢迎回到第三天的教程中。上一节中我们还没有创建背景,玩家对象,和射击的能力!


今天教程中讨论的核心话题包括:

1)创建边界框来删除越界的对象

2)创造敌人/障碍物

让我们开始吧!


边界(Boundary)


从上次的教程未完成的地方开始,我们创建了一些可以从飞船上发射出的子弹,但如果你看一下游戏hierarchy面板,你会看到很多子弹对象会留在那里。



你射击次数越多,留在hierarchy面板上的对象就越多?


如果你暂停游戏,进入场景选项卡,你会看到子弹实际上一直在前进,永远不会消失。



这是一个问题吗?你打赌!我们实例化的GameObject越多,就越需要计算,这意味着我们的性能将会受到很大的影响!


解决这个问题的方法是创建一个覆盖整个场景的巨大立方体。


我在这个立方体上附加了一个脚本:



我们要依赖的是OnTriggerExit()函数。正如你可能怀疑的那样,当一个碰撞器之碰撞的物体时,这个函数就会被调用。


当我们触发代码时,我们会Destroy()对象,在这种情况下,它就是激光。


然后我们附上这个脚本,你会看到激光消失了。


创造敌人


在下一集视频中,我们将学习如何制造会飞向玩家的小行星。


我们:

1)使用提供的小行星模型创建GameObject

2)附着一个胶囊碰撞器组件

3)将碰撞器调整到尽可能适合小行星形状

4)添加一个刚体组件,并使它成为触发器

5)向小行星添加了随机旋转(RandomRotator )器脚本


 

角速度(AngularVelocity)


角速度是物体旋转的速度。


在视频中,我们使用角速度(AngularVelocity)来创建对象的随机旋转。


我们通过使用Unity的随机函数来做到这一点。具体来说,我们选择使用insideUnitSphere来创建一个位于游戏对象内的随机位置向量,并将其乘以我们希望小行星滚动的速度。


射击时摧毁小行星


现在我们有了第一个“敌人”,&n 43 34198 43 14986 0 0 4708 0 0:00:07 0:00:03 0:00:04 4708bsp;我们想要能够射击和摆脱它!


当我们的激光触及小行星时,没有任何事情发生,这是因为小行星都是触发器,所以它们不会相互碰撞。


我们现在要做的是向我们的对象添加一个脚本,该脚本具有处理与另一个对象冲碰撞时应该发生什么样的逻辑。


我们将这个脚本附加到我们的小行星类中:



我们已经很熟悉这个代码了。当我们的小行星撞上某物时,它会同时摧毁另一个物体和它本身。


有趣的是我们检查我们遇到的对象是否是我们创建的边界框,如果是,我们停止我们的代码。


我们检查边界是很重要的,因为我们不希望当游戏加载的时候第一件事就是这颗小行星与边界相撞,这样的话它们都会被摧毁。


为了解决这个问题,视频创建了一个名为边界(Boundary )的标志,并将其附加到边界的GameObject上。有了这个,当小行星与边界的GameObject发生碰撞时,我们将结束函数调用,什么也不会发生。


爆炸


在下一段视频中,我们添加了一些特殊效果,特别是当小行星被击中时会发生什么。


打开之前创建的DestroyByContact脚本,该视频进行了一些修改:



在代码中,将2个GameObjects作为公共变量。这些是本教程提供的爆炸效果:一种是小行星爆炸,另一种是玩家爆炸。


类似于我们如何创建一个新的子弹GameObject,我们为小行星实例化Instantiate()一个爆炸的GameObject,如果小行星与玩家对象相碰撞(我们设置了一个标志),我们也会使玩家爆炸。


一旦我们将上面的代码添加到脚本中,我就回到编辑器,并将爆炸效果附加到脚本组件。


重用代码


还要注意,在这个视频中,我们将我们的移动(Mover )脚本重新附加到我们的小行星,并将速度设置为-5。


结果,它不是像我们的子弹那样向上移动,而是朝着相反的方向移动:向下。


重要的是,脚本本身是可重用的组件,我们不需要为每个GameObject创建一个脚本,如果现有的脚本已经做了一些需要的事情,我们可以重新使用相同的脚本,使用不同的值!


游戏控制器


在下一个视频中,我们致力于创建一个游戏控制器。游戏控制器负责控制游戏的状态,在这种情况下,控制器是用来产生小行星。


对于GameController脚本,我们将其附加到一个新的Empty GameObject。我们将这个游戏对象GameController称为GameController,我们为它创建了GameController脚本。



让我们来看一下这段代码。


我们创建了一些公共变量:



hazard 变量表示小行星,spawnValues变量表示我们将实例化我们的小行星的位置范围。


我们创建一个新的函数SpawnWaves()并从Start()函数中调用它。我们会在后面的视频看到为什么要这样做,但是,阅读函数中的代码:



我们创建了一个Vector3 类型的变量,代表着希望小行星在哪里创建。我们使用Random.Range()在我们给出的2个值之间创建一个randomize值。我们不想更改我们的GameObject的Y或Z值,所以我们只会随机化我们的X位置(左和右)


Quarternion.identity只是意味着没有旋转。这对我们这段代码表示我们正在随机的位置创建一个小行星,而不是旋转。


我们没有旋转的原因是它会干扰我们已经为小行星添加的旋转脚本。

 

产生一波又一波


目前,该代码只产生一颗小行星。如果玩家只需要避免一颗小行星获胜,那将是一场相当无聊的游戏。


接下来,在这段视频中,我们创造出了一波又一波的小行星,让玩家来躲避。


为了做到这一点,我们可以在GameController脚本中复制和粘贴更多的预制到Start()中,然而,这不仅让内部代码很冗余,而且还会使将来更改代码更困难。


以下是我们最后的结果:



协程


协程( Coroutines)是运行你的代码的函数,返回并将控制权返回到Unity中,然后重新开始,在等待条件满足之后重新开始。


我们可以在上面的代码中看到更多的内容。我们有:

返回新WaitForSeconds(spawnWait);


这意味着我们将等待时间来产生一个新的敌人。但是,如果我们要做如下事情:

产生返回空(null)

代码将在下一个帧后立即执行。


听起来是不是很熟悉?这是因为它们与Update()工作原理非常相似!


根据我的理解,如果你想的话,你几乎可以使用协程(coroutines)替换Update(),但是使用它们的主要好处是防止在Update()中填入代码。


如果有一些代码逻辑,我们只想使用一次,我们可以使用协同程序来避免不必要的代码运行。


另外要注意的是,协程(coroutines)在代码的正常流程之外运行。如果你要这样做:



我们的控制台将打印:



如果我们要做这样的事情:



我们会得到这样的结果:



1秒后将会出现混合打印:



这种情况发生是因为我们多次调用协程(coroutines),一秒钟后,当i = 1时函数开始打印,而Update()在i = 0时仍在生成新的协程(coroutines)调用


除了协程(coroutines),其余的代码是非常明显的,我们在等待时间中添加了一些公共变量。


清理爆炸对象


当我们的太空船摧毁了一颗小行星时,就会产生爆炸。然而,爆炸从未消失。这是因为这些爆炸从未离开我们的边界。


我们做的是附加DestroyByTIme爆炸脚本。剧本将在一定时间内销毁GameObject的爆炸。


这样做的代码非常简单。



结论


这就是第3天的课程,今天我们学到了

1)如何使用边界来清理一些游戏对象

2)创建,移动和摧毁敌人

3)如何使用协程(coroutines),在某些方面类似于Update()


我今天就到此为止!在本系列的下一部分中,我们将研究如何创建UI和音频来完成space shooter游戏。


点击阅读原文,可阅读原始文章并访问VR挑战100天的内容。


【版权声明】

原文作者未做权利声明,视为共享知识产权进入公共领域,自动获得授权。


----------------------

今日推荐


2017年第三季度AI 行业全景热度观察

Multiverse CEO 范威洋自述创业历程

PlayStation VR发售一周年,谈VR游戏世界格局


添加小编微信,可享双重福利

1.加入GAD游戏VR交流圈

获取行业干货资讯,观看大牛分享直播

2.领取GAD独家VR资料库,地址在小编朋友圈

包括研究报告、游戏制作、项目分享等全套资料


↓长按添加小编GAD-安琪↓

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存