如何做一款类似疯狂喷气机的游戏--Part2

原文地址:http://www.raywenderlich.com/69544/make-game-like-jetpack-joyride-unity-2d-part-2?utm_source=tuicool 泰然翻译组:xiao yu 校对:lareina。

本文是关于如何使用Unity 2D引擎制作一款类《疯狂喷气机》游戏教程的第二部分。如果你想要参见第一部分,请参见这里。

在教程的第一部分,我们实现了这样一个简单的小游戏-一只可爱的小老鼠在房间中上自由的飞来飞去,再辅以漂亮的火焰,游戏场景看起来非常炫酷。然而,尽管火焰看起来比较赏心悦目,但是仅仅简单的添加喷气火焰并不能使游戏具有很好的可玩性。

在这一部分,将讲解如何自如控制游戏中的小老鼠自如穿行于可以随机生成的房间,不同房间对应不同的游戏等级。此外,当小老鼠在地板上的时候,使用动画使小老鼠在房间中奔跑。

开始

如果已经根据第一部分教程完成了其中的游戏部分,现在在之前的工程上继续。当然你也可以选择下载我们提供的现有工程部分:RocketMouseFinalPart1

找到你之前的工程,或者解压下载的工程,打开其中的RocketMouse.unity 场景

实现老鼠向前飞行

现在开始逐步讲解,为了让小老鼠向前飞行,你需要做两件事情:

  • 控制小老鼠按着指定路线精确运动
  • 控制相机跟随小老鼠运动

下面让我们用代码来完成上述两个任务

设置小老鼠运动速度

很简单,打开MouseController脚本文件,添加如下公共变量:

public float forwardMovementSpeed = 3.0f;

该变量定义了小老鼠的运动速度

注解:将运动速度定义成公共变量,这样就可以在MonoDevelop中而不是打开脚本来对其进行设置。如下图所示:

然后,在FixedUpdate的最后添加如下代码:

Vector2 newVelocity = rigidbody2D.velocity;
newVelocity.x = forwardMovementSpeed;
rigidbody2D.velocity = newVelocity;

上面三行代码仅对速度的x-分量进行设置,这点十分重要,因为y-分量是由火箭动力驱动控制的。

运行程序,可以看到小老鼠向前飞,但是有一个问题—小老鼠可以飞出屏幕。

修正此问题的办法是,控制相机跟随小老鼠。

控制相机跟随小老鼠

新建一个C#脚本文件,命名为CameraFollow。通过拖动使其作为一个组件添加到Main Camera中。

打开CameraFollow脚本文件,定义如下公有变量:

public GameObject targetObject;

在游戏中将小老鼠对象赋值给targetObject,这样就设置了相机的追踪对象。

添加下面代码进行更新:

float targetObjectX = targetObject.transform.position.x;

Vector3 newCameraPosition = transform.position;
newCameraPosition.x = targetObjectX;
transform.position = newCameraPosition;

这段代码取到追踪对象位置的x坐标,并且据此设置相机的位置,从而达到追踪目的。

注解:仅需要修改相机位置的x-分量,因为我们不需要跟随小老鼠上下移动

切回到Unity,选择Main Camera。相机跟踪脚本组件中增加了一个名为Target Object的属性,当前设置为None。

单击架构中Mouse对象,拖动其到指定的Target Object区域,设置目标对象。

注解:拖动时候不可以松开鼠标,因为如果你选中Mouse对象随后释放鼠标的话,就会选中该Mouse对象,对应的右侧会更新为Mouse对象的属性而不是Main Camera的属性。

当然,你还可以通过单击Inspector右侧的锁来锁定Inspector当前显示的对象

运行游戏,此时相机变跟随小老鼠运动了。

到现在为止,相机跟踪小老鼠的功能已经实现,但是,别的我们都还没有做!!本文稍后会继续讲解接下来的工作,但是首先,小老鼠需要一点点空间。。

相机保持在一定距离

