【Unity俯视角射击】我们来做一个《元气骑士》的完整Demo(五)

作者:Yumir
哈喽大家好,我是yumir。
惯例先上成果链接:https://play.unity.com/maintenance-mode(如果链接打不开大家可以晚点再来试一下,Unity这个功能有时会进行维护)

我保证这篇真的是完结篇。
本篇文章讲的是房间管理系统,可以说是把整个游戏串起来的一根线。
当前demo并没有制作初始菜单,也就是,打开即开始!
玩家在游戏中通过从一个房间进入下一个房间来推进游戏的进程,所以我会顺着房间的路线来分享我的制作方法(地图只有一条路线)。

一、房间的基本结构
房间的结构分为数据行为脚本和触发器脚本。
由于没有写随机生成算法所以数据部分都是手动录入的,我将房间的行为划分为:初始化、玩家进入房间、房间中的怪物死亡、打开房间门、关闭房间门以及每帧更新房间中的信息等方法。
触发器脚本则是只有当玩家进入触发器范围时调用房间的玩家进入房间方法这一行为(在之前的文章提到过)。
在GameManager中,我在Start方法中获取当前场景中的所有房间并调用所有房间的初始化方法,将所有房间的探索标志isExplored设置为false,并且将所有房间的门打开:
public virtual void Initialization(){
isExplored = false;
OpenDoor();
}
二、不同种类的房间
目前我制作了四种房间,分别是起始房间、怪物房间、宝箱房间、Boss房间。后期需要新的房间类型需要继承Room类进行脚本编写。
1、起始房间
起始房间的管理脚本基本上是没有内容的,由于并不存在怪物,所以在玩家进入方法中需要添加isExplored =true。
public override void PlayerEnter(){
base.PlayerEnter();
isExplored = true;
}
由于所有房间都需要在玩家进入时通知GameManager,所以我在父类的PlayerEnter中调用了GameManager的UpdatePlayerRoom,UpdatePlayerRoom的内容在本系列第三篇中提到过,该方法的功能时对小地图的显示内容(玩家位置以及可探索地图)进行更新。
在起始房间我放了一个告示牌和一个宝箱,这两个道具在本系列第一篇也已经讲过怎么制作。
但是在制作本篇文章的内容时,我需要在玩家接近武器的时候在屏幕上显示武器的名字,突然想起来告示牌和武器其实可以归为游戏中的可互动(会显示名字)的物体,所以我声明了一个接口。
interface GetTipsInfo
{
string GetTipsInfo();
}
所有可互动物体继承该接口,由玩家在每次射线检测时检测调用,如果射线检测到的物体获取该接口不为空,则调用GameManager的显示提示UI方法显示对应的文字。

2、怪物房间
有怪物的房子逻辑比较复杂,玩家进入房间时房间中的怪物进入开始巡逻状态,当玩家将房间中存在的怪物清理之后又要出现新的怪物,就是一个简单的孵化器的需求。
一般应该是以配表的方式添加怪物,然后再每帧检测剩余的怪物数量是否为零,如果为零则生成新的怪物或者探索结束。由于房间是有障碍物的需要写相对复杂的怪物生成位置的逻辑,时间有限就用了一个取巧的方法:
新建若干个用于存放怪物的父物体,将怪物在场景中摆放好,并且在怪物房的脚本上持有这些父物体。

在初始化方法中设置父物体的显示隐藏,每个父物体相当于一个批次的怪物列表。
public override void Initialization(){
base.Initialization();
//设置当前房间的怪物显示,读取当前怪物表,设置怪物的room
monstersGroupNumber = 0;
for (int i = 1; i < monstersGroup.Length; i++){
monstersGroup[i].SetActive(false);
}
LoadMonstersInGroup(monstersGroupNumber);
}
void LoadMonstersInGroup(int num){
//相当于生成怪物
monstersGroup[num].SetActive(true);
Monster[] theMonsters = monstersGroup[num].GetComponentsInChildren<Monster>();
for (int i = 0; i < theMonsters.Length; i++){
monsters.Add(theMonsters[i]);
theMonsters[i].Initialization(this);//标记怪物属于该房间
}
}
当玩家进入房间时,房间可能被探索过也有可能还没被探索,所以需要判断一下。
public override void PlayerEnter(){
base.PlayerEnter();
if (!isExplored){
CloseDoor();
ActivationMonster();//唤醒房间中的怪物
}
}
当房间中的怪物死亡时,需要在房间持有的怪物列表删除怪物的记录,当怪物列表清空时需要产生新的怪物或者更改房间的探索状态,所以需要每帧询问怪物列表的长度。
public override void UpdateRoomInfo(){
base.UpdateRoomInfo();
if (monsters.Count == 0){
monstersGroupNumber++;
if (monstersGroupNumber < monstersGroup.Length){
LoadMonstersInGroup(monstersGroupNumber);
ActivationMonster();
}
else{
isExplored = true;
OpenDoor();
}
}
}
当monstersGroupNumber的值不小于monstersGroup的长度,就是当前房间中的所有批次的怪物都被清理了,所以直接开门并标记房间已探索就可以了。
3、宝箱房间
宝箱房的控制脚本和起始房间的脚本一样,场景中的游戏物体只有宝箱(系列第一篇文章中写过制作方法),不做赘述。
4、Boss房间
Boss房目前只有Boss怪,所以我就直接持有Boss怪了,将怪物房的怪物列表换成Boss怪执行对应的操作即可。
Boss的AI在本系列第二篇有提到过,这里虽然没有写,但是如果你跟着做的话需要去看,当然这并不影响本文的内容。
当Boss死亡时游戏结束,需要将场景中的传送门显示出来,这里我直接在Boss怪死亡时调用MonsterDie方法,场景中的传送门(endDoor)持有触发器,当玩家走进触发器时触发场景跳转,重新开始游戏。
public override void MonsterDie(Monster monster){
base.MonsterDie(monster);
endDoor.SetActive(true);
isExplored = true;
}
三、一些需要优化的地方
当前这个Demo只是实现了基本的功能,还有许多可以完善的地方。
目前没有应用对象池;
游戏角色出场时没有动画;
攻击时没有击退效果;
激光武器没有宽度;
房间中的道具多样化;
可以图形化编辑的房间布局编辑器。
四、发布到Web
最后想起来可能会有读者不知道怎么把项目发布到Web,这里简单说一下。
1、打开你的Hub-安装,点击图中的版本Unity右上角,选择添加模块。

2、勾选WebGL Bulid Support,点击完成让Unity自动帮你安装就可以了。

3、打开Package Manager,下载WebGL Publisher。这一步并不是必要的,如果你想上传到其他第三方网站并不需要下载这个插件。

4、将项目部署到WebGL。

5、如果你做了第三步,可以在Unity上方的菜单栏上看到Publish选项,点击选择WebGL Project。

6、如果你打开的界面里找不到项目,可以尝试重新部署或者重启Unity,点击Publish等待上传完成,Unity会自动跳转到对应的上传网页,自己修改信息保存就可以把网页分享给朋友试玩了。

——分割线——

欢迎加入游戏开发群欢乐搅基:1082025059
对游戏开发感兴趣的童鞋可戳这里进一步了解:http://www.levelpp.com/