撰写了文章 更新于 2019-12-23 19:52:47
《消亡的海》游戏开发日志03-状态
不同于状态机,只是方便判断角色当下的状态(处于对话/购物/正常/战斗状态)。 以后写战斗系统时,处理AI时再写状态机。
开放游戏源码:https://gitee.com/adolk/boat,Unity版本2019.2.12f1
这次计划完成:
①角色状态切换
②对话
角色状态种类
// 角色状态种类 public enum EnumRoleState { Normal, Talking, Questing, Trading, }
状态切换条件类
// 状态切换条件 public class StateCondition { public Npc npcData; // 以后可以再添加新的条件 public StateCondition() { npcData = null; } }
角色状态类
有点长
// 角色状态类 public class RoleState{ public EnumRoleState enumRoleState; // 角色状态 public Npc actNpc; // 当前互动的NPC public Dialog dialog; // 当前互动的对话 public Quest quest; // 当前互动的任务 public int talkIndex; // 当前对话序号 public RoleState() { enumRoleState = EnumRoleState.Normal; actNpc = null; dialog = null; quest = null; talkIndex = 0; } // 切换状态 public void ChangeState(EnumRoleState ers, StateCondition se) { // 切换的状态与当前一致 if (ers == enumRoleState) return; // 切换成普通状态 if (ers == EnumRoleState.Normal) { enumRoleState = EnumRoleState.Normal; actNpc = null; dialog = null; talkIndex = 0; // 切换成谈话状态 } else if (ers == EnumRoleState.Talking) { enumRoleState = EnumRoleState.Talking; if (se.npcData == null) return; actNpc = se.npcData; dialog = actNpc.dialog; talkIndex = 0; // 如果有任务,强制接任务 if (actNpc.questList != null) { enumRoleState = EnumRoleState.Questing; quest = actNpc.questList[0]; // TODO 搜索所有任务,未完成的、满足前置条件的,直接接 dialog = actNpc.dialog; } } } // 允许移动和搜索互动NPC public bool AllowMoveAndSearchNpc { get { // 如果角色处于正常状态(不处于互动状态),就可以跟NPC互动(或者以后跟宝箱、隐藏物品互动) if (enumRoleState == EnumRoleState.Normal) { return true; } else { return false; } } } // 允许对话 public bool AllowTalking { get { if (enumRoleState == EnumRoleState.Talking || enumRoleState == EnumRoleState.Questing) { if (dialog != null) { if (talkIndex < dialog.contentList.Count) { return true; } else { talkIndex = 0; dialog = null; } } } return false; } } // 允许交接任务和交易 public bool AllowQuestAndTrade { get { // 如果正在对话中,可选择接下来交易或接任务 if (enumRoleState == EnumRoleState.Talking) { return true; } else { return false; } } } }
角色类
public class Role { public string uname; public Pos pos; // 角色在城内的坐标 public float xStep; // 在格子内的像素位置 public float yStep; // 状态 public RoleState roleState; public string faceTo; // 任务 public List<Quest> completedQuestList; public List<Quest> acceptQuestList; public Role(string _uname, Pos _pos) { uname = _uname; pos = _pos; xStep = 0; yStep = 0; // 状态 roleState = new RoleState(); faceTo = "down"; // 任务 completedQuestList = new List<Quest>(); acceptQuestList = new List<Quest>(); } // 移动 public void Move(string _dir, City _city) { if (_dir == "up") { // 超过一格 if (yStep + 1 >= RoleConfig.gridStep) { // 超出城市上界 if (pos.yPos + 1 < _city.height) { yStep = 0; pos.yPos += 1; } // 未超一格 } else { yStep += 1; } faceTo = "up"; } else if (_dir == "down") { // 超过一格 if (yStep - 1 < 0) { // 超出城市下界 if (pos.yPos - 1 >= 0) { yStep = RoleConfig.gridStep; pos.yPos -= 1; } // 未超一格 } else { yStep -= 1; } faceTo = "down"; } else if (_dir == "left") { if (xStep - 1 < 0) { // 超出城市左界 if (pos.xPos - 1 >= 0) { xStep = RoleConfig.gridStep; pos.xPos -= 1; } } else { xStep -= 1; } faceTo = "left"; } else if (_dir == "right") { if (xStep + 1 >= RoleConfig.gridStep) { // 超出城市右界 if (pos.xPos + 1 < _city.width) { xStep = 0; pos.xPos += 1; } } else { xStep += 1; } faceTo = "right"; } } // 搜索对话范围内的NPC public Npc GetTalkNpc(City _city) { Npc _resultNpc = null; // 遍历城市内的NPC,看哪个与角色的距离处于对话范围内,且处于角色面向方向 foreach (Npc _npc in _city.npcList) { int xoff = Mathf.Abs(_npc.pos.xPos - pos.xPos); // X轴距离 int yoff = Mathf.Abs(_npc.pos.yPos - pos.yPos); // Y轴距离 // 如果X轴和Y轴都处于对话间距内 (这里的 RoleConfig.talkRange 我设为1格) if (xoff <= RoleConfig.talkRange && yoff <= RoleConfig.talkRange) { // 如果角色面向上方 if (faceTo == "up") { // 且NPC处于玩家上方 if (_npc.pos.yPos >= pos.yPos) { // 返回这个NPC _resultNpc = _npc; } } else if (faceTo == "down") { if (_npc.pos.yPos <= pos.yPos) { _resultNpc = _npc; } } else if (faceTo == "left") { if (_npc.pos.xPos <= pos.xPos) { _resultNpc = _npc; } } else if (faceTo == "right") { if (_npc.pos.xPos >= pos.xPos) { _resultNpc = _npc; } } } } return _resultNpc; } }
OK,开始写控制类
按键控制类
// 按键控制类 public class ControlManager : MonoBehaviour { public static ControlManager Instance; void Awake() { if (Instance == null) Instance = this; } void Update() { Move(); Talk(); Cancel(); } // 移动 void Move() { Role role = App.Instance.role; City city = App.Instance.city; if (role == null) return; if (city == null) return; if (role.roleState.AllowMoveAndSearchNpc == false) return; bool _up = Input.GetKey(KeyCode.W); bool _down = Input.GetKey(KeyCode.S); bool _left = Input.GetKey(KeyCode.A); bool _right = Input.GetKey(KeyCode.D); if(_up) { role.Move("up", city); } if (_down) { role.Move("down", city); } if (_left) { role.Move("left", city); } if (_right) { role.Move("right", city); } } // 发起谈话 void Talk() { Role role = App.Instance.role; City city = App.Instance.city; if (role == null) return; if (city == null) return; bool _talk = Input.GetKeyUp(KeyCode.Space); // 按空格键发起谈话 if (_talk) { // 未处于对话状态 if (role.roleState.AllowMoveAndSearchNpc) { // 搜索角色面向的NPC Npc _currentNpc = role.GetTalkNpc(city); // 没找到NPC if (_currentNpc == null) return; // 找到NPC 开始对话 role.roleState.ChangeState(EnumRoleState.Talking, new RoleStateNS.StateCondition() { npcData = _currentNpc }); return; } bool allowTalking = role.roleState.AllowTalking; // 已经在对话中 if (allowTalking) { role.roleState.talkIndex += 1; // 将 Dialog.contentList 切换到下一条 allowTalking = role.roleState.AllowTalking; // 重新判断是否还能对话 // 话说完了 if (!allowTalking) { role.roleState.ChangeState(EnumRoleState.Normal, new RoleStateNS.StateCondition()); } } } } // 取消互动 按ESC键 void Cancel() { Role role = App.Instance.role; if (role == null) return; bool _cancel = Input.GetKey(KeyCode.Escape); if (_cancel) { // 取消互动 role.roleState.ChangeState(EnumRoleState.Normal, new RoleStateNS.StateCondition()); } } }
插入NPC,再在NPC里插入对话
// 在城市中插入NPC (没别的意思,真的)
public void InitNpcInCity() {
Dictionary<int, Npc> npcDic = presetNpc.npcDic;
// 出生城
City bornCity = presetCity.cityDic[(int)EnumCity.BornCity];
bornCity.npcList.Add(npcDic[(int)EnumNpc.Yefeng]);
}
// 插入对话到NPC
public void InitDialogInNpc() {
Dictionary<int, Npc> npcDic = presetNpc.npcDic;
// 出生城-叶风
Npc yeFengNpc = npcDic[(int)EnumNpc.Yefeng];
yeFengNpc.dialog = new Dialog();
yeFengNpc.dialog.AddContent("风叔,听说你找我?", 1);
yeFengNpc.dialog.AddContent("你老爸上回让我帮一盒东西,你有空捎一下。", 0);
yeFengNpc.dialog.AddContent("好的。", 1);
}