大部分类似这种无限模式的竞技酷跑类游戏中,玩家角色(本文中的小老鼠)不会位于屏幕中心,取而代之的是,它会位于屏幕左侧居中的位置,这样可以给玩家更多的时间去做躲避障碍物,收集金币等等操作。。

为实现这个操作,选择Mouse对象,设置Positon为(-3.5,0,0),然后运行游戏。

咦,小老鼠依然位于屏幕中心?这与小老鼠对象的位置没关系了,而是因为相机脚本中把相机位置的x-分量设置成了目标对象的x值。这也是为什么我们可以看到左侧蓝色背景的原因了。。

所以进一步进行秀谷,打开CameraFollow脚本文件,添加 distanceToTarget 私有变量:

private float distanceToTarget;

在Star函数中添加如下代码:

distanceToTarget = transform.position.x - targetObject.transform.position.x;

这行代码计算相机与目标对象的初始距离。

最后在Update函数中将这个初始距离考虑在内,如下代码所示:

>void Update () {
    float targetObjectX = targetObject.transform.position.x;
Vector3 newCameraPosition = transform.position;
newCameraPosition.x = targetObjectX + distanceToTarget;
transform.position = newCameraPosition;

}

这样,在整个游戏过程中,相机在追踪目标对象的同时,与目标对象都保持有恒定的初始距离。

运行游戏,可以看到小老鼠一直位于屏幕偏左侧的中心。

生成无限挑战等级

现在游戏运行几分钟以后,小老鼠就飞出房间进入到我们的蓝色背景中了,真让人难过。

当然,可以通过添加代码来增加房间,包括屋顶,地板,以及一些房间中的装饰。然而在unity 2D中,将完整的房间做成预制件(Prefab),然后在游戏中一次性实例化,这样会使问题变得更简单。

注解:在《疯狂喷气机》游戏中,有很多不同的场景,包括水族馆、洞穴等等,每个场景都有自己的预制件。本文只使用一个即可。

下面给出Unity官方文档中有关预制件的摘要介绍:

预制件是一种在工程视图中存储的可重复使用的游戏资源。预制件可以被任意数量的场景使用,每个场景中也可以使用多次。把一个预制件加入场景,就意味着创建了一个预制件的实例。所有的实例都与原始的预制件相关联,严格来说,所有实例都是原始预制件的复制品。对于原始预制件做出的任何修改,对场景中所有创建的实例都会生效。

换句话说,将物体加入场景,设置物体属性,给其添加组件,障碍物,刚性物体等等。在将物体保存为预制件之后,就可以在场景中任意添加该类物体。

创建房间预制件

我们希望房间预制件包括很多不同的物品:包括书架,窗户,屋顶等。首先需要将这些物品作为孩子节点添加到同一个父节点上。

选择GameObject\Create Empty 创建一个空的游戏对象,然后选择GameObject,在属性栏中修改属性:

  • 重命名为room1
  • 设置位置为(0,0,0)

如下图所示:

把空的对象放到屋子的中间,即放到(0,0,0)点是有意而为之的。当你把很多游戏物体都放到一个空对象中进行组织的时候,它们的位置都是相对于空对象的。这样当你想通过移动空对象来移动整个房间的时候,由于空对象的原点和房间的中心重合,就比较容易操作。

换句话说,当你把物体加入空对象时,空对象的当前位置就成为锚点,把锚点设置到中心比别的位置更有利于后续的操作。

移动所有的房屋物件(bg,bg,bgwindow,ceiling,floor,objectbookcaseshort1,objectmousehole)移动到room1,就像之前把喷气火焰的粒子加入到小老鼠对象身上一样。

如果想用更多的书架和老鼠洞来装饰房间,可以类似的多添加一些。

新建一个名为Prefabs的文件夹,打开并且把room1拖至Prefabs文件夹

