Unity高级项目实战课件01点击动作游戏精讲
Unity高级项目实战课件01点击动作游戏精讲
怪物点击动作游戏11.1玩法介绍u在怪物群中穿梭斩杀Ø武士能够自动行走.u点击按键攻击怪物!Ø点击鼠标按键后发起攻击,打倒怪物Ø在指定时间内尽可能多地击倒怪物。21.1玩法介绍u一次性斩杀多个怪物,Ø对于密集分布的多个怪物,可以通过一次攻击就将其全部斩杀。Ø被砍中的怪物向四面八方飞散飞。Ø近处斩杀怪物将得到高分!Ø斩杀怪物时离得越近,得分越高。Ø如果不出现失误,怪物的数量将会增加!得分也会增加。Ø连续斩杀怪物后,出现的怪物数量会逐渐增加。Ø尽可能零失误地持续斩杀怪物,是获得高分的秘诀。31.1玩法介绍u碰到怪物后将失败!u一旦武士和怪物发生接触,游戏就会结束。41.2简单的操作和爽快感不一论创作何种游戏,都会有一些刚开始时就必须考虑的一些事情,那就是游戏的内容.我们在玩游戏的时候,在编写代码的时候,在漫无目的地浏览网负的时候,可能在很偶然的瞬间,脑子里突然浮现出了关于游戏的灵感。构思游戏题材的这个过程,其实是很有乐趣的。的主人公武士。问了之后才知道,除了角色外,还有把怪物逐个砍到的动画。就在那个瞬间,笔者萌发了“用这个角色来制作游戏”的想法就这样,在和设计师深人交流后,制作这个游戏的念头就产生了。决定游戏的内容时有一些要注意的事项。首先就是操作简单。为了便于操作,我们只使用鼠标的一个按键,没有移动和跳跃操作,略显单调,不过如果能营造出点击按健时的韵律感,一定是一款有趣的游戏。还有一个要点是斩杀时的爽快感。画面上的大量怪物要夸张的向四处飞散。游戏的场景大体如下页的插图所示. 这次我们从角色的形象出发构思了游戏的内容灵感这尔西说不定什么时候就会冒出来.一旦感觉到“这好像可以作成游戏呢!”就要把它记录下来,也许什么时候就能派上用场了(确实是这样的)。52.1脚本一览672.2本章小节u无限滚动的背景u无限滚动的背景的改良u管理怪物出现的模式u武士和怪物的碰撞检测u得分高低的判定u使怪物被砍中后四处飞散83无限滚动的背景u3.1关联文件uFloorControl.cs93.2概要在怪物这个游戏中,代表玩家的武士一直向右方前进,在游戏结束之前势必将移动非常远的距离。如果将所需要的背景全部做到一个模型中,那么数据量将非常大。而且还必须在游戏开始的时候就生成这些背景,非常麻烦。在“怪物”这个游戏中,背景仅仅用于显示,和游戏的内容没有关系。即使重复出现同样的背景也不会影响游戏的内容。显示在画面中的也只局限于武士周围的一小部分而已。既然这样,我们就可以反复利用几个相同的组件来合成背景,并且只在玩家的周边将各个组件逐个显示出来(图)。103.3背景组件的显示位置我们准备了三种类型的背景组件。分别是背景A、背景B和背景C(图)。背景组件通过循环并列显示A, B, C三种背景组件,就能够呈现出没有缝隙的背景。而实质上各个组件只有一个显示在了画面中。刚开始时,A, B, C各个组件都显示在武士的周围。当游戏开始武士移动了一定距离后,各个组件将移动到下一个合适的位置(图)。因为总共有二种组件,所以组件的移动宽度=3x一个组件的宽度。这个值在源代码中存放于变量total_width中。1112请在Unity中启动游戏,按下暂停按键切换到场景(Scene)视图。可以看到背景只显示在了武士的周围(图)。133.3背景组件的显示位置把这个流程用代码描述出来,就是下面这样(从FloorControl类中摘出的一部分)。143.3背景组件的显示位置 判断组建是否该移动的逻辑位于代码的(a)行。 floor_position表示背景组件的位置,camera_positio。表示摄像机的位置。虽然程序中使用了摄像机的位置来决定背景的移动,但为了便于理解,这里我们使用武士的位置来说明。由于武士位于画面中央偏左的位置,严格来说摄像机和武士的X坐标值并不相同。但是为了便于理解背景移动的算法,不妨认为这个等式成立:摄像机的X坐标=武士的X坐标。 组件位于floor-position.x时,该组件再次出现时的坐标“floor_position.x + total_ width”如果摄像机的X坐标大于中间点floor_Position.x+total_ width/2.0f,那么距离下次出现的位置比距离现在的位置更近,组件将移动到下一地点。153.3背景组件的显示位置3.4小结这次我们介绍了无限循环的背景的基本制作方法。有些需要碰撞检测的游戏中会创建一个所谓的“地形”模型,但即便是在那种情况下,不影响游戏性的远景也常常通过这种循环显示背景组件的方法来表现。164无限滚动的背景的改良u4.1关联文件uFloorControl.cs174.2概要上节介绍的算法中,背景只在每次调用Update()时移动一次。这样一来,如果武士移动的距离很长,就有可能出现背景和角色的移动不和谐的情况(图)。虽然我们这个游戏中并不会达到那样快的移动速度,但是有些游戏中出现过玩家角色移动,或者在场景中移动到错误位置的现象。下面就让我们来考虑一下这种情况的解决办法。184.3稍作尝试让我们来实际体验一下上节所述的问题。作为调试,这里保留了武士能够一瞬间移动很远的距离这一功能。启动游戏后请按下W键。如图,可以看到在武士周围的背景不复存在了。在Unity中执行时,将其切换到场景视图后使用逐帧模式观察,可以看到背景组件在缓缓移动。在这种情况下,为了能够正确显示背景,该如何处理呢?194.4背景组件显示位置的改良在前一小节中,我们提到了相同类型的背景组件会按照total _wzdth=一个组件的宽带x组件数量(3个)的间隔重复出现。也就是说,程序将从下列值中,选取一个最靠近武士坐标的值作为背景组件出现的位置。因此,只要求出上面算式(1)中。的值,就可以确定背景应该出现的位置。 接下来,让我们看看改良后的FIoorControl.Update方法。20214.4背景组件显示位置的改良在图中,dist是武士的移动距离。将dist除以背景组件的整体宽度total_ width后的结果赋值给n。224.4背景组件显示位置的改良n是整数,但是经除法求出的结果并不一定是整数。因此把结果代入n之前,需要先做四舍五入处理。如果只是简单地进行类型转换(cast ),将直接舍去小数部分,请读者注意这一点。之所以使用四舍五人而不是直接舍去小数部分,是为了在舍去和进位两种情况中选取最靠近武士坐标的情况(图)。这种思路和上节提到的“越过中间点”的判断是一样的。234.4背景组件显示位置的改良可以使用Mathf.RoundTolnt方法来实现四舍五入。Mathf是Unity中的一个功能类。它含有很多基本的数学训算功能。还有一种实现四舍五人的方法:让数字加上0.5后再舍去小数部分:可以利用Mathf.FIoorTolnt方法舍去小数部分。使用RoundToInt和FloorToInt方法时,需要注意输入值为负数的情况:RoundToInt直接对绝对值进行操作,而FloorTolnt则会连同符号判断数值大小。 右表举例列出了分别用这两种方法对正负数进行操作的结果。在这个游戏中,武士的坐标只取正数。山于即使武士会往相反的方向移动也要判定“更近的一端”,因此程序中使用了RoundToInt方法。但是在某此游戏中,则可能需要找出“更靠近左边的一端”,这种情况下就应该使用FloorToInt方法总之,我们应当依据不同的情况灵活选择最好的方法。244.4背景组件显示位置的改良到此为止,我们对循环显示背景组件的方法做了改良。不过大部分情况下,使用前一小节所介绍的方法就足够了,一般没有必要考虑怪物和武士的移动。开发过程中花太多精力在无关紧要的事情上容易造成本末倒置,不过在时间允许的情况下适当做一些有益的尝试,一也许会对后续的开发很有帮助。请读者在明确“完成游戏”这一目标的同时,享受这种探索的乐趣。254.5小结5怪物出现模式的管理u5.1关联文件uLevelControl.csuOniGroupControl.cs265.2概要游戏启动后不久,画面右方将出现怪物(图)。游戏的目标是不停地砍倒怪物并持续前进。27基本上,怪物只有跑向武士这一个动作。武士和怪物都沿直线跑动,玩家的操作仅仅是在合适的时机按下按键。非常简单。但是简单的操作绝不意味着游戏是无趣的。在面向智能手机的游戏中,很多都仅仅支持点击屏幕操作。但其中大受玩家欢迎、百玩不腻的游戏也不占少数。和这些游戏类似,我们这个游戏的精髓在于控制好点击按键的节奏:通过调整怪物出现的频率和速度,可以实现多种不同的情境。下面让我们花些时间来设计怪物出现的方式,让游戏变得更有趣。285.2概要5.3怪物出现的时间点下面我们来看看该如何决定怪物出现的间隔。如果怪物相继出现的间隔很短,玩家就必须很快地点击按键,这样游戏就比较难。相反,如果怪物出现的间隔比较长,或者移动的速度比较慢,那么游戏就会比较简单。首先考虑到怪物的运动速度和出现间隔=难易度,我们在每次成功攻击怪物后就增加游戏的难度。当然这里需要设置一个上限,并使出现失误后游戏会回到最初的状态。每当武士前进了一定距离,怪物就将在其前方出现(图1.11 )。怪物出现的位置位于武士前,正好在画面之外即将进人画面的位置。如果这个距离过短画面上将会突然出现一个怪物。反之如果过长,则会导致在画面的渲染区域之外存在许多怪物,增加不必要的处理开销。在设计怪物出现模式的时候,需算出武士从当前位置出发应当前进多远才让下一个怪物出现。如果玩家能很顺利地斩杀怪物,就让这个距离越来越短,而如果玩家出现失误,则恢复到最初的长度(图)。实际试玩这个游戏后,就可以体会到随着怪物出现的间隔变短,游戏的难度也在渐渐增加。不恰当的速度或间隔的上限值可能将汗致无法完全除怪物,因此游戏开发者们要通过反趁试玩来调整得出合适的值。29305.3怪物出现的时间点315.3怪物出现的时间点5.4怪物出现模式的变化虽然速度加快会导致游戏变难,不过反复试玩几次后玩家就会惊奇地发现自己完全能够适应了。即使是一开始觉得比较难的速度,经过jL次挑战后似乎也变得没有什么了·这主要是因为目前怪物出现的间隔是固定值的缘故。请读者想象一下和着音乐打拍子的情景。大家应该都有过这样的体会,即“即使节拍很快也跟上了”。其实两者的原理是一致的。因为不论速度多快,但节奏是相同的,所以玩家只需要按照同样的时间间隔点击按键就可以打倒怪物。为了使玩家能够体会到点击按键的爽快感,要求游戏具备一定的节奏。不过如果一直使用同样的节奏,玩家很容易就可以消除怪物,这样游戏就显得有些无趣了。也就是说,问题不在于速度,而在于节拍是固定的。那么我们试着每隔一段时间,就使用特别的出现模式。这里我们制作了以下几种和普通模式不一样的特别模式(图)。32u连续:怪物以短于正常时的时间间隔涌上来。u缓慢:怪物移动的速度比一般模式的最低速度还慢,并且出现的间隔很长。玩家在持续玩难度较大的关卡时会感觉疲劳,因此可以插入这个模式供玩家休息调整。u赶超:后出现的怪物追赶并超越更早出现的怪物。后登场的怪物将会更早到达武士的位置,这样会使玩家难于决定出手的时机,让其措手不及。可以说是这个游戏中比较难的一种模式。u加速减速:登场的怪物到达画面中央附近位置后加速,快要接近武士时减速,然后再朝武士前进。游戏的情景就好像伴随着“危险!快跑!”“不!这样不行!”这样的台词。相比用于控制游戏的难易度,这种模式更适合用于营造游戏的演示效果。345.4怪物出现模式的变化我们把这4种特别模式和普通模式混在一起来控制怪物的出现。每经过若干次普通模式后就随机选择一种特别模式。普通模式的持续次数也通过随机决定(图)。355.4怪物出现模式的变化开始特别模式时,以及从特别模式恢复到普通模式时,必须确保画面中的怪物已经完全消失。这样可以防止特别模式和普通模式中的怪物同时出现。比如我们看看在“加速减速”模式中出现普通怪物的情况。当怪物在画面右边加速前进时如果出现了别的怪物,有时就会造成两个怪物以非常短的时间间隔到达武士的位置(图)。为了避免这种情况,需要在使用特别模式前后等待一段时间,直到画面上的怪物“编队”完全消失。那么,下面我们就来看看上述流程的实际代码吧。365.4怪物出现模式的变化375.4怪物出现模式的变化3839(a)首先检查是否已经准备好了生成下一批怪物。就像前面所说明的那样,这是为了防止在特别模式中出现其他怪物。(b)如果还没做好生成怪物的准备,需要检查现在和下一批怪物的出现模式是特别模式还是普通模式。当满足下列两种条件时,可以生成下一批怪物。 (b1)当前为特别模式并且画面中已经没有怪物了 (b2)当前为普通模式(C)以现在的武士所在位置为基准,计算出怪物的生成位置。怪物从登场开始到消失为止,武士前进的距离随各模式不同而不同。因此,需要在准备好生成怪物的时候,就定好怪物将要产生的位置。计算出怪物的生成位置后,产生怪物的准备工作就完成了。这之后直到新的怪物被创建出来,(b)和(c)的处理都将被跳过。(d)武士的位置超过oni_generate_line后生成新的怪物。(e)最后,提前选择下一次将生成的怪物的类型。相对于在怪物生成后立刻选择下一批怪物的类型,程序在怪物从画面上消失时就要计算下一批怪物产生的位置。处理流程可能稍微有些复杂,请读者参考下面(图)的程序流程图理解一下。405.4怪物出现模式的变化415.4怪物出现模式的化变5.5小结除了除了这里里举例的例的4种模式之外,种模式之外,应该还有很多种算法。有很多种算法。读者可以在理解了程序的者可以在理解了程序的结构原理后,构原理后,试着自己着自己创造一些造一些有趣的模式。有趣的模式。426武士和怪物的碰撞检测u6.1关联文件uOniGroupControl.cs436.2概要按下鼠标按键后武士将挥刀迎击,如果能成功砍到,怪物将向四处飞去。不过如果没有砍倒怪物却接触到了它,游戏则将结束。为了实现这种功能,需要检验武士对象和怪物对象之间的冲突,也就是所谓的碰撞(collision)检测处理。在很多游戏中,碰撞检测是非常重要的一环,不过在程序处理方面往往是比较麻烦的但是在Unity中,只需设定好形状就可以进行碰撞检测的计算。非常方便!不过这并不意味着我们可以什么都不用考虑。使用何种形状来进行碰撞检测,将极大地影响游戏的效果。在这一点上,即使采用了Unity,也仍旧需要依赖开发人员的经验和直觉。446.3分别对各个怪物进行碰撞检测的问题首先我们尝试对武士采用立方体,对怪物采用球体来执行碰撞检测(图)。角色之间的碰撞检测,经常使用这种粗略的几何形状来进行。这样做的好处是相较于严格的几何形状,计算量会少很多。而且对于大部分游戏而言,这种做法都能得到比较逼真的结果。45一般来说,球体的计算量更小。因为游戏中会出现大量的怪物,所以我们选择了计算量尽可能小的球体作为检测形状。设定好形状之后,就可以用Unity来执行碰撞检测的计算。然后再实现碰撞后武士的行为似乎就大功告成了。不过事实上等游戏运行起来以后,会发现还存在很多问题。第一个问题是,武士会绕开怪物前进的问题(图)。466.3分别对各个怪物进行碰撞检测的问题这是因为怪物的碰撞检测形状比武士的小很多。在Unity的碰撞处理中,为了使对象在发生碰撞后仍可以按照原来的前进方向运动,对碰撞对象加人了滑动之类的处理。请回忆一下动作游戏中角色遇到墙壁时的反应。按照斜线方向一直按住方向键,大部分游戏中角色都将和墙壁发生摩擦继续移动。让碰撞后的对象进行滑动,多数情况下都会使游戏玩起来更简单自然,不过在我们的这个游戏却带来了危害。另外还有一个问题是,攻击的难度将加大(图)。476.3分别对各个怪物进行碰撞检测的问题点击鼠标按键后武士开始挥舞砍刀。攻击检测将伴随着这个攻击动作进行。和怪物的碰撞检测相似,我们也使用球体来进行检测。虽然用于攻击检测的球体尺寸够大,不过从武士的中心位置往内或者往外偏移的地方有可能仍位于攻击范围之外。这样就会出现看起来好像攻击成功了其实却并未命中的情况。即使只剩下了一个怪物也有可能导致游戏以失败告终。像这样,如果稍微错过了时机就会造成失误的话,游戏就变得太难了。针对这个问题,试着改变碰撞检测的形状及其尺寸也是一种解决方法。不过怪物自身的尺寸本来就很小,如果加大的话又将出现另外一个极端,即“看起来没有击中,结果却击中了”的情况可能会增多。让我们试试其他的解决方法。486.3分别对各个怪物进行碰撞检测的问题6.4把怪物编成小组游戏中的怪物总是扎堆出现。同一批次的怪物彼此之间比较密集,另外武士总是沿着直线前进。因此即使把同一批怪物编为一个小组来处理好像也没有问题。于是我们用OniGroup对象把怪物集合起来,将怪物作为它的子元素来处理。碰撞检测也改为对OniGroup对象整体进行(图)。49怪物小组的碰撞检测使用立方体,尺寸和武士的碰撞检测所用的立方体大抵相同(图)。这样设置以后,武士就不能再越过怪物或者从一侧绕过怪物了。另外,假设OniGroup检测到来自武士的攻击后,作为子元素的所有怪物都将受到攻击。这样一来,前面提到的因为怪物的位置稍有差异就导致攻击不成功的情况就不会再有了。并且游戏也增添了多个怪物被同时砍飞的爽快感。506.4把怪物编成小组Unity中允许直接使用模型的形状来进行碰撞检测·不过很多游戏中都采用粗略的形状,而且也能达到像我们这次的游戏一样良好的效果。特别是那些尺寸比其他角色小很多的对象以及大量对象一起移动的情况下,把它们集中归为一个小组做碰撞检测是很好的方法。516.5小结7得分高低的判定u7.1概要大部分游戏都鼓励玩家不断挑战更高的得分。虽然也有像角色扮演(RPG)这类更注重情节而不关注得分的游戏,不过支持玩家通过互联网与其他玩家同台竞技,进而挑战更高得分的游戏正变得越来越多。这次我们开发的是一个斩杀怪物的游戏。成功斩杀怪物后,怪物出现的数量会越来越多。玩家要尽可能地持续斩杀怪物,这样才能在游戏结束之前杀掉大量的怪物。反之,玩家一旦失手,怪物出现的数量就会减少。当然,我们可以直接把倒下的怪物数量作为玩家的得分,但这里我们不妨多琢磨一下,看看怎样才能让游戏更有趣。例如,假若武士在追赶怪物的过程中一直不攻击怪物,最终将撞上怪物。在接近怪物的过程中,如果太近的话就会失手。玩家要在确保不撞上怪物的前提下尽可能地接近怪物并斩杀,这样游戏的技术难度就增加了。这次我们设定了一个“靠近斩杀怪物将得到高分”的规则,但如果靠得太近又会导致武士撞上怪物而失手,这样游戏就变得更加刺激了。如果觉得游戏缺点什么,或许可以尝试着往游戏中加人这种“高风险&高回报”的玩法。527.2武士的攻击判定在讨论如何判断攻击距离的远近之前,我们先说明一下攻击判定的原理。玩家点击鼠标按键后,武士就会发起攻击行为。而攻击判定的计算就将伴随着攻击行为的整个过程。在格斗类游戏中,往往需要对玩家角色的拳脚和所使用的武器执行攻击判定同样,也需要对被攻击者的每个关节部位进行伤害计算。正因为有了这样精细的碰撞检测,才能够实现诸如“蹲下躲开对方的回旋踢”“脚部受到攻击而.导致行走速度减缓”等游戏特性。不过我们这个游戏的碰撞检测并不需要细致到这种程度。由于怪物以很快的速度朝武士靠近,如果要严格按照刀的形状来进行碰撞检测,击中的难度将大大增加。所以这里我们用一个大的球形来进行碰撞检测,并在播放攻击动作的时候将其放置在武士前面(图)。53攻击的碰撞检测的执行时间,会比攻击动作的播放时间稍微长一些。如果提前按下鼠标按键,怪物就将进入上面所说的碰撞检测的球体中,这就意味着攻击成功(图)。格斗游戏中常常有“预判断”的说法。像这种敌人朝着玩家快速扑来的游戏,加人这种机制后会让游戏变得更容易上手。547.2武士的攻击判定7.3判断在多近的距离斩杀通过提前进行碰撞检测和延长检测的时间,就可以应对怪物快速运动的情况。那么,现在让我们回到主题,看看如何才能计算出.“武士在多近的距离斩杀了怪物”。“要计算武士在多近的距离斩杀了怪物,看看怪物和武士之间的距离不就行了吗?”55 我们用脚本PlayerControl.cs来管理攻击判定开始后的时间。其中,attack_timer是用来记录攻击判定持续时间的计时器。在按键被按下的瞬间会用一个特定的值对它进行初始化,随着时间的减少,当它的值变为0时,则意味着攻击判定执行结束。567.3判断在多近的距离斩杀attack_timer表示的只是攻击判定的“剩余时间”,为了获得被用于判段“在多近的距离斩杀”的“经过时间”,我们还需要准备一个叫作GetAttackTimer的方法。SceneControl.cs的AddDefeatNum方法在武士攻击命中怪物时被执行。577.3判断在多近的距离斩杀最后,设定用于度量经过时间和得分高低关系的ATTACK_TIME_GREAT和ATTACK_TIME_GOOD的值。如果经过时间小于ATTACK_TIME_GREAT并在足够近的距离内斩杀了怪物则判定为GREAT,若时间比ATTACKJIME_GOOD短则判定为GOOD,除此之外在远距离斩杀怪物的情况则判定为。KAY。每次攻击后都记录下判定的结果,在游戏结束后再通过这些结果来决定玩家的总体成绩。58通过改变用于衡量得分高低的经过时间的阂值(ATTACK_ TIME_ GREAT和ATTACK_TIME_GOOD ),可以调整游戏中获得高分的难度。比起制作程序本身,有时候调整这些数值反而更花时间。但由于这些数值是决定游戏平衡性的重要因素,因此建议读者通过对照效果调整出最合适的数值。597.4小结8使被砍中的怪物向四处飞散u8.1概要被武士砍中后,怪物将向四面八方飞散。动作的不同将导致攻击力度的强弱表现不同,被攻击的各个对象的反应也有很大差异。在格斗游戏中,对对手一顿拳打脚踢之后,看到其步履蹄姗的样子,往往可以感受到他的疼痛。相反如果对手显得从容不迫,即使动作再华丽也只能给人一种攻击力很弱的印象。有时候我们常常听到“攻击反馈”的说法。在玩游戏时大家应该都有过感觉按键和摇杆好像变重了的经历吧?可以说这种游戏通过视觉和听觉把攻击反馈非常完美地呈现了出来。我们将通过怪物的四处飞散来表现武士的攻击强度。另外,我们也将实现上节提到的靠近斩杀怪物会获取高分的规则,并使“在多近的跟离斩杀了怪物”影响怪物的飞散方式。不过每次都采用同样的方式飞散开未免有些单调,因此我们会调整飞散的方向使每次的效果都略有不同。608.2想象一下“圆锥体”u在考虑实现方法之前,我们首先整理一下“需要做什么”。用专业术语来说这叫作需求分析。Ø要让怪物华丽地四处飞散Ø让每次的动作都各不相同“华丽”这种描述对于编程来说是一个比较暖昧的说法。应该描述得更为具体一些。前面我们已经提到过把若干个怪物编成一个刁、组,并通过这个小组来执行被攻击判定。受到攻击时小组内的所有怪物都将四处飞散。而如果怪物们都向着同样的方向飞去,将毫无“华丽”可言。换句话说,所谓的“华丽”,应该是这些怪物尽量朝着不同的方向飞散开来。这个被刀砍中然后各自飞散开的过程,更类似于炸弹爆炸的画面。由于怪物被刀砍中时受到了某一方向的作用力,因此往相反的一侧飞出才显得自然。武士具有右斩、左斩的动作。每个动作都将令怪物向反方向飞出。“靠近斩杀时怪物将更华丽地飞散开,这个要素也是必要的。虽然单纯改变速度也能达到类似的效果,但为了让玩家更容易地了解是否完美地砍中了怪物,我们将飞散的方向改为前后方向。如果从前面飞来的怪物都按照相同的方向弹开,就能让玩家强烈地感受到攻击的力度那么我们再次细化需要完成的工作。61u怪物朝不同方向飞出u根据动作的不同往左或往右飞出u根据斩杀时距离的远近调整为前后方向u每次飞出的方式都有变化要是每次一飞出的方式都不一样,很多读者可能会想到使用随机数。不过如果仅对飞出的方向和速度进行随机化处理,虽然可以改变飞出的方向,但是不能够保证怪物会按我们期待的方向飞出。像这样“想在随机化的同时进行某种程度的倾向控制”的时候,解决问题的关键就是先确定好关键性的原则,再使用随机数改变细节参数。这里我们参考水管喷头喷水的情景,决定使怪物沿着圆锥的表面飞出,也就是说圆锥的朝向基本上决定了飞散的方向,底面的半径则决定了飞散开的范围(图)。628.2想象一下“圆锥体”638.2想象一下“圆锥体”8.3具体的计算方法接下来,我们对各个参数进行详细的说明·首先看看圆锥的底面半径如何决定了飞散的范围(图)。底面半径越大圆锥的开口范围越广,每个怪物的速度向量的方向也有很大差异,因此怪物的飞散范围就比较广。反之如果半径比较小,则飞散开的范围就比较窄。64u下面,我们通过圆锥的倾角来控制前后方向(图)。这里的“前后”,指的是从武士的视角看到的前后。武士向画面右方前进,也就是+X方向,这样在画面上看起来就是左右倾斜。需要注意的是在计算时会变为围绕Z轴(Vector3.forward)旋转。658.3具体的计算方法u最后,通过圆弧的中心角度来控制左右方向的飞散(图).怪物飞散的方向,也就是速度向量分布在圆锥的表面上。但是它们并没有完全分布在1周360度的各个角度,而是集中在了大约半个圆周的范围内。这里将通过排列着各个速度向量的圆弧(图)中两端是黑点的圆弧)的中心点的角度控制左右方向。程序中使用y_angle_swing变量来表示。下面我们结合代码来看看实际的计算过程。668.3具体的计算方法678.3具体的计算方法u(a)将blowout_up设为朝上方向的向量。这是圆锥的中心轴,圆锥的初始状态为直立,且 顶点在下。u(b) blowout_xz为底面中心指向圆周方向的向量。base_radius为圆锥的底面的半径,这个值决定了怪物飞散开的范围的大小。u(c)使vblowout_xz向量绕Y轴旋转。y_angle是将小组整体的圆弧以y_angle_swing为中心按怪物数量平均分割后得到的角度值。u(d) blowout_ up, blowout_ xz分别为初始速度向量的垂直和水平分量·这里将二者相加因为最后要将此向量和速度相乘,所以事先用Normalize()进行规范化。u(e)使求出的向量围绕Z轴(Vector3.forward)旋转。这相当于将圆锥向前后倾斜。u(f)将向量与速度值相乘得到最后结果。u程序中的参数以及各个步骤(a)一(f)和圆锥的对应关系如图。688.3具体的计算方法698.3具体的计算方法实际的游戏中会使用随机化的参数,使每次的结果都略有不同。像这样先确定好大原则后再用随机数对细节参数进行调整的方法,是游戏开发中经常用到的技巧。至于该使用什么样的大原则则因游戏而异。这次游戏中使用的是圆锥体,地面上发生爆炸时可以采用半球,2D游戏中可以使用扇形等。请读者务必尝试一下这些方法来加深理解。708.4小结
相关知识
Unity优化百科(UWA 博客目录)
Unity微信小游戏上架实战:个人开发者指南
千锋Unity3d第一人称游戏项目实战视频教程(完整版)
Unity移动游戏开发
Unity入门:如何使用Unity
Unity游戏开发实战:详解如何在Unity中调用Android原生方法实现功能扩展
Unity 3D 中文教程
Unity手机游戏开发:从搭建到发布上线全流程实战
Unity 3D性能优化实战指南
Unity经典卡牌游戏制作教程
推荐资讯
- 1老六爱找茬美女的烦恼怎么过- 4999
- 2博德之门3黄金雏龙法杖怎么得 4869
- 3《大侠立志传》剿灭摸金门任务 4312
- 4代号破晓官方正版角色介绍 4023
- 5赛马娘锻炼到底的伙伴支援卡事 3803
- 6闪烁之光11月兑换码大全20 3776
- 7原神原海异种刷怪路线-原神原 3547
- 8爆梗找茬王厕所特工怎么通关- 3544
- 9《我的世界》领地删除指令是什 3440
- 10原神开局星落湖怎么出去 原神 3426