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

作者:Yumir
哈喽大家好我的yumir。
惯例先上成果链接:
https://connect.unity.com/mg/other/untitled-9864
本篇相对前面两篇会比较简短啦,但是剩下的内容一篇讲完又太多太复杂,所以还是单独开一片力求把问题将清楚,也欢迎大家多多提出自己的疑惑。
接下来开始制作元气骑士小地图吧。

地图UI
我在元气骑士地图自动生成那篇文章提到过,元气骑士的地图实际上是在5*5的格子里面从中心开始向四周随机衍生房间,没记错的话是五到六个。
比如这次Demo做的地图是这样的:

表现到小地图上就是这样的:

地图整体的UI布局是这样的:

将上图切割成9*9的矩阵可知,该图是由若干方块、横向长方形和纵向长方形组成的,在组成的图形对应位置上放上小房间的图标表示为起点,另外再新建一个红色的小方块作为玩家定位点。
可以利用Grid Layout Group进行排版,制作一个9*9的方块布局,再在方块中设置对应的形状,在Ctrl+D的加持下一两分钟就可以做完了。
需要注意的是,在使用这个UI的时候是需要通过显示隐藏当中的方块来绘制地图的,如果这时候物体身上挂载了Grid Layout Group,就会导致显示出来的格子全都会自动对齐,所以在使用之前需要将Grid Layout Group去掉。
地图逻辑
我想要编写一个用于管理小地图的UI显示的脚本,首先对脚本的需求进行分析,该脚本管理的就是一个小地图UI(上面的9*9格子)和一个用于表示玩家位置的小方块。
所以新建一个用于管理小地图UI的脚本,持有小地图本体和表示玩家位置的小方块,声明一个list用于管理小地图上所有的格子。
在Start方法中进行初始化:
public Transform littlemap;
public Transform playerIndex;
List<Transform> mapItems;
void Start(){
mapItems = new List<Transform>();
foreach (Transform item in littlemap){
mapItems.Add(item);
}
for (int i = 0; i < mapItems.Count; i++){
mapItems[i].gameObject.SetActive(false);
}
mapItems[40].gameObject.SetActive(true);
}
掐指一算我的小地图需要三个功能,分别是:更新玩家所在的房间、更新可以探索的地方、更新已探索的房间等。除此之外还有一个显示特定某个房间的需求,但是只有在初始房间需要用到,所以就没有提取为方法。
1、更新玩家所在的房间
小地图实现这个功能的任务其实可以简化到两行代码,由调用者输入房间号,小地图根据房间号计算出房间在小地图对应的位置,将玩家方块设置到该位置即可。
public void UpdatePlayerIndex(int num){
int mapNum = num / 5 * 18 + num % 5 * 2;
playerIndex.transform.position = mapItems[mapNum].transform.position;
}
那么我们需要如何使游戏在合适的时候更新玩家的位置呢?
目前我是这样解决的:
首先在每个房间新建一个触发器覆盖房间范围(省事,后期进行优化)。这样一来我们就能得到一个“玩家进入某房间”的事件,每个房间有各自的管理脚本,我在房间脚本的父类中声明了玩家进入的方法。

public class RoomTrig : MonoBehaviour{
private void OnTriggerEnter2D(Collider2D collision){
if (collision.transform.tag == "Player")
GetComponent<Room>().PlayerEnter();
}
}
虽然本篇只涉及到更新玩家所在位置这一操作,但是后续可以在该事件中对不同房间进行多样化操作。
在游戏管理脚本中声明更新玩家所处房间的方法:
public void UpdatePlayerRoom(Room room){
this.room = room;
//更新地图显示
littleMap.UpdatePlayerIndex(room.roomNum);
if (!room.isExplored){//如果没有被探索过
littleMap.UpdateCanExploreInMap(room);
littleMap.UpdateRoomsExploredInMap(room.roomNum);
}
}
2、更新可以探索的地方
这个操作需要用到一组数据,也就是我之前实现地图自动生成时用到的树状结构的“房间类”,因为制作demo的时候地图并不是动态生成的,所以房间的数据也需要手动添加。

等以后有机会做动态生成的时候再将数据剥离即可。
可以看到目前的数据结构是每个房间持有自己的子节点房间,存放于nextRooms数组中。
在小地图管理脚本中声明一个新的方法:
public void UpdateCanExploreInMap(Room room){
foreach (Room nextRoom in room.nextRooms){
int data = nextRoom.roomNum - room.roomNum;
int roomNum = room.roomNum;
int roadNum = 0;
switch (data){
case -5://上
roadNum = roomNum / 5 * 18 + roomNum % 5 * 2 - 9;
break;
case 5://下
roadNum = roomNum / 5 * 18 + roomNum % 5 * 2 + 9;
break;
case -1://左
roadNum = roomNum / 5 * 18 + roomNum % 5 * 2 - 1;
break;
case 1://右
roadNum = roomNum / 5 * 18 + roomNum % 5 * 2 + 1;
break;
default:
break;
}
int nextRoomNum = nextRoom.roomNum / 5 * 18 + nextRoom.roomNum % 5 * 2;
mapItems[nextRoomNum].gameObject.SetActive(true);
mapItems[roadNum].gameObject.SetActive(true);
}
}
该方法遍历传入的房间对象所持有的nextRooms数组,根据房间号的差判断可探索房间位于所处房间的哪一个方位,计算两个房间之间的道路格子的位置。
最后将小地图上房间之间的“道路”和可探索的房间设置显示,就可以了。
3、更新已探索的房间
上文游戏管理脚本中的更新玩家所处房间方法中有一个if判断,当玩家进入一个房间,如果该房间还没有被探索过,是需要执行两个方法的,一个是上文中的更新可以探索的房间,那么玩家当前所处的房间也就可以被标记为已探索。
现在想想这里改成将整个地图隐藏,当玩家探索完毕的时候再调用这个方法会更好,下次一定。
public void UpdateRoomsExploredInMap(int room){
int mapNum = room / 5 * 18 + room % 5 * 2;
mapItems[mapNum].GetComponent<Image>().color = new Color(1, 1, 1, 1);
}
我事先把所有表示房间的格子的颜色都设置为白色半透明的格子,当玩家探索完之后,改为不透明格子,就是已经探索完了。
一个简单好用的小地图UI就这样制作完成了,文中提到的地图自动生成方法如果没有看过并且感兴趣,传送门在这里:

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