这样就完工了。可以看到一个名为room1的预制件,它包括了所有的房屋组件。现在来测试一下,将room1预制件拖至场景中,就可以重复添加很多一样的房间了。。

当然,创建的room1预制件也可以被用于其他的场景中。

房间预制件制作的基本原理

房间生成脚本的原理很简单。脚本中包括一个可以生成房间实例的房间对象数组,一个已经生成的房间对象实例的数组,还有两个方法。一个方法判断是否需要添加房间实例,另一个方法是用来添加房间实例的。

为了判断是否需要增加房间实例,函数需要判断场景中是否还需要一个房间,然后需要增加场景的宽度,来保证玩家可以一致玩下去。。

上图的第一种情况,可以不添加房间,因为,最后一个房间距玩家的距离足够远,大于ScreenWidthInPoints;而第二种情况,则需要添加房间。

注解:小老鼠对象不在屏幕的左边缘,所以尽管距右侧边缘的距离小于屏幕宽度,玩家在第二种情况下还是看不到终点,但是马上会看到,所以在那之前,需要增加一个房间。

当然,上图只是一个简单的例子,事实上,脚本函数在更早的时候(即)就会检测出需要增加房间。

现在开始完成脚本函数。

添加生成房间的脚本函数

新建C#脚本函数,命名为GeneratorScript.将函数添加到mouse游戏对象中。到目前为止,小老鼠对象有两个脚本组件了:

在MonoDevelop中双击打开GeneratorScript脚本文件。

首先添加System.Collections.Generic命名空间,因为在函数需要需要使用List类:

using System.Collections.Generic; 

然后添加变量:

public GameObject[] availableRooms;

public List currentRooms;

private float screenWidthInPoints;

availableRooms数组包括所有的预制件,可以用其来生成实例。本例中,只有一个room1实例,可以添加许多其他类型的预制件到这个数组中,这样,生成函数就可以随意选择要使用的预制件类型来生成场景中的实例了。

注解:本例中完成的工程在Part3的结尾部分可以下载到,工程中包括多种类型的房间预制件,也有在现有基础上的很多改进。暂时为了简单的解释过程,我们只使用一个room预制件。

currentRooms列表包括已经实例化的预制件对象,方便确定当前最后房间的位置,从而来判断是否需要增加更多的房间。一旦房间从玩家背后消失,则将其从列表中删掉。

screenWidthInPoints变量用来存储屏幕宽度

在Start函数中添加如下代码:

float height = 2.0f * Camera.main.orthographicSize;
screenWidthInPoints = height * Camera.main.aspect; 

这两行代码用来计算屏幕宽度。

增加新房间的方法

在GeneatorScript 脚本中增加下述的 AddRoom 方法

void AddRoom(float farhtestRoomEndX)
{
//1
int randomRoomIndex = Random.Range(0, availableRooms.Length);

//2
GameObject room = (GameObject)Instantiate(availableRooms[randomRoomIndex]);

//3
float roomWidth = room.transform.FindChild("floor").localScale.x;

//4
float roomCenter = farhtestRoomEndX + roomWidth * 0.5f;

//5
room.transform.position = new Vector3(roomCenter, 0, 0);

//6
currentRooms.Add(room);
}

AddRoom的参数 farhtestRoomEndX 是当前最后侧房间的右边缘位置。下面逐行来结束上述函数的释义:

  1. 随机生成一个预制件类型用来生成(本例中只有一种)。
  2. 根据随机生成的类型,创建实例room。
  3. 由于房间只是一个包括若干物品的空对象,不能够直接得到大小。可以通过找到天花板的宽度来得到房间的宽度,两者是一样大小的。
  4. 计算新创建房间实例的x位置,紧挨着当前最后一个房间
  5. 设置房间位置。仅需要设置x坐标,因为所有房间的y和z坐标都是0.
  6. 现在稍稍休息一下,下面一个方法会有些复杂。

检测是否需要添加新房间的方法

准备好了么?好的,添加GenerateRoomIfRequired方法:

