
传送门
Unity官方实例教程 Space Shooter(一)
Unity官方实例教程 Space Shooter(二)
Unity官方实例教程 Space Shooter(三)
Unity官方实例教程 Space Shooter(四)
Unity官方实例教程 Space Shooter(五)
前言

在Unity官方实例教程 Space Shooter(一)中,我们学会了:
- 如何下载和导入资源
- 如何设置游戏视窗大小
- 添加了飞船和飞船喷射效果
- Capsule Collider和Mesh Collider的用法
但是我们还没有为游戏添加任何的操作,现在还只是一个可以看,但不能玩的版本,所以今天我就让游戏可以玩起来!
你将学到什么?
- 如何控制飞船移动
- 如何限制飞船的移动范围
- 如何整理公共变量
- 添加游戏背景
- 如何创建一个新材质
- 如何让飞机发射子弹
一、调整摄像机的位置
我们进入Game窗口,可以看到现在飞船是出于屏幕的正中间的,对于我们最终的游戏来说,这不是一个合适的位置,所以我们首先调整一下摄像机的位置,来改变飞船在屏幕中的位置
这边其实也可以调整飞船的位置,来达到同样的目的,但是让飞船处于(0,0,0)的位置,会利于我们之后的制作,所以本例中我们采用调整摄像机的位置的方法来实现
我们选中Main Camera,然后将其的Position的Z值调整为5,然后我们看一下飞船的位置,如下:

这是一个不错的位置,接下来我们便可以来实现飞船的移动功能了
二、控制飞船移动
为了实现飞船的移动,首先我们给飞船也就是我们的Player添加一个脚本(Script),关于如何添加脚本请参见Unity官方实例教程 Roll-a-Ball(一),在这里我们将脚本的名字命名为PlayerController,然后我打开脚本,添加以下代码:

- 首先我们定义了公共的变量speed
- 然后我们用两个变量moveHorizontal和moveVertical记录玩家输入的方向数据
- 然后我们新建一个Vector3类型的变量movement,并且将moveHorizontal和moveVertical分别赋值给movement的X和Z
- 最后我们获取Player的刚体的速度属性,将movement乘上speed的值赋给它
代码写完之后,我们保存一下代码,然后回到Unity编辑器,将speed设置为10,接着运行游戏来检测我们刚刚的代码是否起到作用了。如无意外,现在我们可以控制飞船上下左右移动了!

不过现在飞船移动好像不是那么的生动,我们在给飞船左右移动的时候,让飞船整个身体倾斜一点,这样更加性感,我们再次打开脚本,增加以下代码:

- 首先我们添加一个公共变量tilt,来设置飞船倾斜的幅度
- 然后我们获取Player刚体属性的rotation,将我们移动的速度x值乘上-tilt赋值给rotation属性
关于Quaternion的详细信息有兴趣的朋友可以去查阅官方文档,后面会出专门的文章来详细讲解,这边就不做详细介绍了,大家只需要知道这句话的作用就是实现飞船左右移动时的倾斜功能
代码写完之后,我们保存一下,然后回到Unity编辑器,将tilt设置为5,接着运行游戏,我们就可以检查刚刚的代码是否起到作用,如无意外,飞船左右移动的时候就会有倾斜效果了

三、限制飞船的移动范围
我们实现了飞船移动功能后,会发现一个问题,就是飞船可以移动到屏幕外面去,这样玩家就看不到飞船了,这不是好的体验,就像马航失联一样,所以我们需要限制一下飞船的移动范围,让它无法飞出我们的屏幕外
让我们来思考一下,如何来限制飞船的移动范围呢?首先我们飞船的移动范围,换句话说就是飞船的Position属性,而它的范围呢,就是我们的屏幕边界,由于我们游戏视角是俯视角,飞船的Y轴位置不会变,所以我们只需限制飞船在X和Z轴上的位置即可,我们在编辑器拖动飞船到屏幕的最左边,可以看到飞船的X大约在-6左右,我们使用同样的方法,可以测试飞船在X和Z轴上的范围分别是(-6,6)和(-3,8)。
接下来我们看看如何在代码中来限制飞船的位置:

