用Unity3D实现简单的牧师与魔鬼游戏(动作分离版)
项目地址
牧师与魔鬼游戏(动作分离版)
完成效果图
上次博客链接
牧师与魔鬼游戏
实现心得
这次作业是在上次作业的基础上完成的,具体做出的改变是添加了一个裁判类和一个行为类,将其它控制类中涉及到判断游戏状态的代码都封装到了裁判类中,并在主控制类添加了一个裁判类的成员变量,在主控制器中使用裁判类的相关方法对游戏状态和游戏对象状态进行判断:
/* 裁判控制类 */
public class JudgeController {
private int gameState = (int)GameState.Playing; // 游戏状态,0表示游戏正在进行,1表示游戏失败,2表示游戏成功
public void InitJudgeController() {
gameState = (int)GameState.Playing;
}
/* 获取游戏对象是否在船上 */
public bool IsOnBoat(RoleController role) {
return role.GetRoleModel().GetIsOnBoat();
}
/* 判断船上是否没有角色 */
public bool IsNoRoleOnBoat(BoatController boat) {
string [] roleOnBoat = boat.GetBoatModel().GetRoleOnBoat();
if (roleOnBoat[0] != "" || roleOnBoat[1] != "") {
return false;
} else {
return true;
}
}
/* 检查游戏状态 */
public int CheckGameState(ShoreController leftShore, ShoreController rightShore, BoatController boat) {
// 初始化左边和右边的牧师和魔鬼数量都为0
int leftPriest = 0, rightPriest = 0;
int leftDevil = 0, rightDevil = 0;
// 获取左岸和右岸以及船上的牧师和魔鬼的数量数组
int [] leftShoreCount = leftShore.GetRoleCountOnShore();
int [] rightShoreCount = rightShore.GetRoleCountOnShore();
int [] boatCount = boat.GetRoleCountOnBoat();
// 如果船在左边,那么左边的牧师和魔鬼的数量为左岸数量加上船里的数量
if (boat.GetBoatSide() == (int)ShoreSide.Left) {
leftPriest = leftShoreCount[0] + boatCount[0];
leftDevil = leftShoreCount[1] + boatCount[1];
rightPriest = rightShoreCount[0];
rightDevil = rightShoreCount[1];
} else {
// 如果船在右边,那么右边的牧师和魔鬼的数量为右岸数量加上船里的数量
leftPriest = leftShoreCount[0];
leftDevil = leftShoreCount[1];
rightPriest = rightShoreCount[0] + boatCount[0];
rightDevil = rightShoreCount[1] + boatCount[1];
}
// 如果左边牧师加魔鬼的数量等于6且魔鬼全部上岸,那么游戏成功
if (leftPriest + leftDevil == 6 && leftShoreCount[1] == 3) {
gameState = (int)GameState.Win;
} else if (leftPriest < leftDevil && leftPriest > 0) {
// 如果任意一边牧师的数量小于魔鬼的数量且有牧师,那么游戏失败
gameState = (int)GameState.Lose;
} else if (rightPriest < rightDevil && rightPriest > 0) {
gameState = (int)GameState.Lose;
} else {
// 否则游戏正在进行中
gameState = (int)GameState.Playing;
}
return gameState;
}
/* 返回是否正在进行游戏 */
public bool isPlayingGame() {
return gameState == (int)GameState.Playing;
}
}
而行为类则是将原先代码中的移动控制器MoveController 和点击控制器ClickController 合并到了一起,其它控制类中出现这两个类的地方也换成了行为类:
/* 行为控制器,一般会挂载到某个具体的游戏对象上 */
public class ActionController : MonoBehaviour {
private ActionModel actionModel;
private ActionView actionView;
private RoleController clickRole; // 如果点击的是角色,那么记录点击的对象的控制器
void Start() {
actionModel = new ActionModel();
actionView = gameObject.AddComponent<ActionView>() as ActionView;
}
void Update() {
int state = actionModel.GetState();
Vector3 middlePos = actionModel.GetMiddlePos();
Vector3 endPos = actionModel.GetEndPos();
int speed = actionModel.GetSpeed();
// 根据速度、中间位置、终点位置、移动状态来移动物体
Move(state, middlePos, endPos, speed);
}
/* 初始化控制器,设置物体不移动 */
public void InitActionController() {
// 如果对象是船,获取船在哪边
int side = actionModel.GetSide();
// 在左边的话,船会回到右边去
if (side == (int)ShoreSide.Left) {
MoveToOtherSide();
}
}
/* 如果对象是船,设置船的岸边边侧 */
public void SetBoatSide(int side) {
actionModel.SetSide(side);
}
/* 获取船的岸边边侧 */
public int GetBoatSide() {
return actionModel.GetSide();
}
/* 根据速度、中间位置、终点位置、移动状态来移动物体 */
public void Move(int state, Vector3 middlePos, Vector3 endPos, int speed) {
switch (state) {
case (int)MoveState.Not_Moving:
break;
case (int)MoveState.Moving_To_Middle:
// 移动物体到中间位置,移动到后,设置物体的下一个状态为移动到终点
actionView.MoveTo(middlePos, speed);
if (transform.position == middlePos) {
actionModel.SetState((int)MoveState.Moving_To_End);
}
break;
case (int)MoveState.Moving_To_End:
// 移动物体到终点位置,移动到后,设置物体的下一个状态为不移动
actionView.MoveTo(endPos, speed);
if (transform.position == endPos) {
actionModel.SetState((int)MoveState.Not_Moving);
}
break;
}
}
/* 设置物体要移动到的位置 */
public void SetMovePos(Vector3 pos) {
// 设置物体开始往中间位置移动
actionModel.SetState((int)MoveState.Moving_To_Middle);
// 设置最终移动位置为pos
actionModel.SetEndPos(pos);
// 如果要移动到的位置的y坐标等于物体所在位置的y坐标,说明是船在移动
if (pos.y == transform.position.y) {
// 船沿直线运动,所以中间位置也可设为最终位置
actionModel.SetMiddlePos(pos);
// 移动状态可以直接设为往终点移动
actionModel.SetState((int)MoveState.Moving_To_End);
}
// 如果要移动到的位置的y坐标小于物体所在位置的y坐标,说明是物体从岸上移动到船上
else if (pos.y < transform.position.y) {
actionModel.SetMiddlePos(new Vector3(pos.x, transform.position.y, pos.z));
}
// 如果要移动到的位置的y坐标小于物体所在位置的y坐标,说明是物体从船上移动到岸上
else {
actionModel.SetMiddlePos(new Vector3(transform.position.x, pos.y, pos.z));
}
}
/* 将船移动到岸的另一侧 */
public void MoveToOtherSide() {
// 先获取船在哪边
int lastSide = actionModel.GetSide();
// 移动船到另一边
if (lastSide == (int)ShoreSide.Left) {
SetMovePos(new Vector3(2.5F, -1, 0));
actionModel.SetSide((int)ShoreSide.Right);
} else {
SetMovePos(new Vector3(-2.5F, -1, 0));
actionModel.SetSide((int)ShoreSide.Left);
}
}
/* 如果对象是角色,设置被点击的对象为该角色 */
public void SetClickRole(RoleController role) {
clickRole = role;
}
void OnMouseDown() {
// 如果鼠标点击的对象是船,那么移动船只
if (gameObject.name == "Boat") {
SingleObject.getInstance().GetMainController().MoveBoat();
} else {
// 如果鼠标点击的对象是角色,那么移动对象
SingleObject.getInstance().GetMainController().MoveRole(clickRole);
}
}
}
这样一来,在实现模块分离和降低耦合性的同时,也保证了游戏功能的一致性。游戏功能和效果和之前没有任何区别。
游戏截图:
正在进行游戏:
游戏失败:
游戏成功:
|