void GenerateRoomIfRequired()
{
//1
List roomsToRemove = new List();

//2
bool addRooms = true;

//3
float playerX = transform.position.x;

//4
float removeRoomX = playerX - screenWidthInPoints;

//5
float addRoomX = playerX + screenWidthInPoints;

//6
float farthestRoomEndX = 0;

foreach(var room in currentRooms)
{
//7
float roomWidth = room.transform.FindChild("floor").localScale.x;
float roomStartX = room.transform.position.x - (roomWidth * 0.5f);
float roomEndX = roomStartX + roomWidth;

//8
if (roomStartX > addRoomX)
    addRooms = false;

//9
if (roomEndX < removeRoomX)
    roomsToRemove.Add(room);

//10
farthestRoomEndX = Mathf.Max(farthestRoomEndX, roomEndX);

}

//11
foreach(var room in roomsToRemove)
{
currentRooms.Remove(room);
Destroy(room);
}

//12
if (addRooms)
AddRoom(farthestRoomEndX);
}

上面代码看起来很复杂,让人抓狂,实际上一点都不复杂。尤其是你首先要理解之前解释过的原理。

  1. 创建一个新数组用来存储需要被移除的房间。之所以需要单独创建一个数组,是因为当你在遍历的时候,暂时还不能移除。
  2. addRooms 是一个bool型变量,标记是否需要增加新房间,默认值是ture。虽然在foreach循环中,大部分情况下,会被设置成false
  3. 保存当前玩家的位置:这里说的位置,其实特指玩家的x分量位置
  4. 计算一个removeRoomX位置,在这之前的房间是应该被删除的(为了考虑内存因素,看不到的房间要被删掉)
  5. 计算addRoomX变量。如果在addRoomX位置之后没有房间存在,则需要新建房间。
  6. farthestRoomEndX变量存储的是当前游戏等级结束时候的位置,为了使得等级和等级之间无缝对接,需要严格的在这个位置添加新房间。
  7. 使用foreach函数遍历当前的房间,使用天花板的宽度作为房间宽度,并且计算房间的起始位置roomStartX(房间的最左侧位置)以及结束位置(房间的最右侧)
  8. 如果在addRoomX之后有房间,则现在不需要创建新房间。
  9. 如果房间的右侧位置小于removeRoomX,则将该房间加到移除队列
  10. 计算得到 farthestRoomEndX,这个当前等级结束的位置。
  11. 删除掉移除数组中存储的房间。
  12. 如果addRooms变量为true,则证明需要增加房间。

看吧,看起来很复杂,我们还是轻松搞定了!!

在GeneratorScript脚本中添加FixedUpdate函数,它调用GenerateRoomIfRequred函数

void FixedUpdate () 
{
GenerateRoomIfRequired();
} 

这样保证了GenerateRoomIfRequired函数可以周期被调用。

注解:当然这个函数不必每帧都调用,而且生成函数本身也可以进一步优化。保险起见,暂时先这样吧。。

设置脚本各种选项设置,然后享受自己做的游戏吧

现在,返回到Unity,选择mouse游戏对象。在属性栏,找到GeneratorScript:

将room1拖动到CurrentRooms列表,打开Prefabs文件夹,将rooms1拖动到Available Rooms。

这里需要提醒的是,Available Rooms存储的是预制件类型,而Current Rooms存储的是已经添加到场景中的房间实例。

下面给出选择过程的一个Gif图。图中多创建了一个名为room2的预制件,只是为了演示下在存在多个预制件的时候,应该如何选择:

运行游戏。现在可以看到小老鼠在无限模式的房间里飞行了。。

可以注意到,在游戏运行过程中,Hierarchy中的房间不停的出现,消失。为了更了解房间实例创建消失的过程,可以切换到Scene视图,在该视图,可以清楚明了的看到房间是如何被删除和如何被添加的。。