- 首先序列化了一个Boundary类,用来保存飞船在X和Z轴上的范围,也就是xMin、xMax、zMin、zMax
- 然后我们定义了一个变量boundary
- 最后我们获取飞船的位置属性,然后通过Mathf.Clamp来确保飞船在X和Z轴上的范围处于我们设定的值内
将xMin、xMax、zMin、zMax整合到Boundary类里面,是方便分类管理公共变量,如下图:可以通过小三角来收起/展开,这样让公共变量更加整洁
Paste_Image.png
写完代码后,我们保存一下,然后回到Unity编辑器,将xMin、xMax、zMin、zMax的值分别设置为(-6,6,-3,8),然后运行游戏测试一下,就可以发现,现在飞船无法跑出屏幕外了,Nice!
四、添加游戏背景
和官方视频不同,我们这边到这一步才添加游戏背景,原因是游戏背景和后面马上要讲到的子弹,都用到了同一个GameObject——Quad,所以两个东西放到一起来讲
首先我们新建一个Quad对象,然后进行两个标准动作,将名称命名为BackGround,新建成功后,我们在Game视窗中可以看到,没有任何变化,为什么呢?我们回到Scene视图来看一下,Quad到底是个什么东西

我们可以看到,Quad就是一个类似平面(Plane)的对象,它使垂直与摄像机的,所以我们看不到他,所以我们需要将它在X轴上旋转90°,然后我们就可以在Game视窗中看到了

我们观察一下BackGround的Inspector属性,由于我只是做背景用,所以Mesh Collider我们根本不需要,这里我们就将该组件给移除掉

接下来我们将背景图片资源,直接拖入BackGround里面,Unity自动为我们生成了一个材质,此时我们可以看到BackGround变成了如下的样子:

这就是我们的背景,额,作为一个背景,它好像还是有很多问题,太小、太暗,比例失调,所以首先第一步,我们就是将它的大小调整到合适的尺寸,我们选中背景图片资源,观察一下他的信息

我们可以看到,背景图片的尺寸为10242048,为了让图片比例不会失调,我们需要将BackGround*的X设置为Y一半,我们将XY分别设置为(15,30)

我们可以看到,现在BackGround的比例已经正常了,大小也合适,但是图片还是太暗了,这是由于我们选中的材质渲染模式有关系,
我们将Shader修改为Unlit/Texture后,图片颜色就会变得正常了

最后一步,作为背景,我们发现它有一部分将飞船给遮挡了

所以我们需要将背景往下移动一些,而且由于我们的摄像机是选用的正交模式,所以背景下移并不会改变他的显示效果,我们将BackGround的Position Y设置为-10,这样背景就不会在挡住飞船了
五、制作子弹
为了视觉效果和逻辑分离,我们首先新建一个空的GameObject,命名为Bolt,然后继续新建一个Quad,命名为VFX,将VFX拖入到Bolt下面,然后我们选中VFX,把它的Rotation X设置为90,同样的,作为Quad,我们也需要像背景一样,将一个图片显示在上面,但是,这里我们和设置背景图片不一样,我们使用一种新的办法来设置,首先我们新建一个材质
新建材质
首先我们选中Create->Material,创建一个新的材质,命名为fx_Bolt_orange

然后我们选中刚刚新建的材质,修改它的Shader模式为Particles/Additive

然后将子弹的图片和材质关联起来,如下图:

最后我们将我们做好的材质拖入VFX中

我们便可看到子弹的效果做好了!

给子弹添加碰撞
一开始我们说了要视觉效果和逻辑分离,所以我们移除VFX中的Mesh Collider组件,然后给Bolt添加刚体和胶囊碰撞(Capsule Collider),同时按下图设置他们的属性:

让子弹飞一会儿
到这里,子弹的视觉效果和物理属性我们都已经设置好了,下一步我们让子弹可以在发射后往前移动,如果子弹不能移动那还怎么打到人呢?
所以我们给Bolt添加一个新的脚本,命名为Mover,然后打开并编辑它,如下图:

