撰写了文章 更新于 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);
}
测试一下跑起来效果如何
目录