注解:在Scene视图运行一段时间后,会看到空场景。这是因为小老鼠已经飞行过了所有的房间。这时候可以重新运行游戏。

小老鼠的动作模拟

虽然游戏实现了房间的动态创建与删除,但是小老鼠的动作看起来好单调,懒洋洋的。它都不会自己动一下,只会等着喷气火焰推着走。。喷气火焰运行需要昂贵的燃油,所以在地板上的时候,小老鼠还是要自己运动运动。为了使小老鼠跑起来,需要创建一个动画,并且修改MouseController脚本,实现在地面运动以及空中运动的灵活切换。

分割mouse_run动画脚本

小老鼠跑步的动画存储在mouserun 脚本中,所以首先需要把它进行切片。打开Sprites文件夹,找到mouse_run。选中并设置Sprite模式为Multiple。然后单击Sprite Editor打开Sprite编辑器

单击编辑器中左上角的Slice按钮,打开选项。设置Type为Grid,设置grid size为162*156,单击下方的Slice按钮,网格消失。单击右上角的Apply保存:

关闭Sprite编辑器。现在在工程浏览器中打开mouse_run,可以看到,它被分割成了四帧动画。

创建动画

根据分割得到的动画帧,可以进一步创建跑步以及飞的动画。

注解:飞行的动画只包括一个精灵帧,就是在创建小老鼠对象的时候使用的精灵。

打开Animation窗口进行动画编辑,选择Window/Animation打开动画视图。可以拖动使得动画视图停靠在Game视图旁边,这样方便切换操作。

在创建第一个动画之前,在Project新建Animations文件夹,并且打开该文件夹。

下一步,选择mouse游戏对象。

在Animation窗口,新建两个clips:run以及fly,如下图所示:

可以看到,在Animation文件夹中创建了三个文件:包括fly动画文件、run动画文件以及一个mouse动画文件。在Hierarchy中选择mouse,在对应的观察栏中,可以看到Animator组件已经自动添加了。

添加跑步动画帧

首先,在跑步动画中添加帧数据。在动画视图中,选择跑步动画。这里需要保证动画视图和工程视图同时可见。

在工程视图中,打开Sprites文件夹,展开mouse_run帧资源

全选所有的动画帧:mouserun0, mouserun1, mouserun2, mouserun3。拖动这些帧到Animaiton视图的时间线上。如下图所示:

下面给出添加成功之后的效果图:

添加飞行动画帧

不管你信不信,飞行动画只包括一个帧,选择Animation视图中的fly动画:

在工程视图中找到mouse_fly精灵,将它拖到时间线上,就像在跑步动画里一样。

在添加动画帧以后,要保证动画视图的记录模式关闭。可以点击动画视图控制栏中的红点来停止记录模式。

怎么会有人想到用一帧数据来创建动画呢?好吧,这样可以使得跑步和飞行动画之间的切换变得非常容易。

调整动画属性

运行场景,有两个比较奇怪的现象

  1. 小老鼠跑的比较疯癫
  2. 小老鼠都不会落地了,即使你不点击屏幕

庆幸的是,这两个问题都很容易解决。第一个问题是因为动画播放速度过快导致的,第二个是因为设置问题。

注解:不知你注意到没有,小老鼠默认就是飞着的。这是因为你先添加的是飞行的动画,Animatior组件将它设置成为默认动画。如此,场景运行以后以后,小老鼠就开始飞行。

现在修正飞行速度,在动画视图中选择run Animation,并且设置采样属性为8,而不是60。如下图所示:

为解决第二个问题,在Hierarchy中选择小老鼠游戏对象,在观察栏中找到Animator组件。设置Apply Root Motion 为disable,同时设置Animate Physics为enable。如下图:

下面给出Unity官方文档关于Apply Root Motion 属性的摘录:

根动画是一种效果,即使物体脱离原来的状态(通过修改转换矩阵来改变运动状态),而是直接运行由动画本身创建的动画。