- 首先我们定一个公共变量speed用来调节子弹飞行的速度
- 然后我们在子弹生成时赋予它一个往前的速度
写完代码后,我们保持一下,然后回到Unity编辑器,将speed速度设置为20
制作成Prefab
做完子弹的所有准备工作后,我们将Bolt制作成一个Prefab(预制件),方便以后使用

最后我们边可以运行一下,看到子弹飞出去的效果了

六、飞船发射子弹
现在我们有了飞船,有了子弹,下一步就应该把它们联合起来,让飞船可以发射子弹,那么开始之前,我们思考一下,要实现飞船发射子弹的功能,我们需要一些什么?
- 首先我们要知道子弹从哪里发射
- 然后我们需要检查用户按键,来接受发射信号
- 然后我们需要设置子弹发射的频率
- 然后我们还需要知道如何生成一个子弹
我们一个个来看
设置子弹发射点(Shot Spawn)
在实现子弹发射之前,我们将场景中现有的Bolt删除,因为我们不需要他了
首先我们新建一个空的GameObject,命名为Shot Spawn,作为飞船的一个武器挂载点,确保所有的子弹都是从这个点出发,然后我们把Shot Spawn拖入到Player下面,并调整Shot Spawn的位置到合适的点,本例中置为飞船前方就可以了,如下图:

实现发射功能的代码
然后我们打开PlayerController脚本,新增以下代码:

- 首先我们定义一个私有变量nextFire,用来记录下一发子弹的时间
- 然后我们定义一个公共变量fireRate,用来控制子弹发射的间隔时间
- 接着我们定义一个公共变量shot,用来保存我们发射的子弹Prefab,也就是告诉程序,我们发射的是哪个子弹
- 然后我们定义一个公共变量shotSqawn,用来保存子弹的发射点,也就是告诉程序,子弹从哪里发射出去
- 接着我们在Update函数中,判断用户是否有按下Fire1键,这边的Fire1键就是键盘上的左Ctrl键和鼠标左键,同时当前时间超过我们下一发子弹所需的时间,换句话来说,这个if的作用就是确保我们武器没有在冷却时间时按下发射键,才会发射子弹
- 当if条件通过后,我们先记录下一发子弹的时间,然后通过Instantiate方法生成一发子弹,他有3个参数,一个是发射的对象,一个是发射对象的position,一个是发射对象的rotation
写完代码后,我们保存一下,然后回到Unity编辑器,并分别设置我们刚刚定义的几个公共变量,如下:

所有操作做完后,我们边可以运行游戏,看看实际效果了!

下集内容
在下一集,我们将学会:
- 如何回收子弹
- 如何创建障碍物
- 如何通过代码创建无尽波数的障碍
- 如何实现子弹击碎障碍功能
网友评论
另外,就是如果直接把mover.cs绑定到VFX,在下两章会导致另一个问题,即子弹与岩石相撞之后,判定相撞的对象是VFX而不是bolt,这在后面回收的时候只回收了VFX而没有回收bolt。(这个BUG在我找了一圈问题之后才明白)。
楼上@stezpy 删除VFX其实并不合适,这样没有实现“视觉效果与逻辑的分离”。
B:那是因为飞机的速度在FixedUpdate函数里面会不停的更新,所以你在Start里面设置的速度,会在游戏运行中,在FixedUpdate里面改变,而你没有输入,所以飞机的速度就是为0的
C:这个道理和B一样的
我不太明白镜头的size参数是什么意思
如果size是10,是600*900的分辨率,意思是每个单位size表示60*90的区域么
还有gameobject里position里的x,y,z是以什么为标准的,每个position里的值是什么意义,和分辨率是如何对应的。
希望博主有时间的话能指点一下,十分感谢楼主的教程。
2、GameObject里的Position的X,Y,Z是表示GameObject在世界坐标系下的xyz坐标值,本例中的GameObject的位置确定是在Game视图下,实际观看GameObject的位置来手动调整的