换句话说,如果你想要通过改变其变换矩阵来使其运动的话,就需要设置这个Apply Root Motion 为enable,而这不是我们现在所需要的。

此外,由于游戏使用了物理,如果能够把动画和物理能够结合起来就更好了。这就是我们把Animate Physics设置为enable的原因。

运行场景,可以看到小老鼠在地板上行走。

然而,当小老鼠在空中的时候,它依然在走路。

这要怎么办呢?为了修正这个问题,需要创建一些动画的过渡转换对象。

动画之间的切换

由于本例涉及到两个动画,就需要使动画对象(本例中的小老鼠)在两个动画之间自如切换。这里需要使用动画转换机制来解决这个问题。

创建动画转换实例

在上方菜单栏,选择Window/Animator,添加Animator窗口。可以看到Animator窗口中有两个动画:跑步和飞行。跑步动画橙色显示,这代表跑步动画为默认动画:

然而,可以观察到,现在在跑步动画和飞行动画之间并没有任何转换关系。这就意味着,小老鼠会一直僵持在跑步动画的阶段。解决这个问题,需要添加两个转换节点:从跑步到飞行以及从飞行到跑步。

右键点击run动画,选择Make Transition,然后将鼠标放到fly动画上方,左键点击,这就添加了一个从跑步动画到飞行动画的转换。类似的,可以添加一个从飞行动画到跑步动画的转换。

下面给出这两个转换的创建过程:

到目前为止,创建了两个无条件的转换。意思就是,运行场景,小老鼠先跑步,然后完成一个动画过程时候,开始飞行。当飞行结束之后,再开始跑步,就这么来回转换。

不过,这个不过不是很好能观察到,因为飞行动画太短了,只有一帧。但是如果在Animator窗口可以观察到飞行动画和跑步动画之间的切换。

添加转换参数

为了结束这种不健全的循环,可以给转换添加一些控制参数,控制两个动画相互转换的时间。

打开Animator视图,在窗口左下角找到参数面板。目前是空的。单击+按钮来增加一个参数,在下拉菜单中选择Bool类型。

给新参数命名为grounded

选择从跑步到飞行动画的转换,打开它的属性面板(在Inspector栏中),在Conditions部分,把唯一性条件从Exit Time改成grounded,并且设置值为false。

同样对从fly动画到跑步动画的转换做类似的操作,只是把grounded的值设置为true。这样,当ground属性为false的时候,小老鼠开始飞行,当为true的时候,开始跑步。

现在可以通过手动设置ground属性来验证一下添加了条件的转换。运行场景,同时保证Animator视图可见,在游戏运行的过程中,手动选择或者取消选择对于ground属性的数值设置,可以看到下图中的效果:

添加物体来检测是否小老鼠着陆

有很多方法来检测游戏对象是否落地。我比较倾向于下面的方法,因为它比较直观的给出了监测点的位置。

使得这种方法比较直观的原因是,给游戏对象添加了一个空的孩子节点,就像下图显示这样:

创建一个空的游戏对象,拖动到mouse对象上作为其孩子节点。选择新创建的这个游戏对象,重命名为groundCheck,并将其位置设置为(0,-0.7,0)。

由于空对象没有图标,为了使其更明显,给它设置一个图标。单击Inspector的icon selection 按钮,选择green oval。当然也可以选择其他颜色,我是比较喜欢绿色的。

这里给出设置完成以后最后的样子

脚本将使用这个空对象的对中来检测小老鼠是否着陆了。。

使用层来定义什么是着陆

在检测小老鼠是否着陆之前,首先需要定义下何为着陆。如果不这样做的话,小老鼠有可能会在激光上,金币上或者其他带有碰撞体的物体上行走。

这里需要在脚本中使用LayerMask类,在那之前,首先需要给地板设置正确的层。打开Prefabs文件夹,展开room1预制件。选择其中的floor:

在观察面板,选择Layer,在下拉菜单中选择Add Layer:

Tags&Layers编辑器被打开,找到第一个可编辑的条目,图中所示User Layer 8,输入Ground。之前的layer都是Unity自身保留使用的。

下一步,在Prefab文件夹中选择floor,并把它的Layer设置成Ground。

检测是否小老鼠已经着陆

为了让老鼠自动切换状态,你将不得不更新MouseController脚本来检查老鼠目前是否着陆,然后让Animator知道这件事。

在MonoDevelop中打开MouseController脚本,并添加以下实例变量:

public Transform groundCheckTransform;

private bool grounded;

public LayerMask groundCheckLayerMask;

Animator animator;

groundCheckTransform变量将存储之前创建的用于groundCheck的空对象。

grounded变量表示小老鼠是否着陆。

groundCheckLayerMask变量给出具体着陆的定义。

最后,animator变量包含了Animator组件的引用。

注解:使用GetComponent得到的组件对象最好缓存起来,因为GetComponent比较耗时。

为了缓存Animator组件,在Start中添加如下代码:

animator = GetComponent(); 

然后添加UpdateGroundedStatus方法:

void UpdateGroundedStatus()
{
//1
grounded = Physics2D.OverlapCircle(groundCheckTransform.position, 0.1f, groundCheckLayerMask);

//2
animator.SetBool("grounded", grounded);
}

上述方法检测老鼠是否着陆,并且设置对应animator参数

  1. 为检测小老鼠是否着陆,以groundCheck对象的位置为圆心,新建一个半径为0.1的圆。如果圆与在groundCheckLayerMask中定义的层有重叠,则小老鼠着陆
  2. 该行代码设置了grounded参数,从而激活动画

最后,在FixedUpdate函数的结尾,增加对 UpdateGroundedStatus函数的调用。

UpdateGroundedStatus();

这保证每次更新都会调用到,能保证着陆状态实时更新。

设置鼠标控制的脚本参数用来检测是否着陆

下面给出可以使小老鼠自动切换运动状态的最后一小步工作。打开Unity,选择mouse游戏对象。

找到Mouse Controller脚本组件。可以看到新增加了两个参数:

单击Ground Check Layer Mask,在下拉菜单中选择ground层,将groundCheck对象拖动到Ground Check Transform属性栏中:

运行场景。

喷气火焰的使用与不使用

尽管通过系列操作,我们治愈了小老鼠懒惰的毛病,但是依然没有处理浪费的问题。即使在小老鼠在地板上走路的时候,喷气火焰也还是存在。你不会想让小老鼠这样浪费吧,会破产的吆。。我们只需要做一点点修改就可以修正这个问题。

打开MouseController脚本,添加jectpack公有变量,它存储着喷气火焰粒子的引用。

public ParticleSystem jetpack; 

添加如下AdjustJetpack方法:

void AdjustJetpack (bool jetpackActive)
{
jetpack.enableEmission = !grounded;
jetpack.emissionRate = jetpackActive ? 300.0f : 75.0f; 
} 

该方法在ground为true的时候,将喷气粒子禁用。除此之外,,在老鼠落下的时候,减少粒子的发射率。

在FixedUpdate方法中增加对该方法的调用

AdjustJetpack(jetpackActive); 

提醒一下,当按下鼠标左键的时候,jetpackActive为true,否则为false。

现在切换到Unity,拖动jetpackFlames到MouseController的jetpack的属性中:

运行游戏

可以看到,喷气火焰有三种状态,小老鼠着陆的时候,被禁用;当上升运动的时候,给足马力;下落的时候,减少喷射速率。这也比较符合现实生活中的状况。

下面你该继续完成的

我希望读者在看完教程之后,可以有所收获。最终的工程可以从下面链接找到

RocketMouseFinalPart2

下一部分是教程的最后一部分,会加入很多有意思的元素。可以添加激光,金币,音效等等。

如果想要学习更多的关于预制件的只是,Unity文档是个不错的选择。

标签: unity教程

?>