用Unity3D实现简单的牧师与魔鬼游戏
项目地址
牧师与魔鬼游戏
完成效果图
实现心得
游戏所使用的是MVC模式开发。
遵循的动作表为:
动作 | 条件 |
---|
开船 | 船上至少有一个角色(牧师或魔鬼) | 牧师在左岸上船 | 船上至少有一个空位且在左岸,左岸至少有一个牧师,船在左岸 | 牧师在左岸下船 | 船上至少有一个牧师且在左岸 | 恶魔在左岸上船 | 船上至少有一个空位且在左岸,左岸至少有一个魔鬼,船在左岸 | 恶魔在左岸下船 | 船上至少有一个恶魔且在左岸 | 牧师在右岸上船 | 船上至少有一个空位且在右岸,右岸至少有一个牧师,船在右岸 | 牧师在右岸下船 | 船上至少有一个牧师且船在右岸 | 恶魔在右岸上船 | 船上至少有一个空位且在右岸,右岸至少有一个恶魔,船在右岸 | 恶魔在右岸下船 | 船上至少有一个恶魔且船在右岸 |
首先确定游戏界面组成部分:
由游戏界面组成部分可以设计模式开发结构的视图部分:
可以看到,游戏界面由五个部分组成:船、岸、角色、河流、功能提示框,所以首先可以创建船视图BoatView 、岸视图ShoreView 、角色视图RoleView 、河流视图RiverView 和功能视图FunctionView 五个视图类,因为移动也需要在界面中展现,所以还可以创建一个移动视图MoveView ,从而很简单地确定了MVC结构的视图部分:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace PriestsAndDevils {
/* 船视图 */
public class BoatView {
private GameObject boat; // 创建船视图需要的游戏对象
/* 创建船视图 */
public BoatView() {
boat = Object.Instantiate(Resources.Load ("Perfabs/Boat", typeof(GameObject)), new Vector3(2.5F, -1, 0), Quaternion.identity, null) as GameObject;
boat.name = "Boat";
}
public GameObject GetGameObj() {
return boat;
}
/* 为游戏对象添加移动控制器 */
public MoveController AddMoveScript() {
MoveController moveScript = boat.AddComponent(typeof(MoveController)) as MoveController;
return moveScript;
}
/* 为游戏对象添加点击控制器 */
public void AddClickScript() {
boat.AddComponent(typeof(ClickController));
}
}
/* 岸视图 */
public class ShoreView {
private GameObject shore; // 创建岸视图需要的游戏对象
/* 根据岸的边侧创建游戏对象和视图 */
public ShoreView(int side, string sideName) {
shore = Object.Instantiate(Resources.Load("Perfabs/Shore", typeof(GameObject)), new Vector3(7 * side, -1, 0), Quaternion.identity, null) as GameObject;
shore.name = sideName;
}
}
/* 角色视图 */
public class RoleView {
private GameObject role; // 创建角色视图需要的游戏对象
/* 根据角色类型和序号创建游戏对象和视图 */
public RoleView(string roleName, int number) {
role = Object.Instantiate(Resources.Load ("Perfabs/" + roleName, typeof(GameObject)), Vector3.zero, Quaternion.identity, null) as GameObject;
role.name = roleName + number;
}
/* 为游戏对象添加移动控制器 */
public MoveController AddMoveScript() {
MoveController moveScript = role.AddComponent(typeof(MoveController)) as MoveController;
return moveScript;
}
/* 为游戏对象添加点击控制器 */
public ClickController AddClickScript() {
return role.AddComponent(typeof(ClickController)) as ClickController;
}
/* 获取对象名字 */
public string GetName() {
return role.name;
}
/* 设置角色父对象 */
public void SetRoleParentTrans(Transform trans) {
role.transform.parent = trans;
}
/* 设置角色位置 */
public void SetPos(Vector3 pos) {
role.transform.position = pos;
}
}
/* 移动视图 */
public class MoveView : MonoBehaviour {
/* 在界面上根据移动位置和速度呈现物体移动效果 */
public void MoveTo(Vector3 pos, int speed) {
transform.position = Vector3.MoveTowards(transform.position, pos, speed * Time.deltaTime);
}
}
/* 河流视图 */
public class RiverView {
private GameObject river; // 创建河流视图需要的游戏对象
/* 创建河流视图 */
public RiverView() {
river = Object.Instantiate(Resources.Load ("Perfabs/River", typeof(GameObject)), new Vector3(0, -1.5F, 0), Quaternion.identity, null) as GameObject;
river.name = "River";
}
}
/* 功能视图 */
public class FunctionView : MonoBehaviour {
private string tipContent; // 提示框显示内容
public FunctionView() {
tipContent = "Click and Play the Game";
}
public void SetTipContent(string tip) {
tipContent = tip;
}
/* 初始化提示框 */
public void InitFunctionView() {
tipContent = "Click and Play the Game";
}
void ShowResetButton() {
GUIStyle resetStyle = new GUIStyle("button");
resetStyle.fontSize = 20;
// 按下重置按钮,游戏被初始化
if (GUI.Button(new Rect(30, 20, 70, 30), "Reset", resetStyle)) {
SingleObject.getInstance().GetMainController().InitGame();
}
}
void ShowTip(string tipContent) {
GUIStyle tipStyle = new GUIStyle();
tipStyle.fontSize = 20;
GUI.Label(new Rect(Screen.width - 140, 20, 100, 50), "Priest: Yellow\nDevil: Red", tipStyle);
tipStyle.fontSize = 30;
tipStyle.alignment = TextAnchor.MiddleCenter;
// 展示提示内容
GUI.Label(new Rect(Screen.width / 2 - 50, 70, 100, 50), tipContent, tipStyle);
}
void OnGUI() {
ShowTip(tipContent); // 展现提示框
ShowResetButton(); // 展现重置按钮
}
}
}
由视图部分可以接着设计模型部分和控制器部分:
对于模型部分,因为河流基本没有相关逻辑,功能提示框的逻辑与整个游戏有关,所以首先想到,只为船Boat、岸Shore、角色Role创建三个模型,另外两个部分可以直接创建视图,移动视图也可以创建一个模型,从而使具体的游戏对象可以挂载一个移动控制部分进行移动,所以MVC的模型部分,一共可以创建BoatModel 、ShoreModel 、RoleModel 、MoveModel 四个模型类:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace PriestsAndDevils {
/* 船模型 */
public class BoatModel {
private int side; // 岸边方向,-1表示船在左岸即终点岸,1表示船在右岸即出发岸
private string [] roleOnBoat = new string [2]{"", ""}; // 船上的角色,要不为牧师或魔鬼,要不为空
public BoatModel(int side) {
this.side = side;
}
public void SetSide(int side) {
this.side = side;
}
public int GetSide() {
return side;
}
public void SetRoleOnBoat(string [] roles) {
roleOnBoat = roles;
}
public string [] GetRoleOnBoat() {
return roleOnBoat;
}
}
/* 岸模型 */
public class ShoreModel {
private int side; // 岸边方向,-1表示左岸即终点岸,1表示右岸即出发岸
private string [] roleOnShore = new string [6]{"", "", "", "", "", ""}; // 岸上的角色,要不为牧师或魔鬼,要不为空
public ShoreModel(int side) {
this.side = side;
}
public void SetSide(int side) {
this.side = side;
}
public int GetSide() {
return side;
}
public void SetRoleOnShore(string [] roles) {
roleOnShore = roles;
}
public string [] GetRoleOnShore() {
return roleOnShore;
}
}
/* 角色模型 */
public class RoleModel {
private int roleType; // 角色类型,0表示牧师,1表示魔鬼
private bool isOnBoat; // 角色是否在船上
public RoleModel(int type) {
roleType = type;
}
public void SetRoleType(int type) {
roleType = type;
}
public int GetRoleType() {
return roleType;
}
public void SetIsOnBoat(bool isOnBoat) {
this.isOnBoat = isOnBoat;
}
public bool GetIsOnBoat() {
return isOnBoat;
}
}
/* 移动模型 */
public class MoveModel {
private static int speed = 25; // 移动速度
private Vector3 middlePos; // 移动的中间位置,因为角色以折线形式运动,所以会有一个先移动到的中间位置
private Vector3 endPos; // 移动的最后位置,角色或船最后移动到的位置
private int state; // 移动状态,0表示没有移动,1表示正在移动到中间位置,2表示正在从中间位置移动到最后位置
public int GetSpeed() {
return speed;
}
public void SetMiddlePos(Vector3 pos) {
middlePos = pos;
}
public Vector3 GetMiddlePos() {
return middlePos;
}
public void SetEndPos(Vector3 pos) {
endPos = pos;
}
public Vector3 GetEndPos() {
return endPos;
}
public void SetState(int state) {
this.state = state;
}
public int GetState() {
return state;
}
}
}
对应的控制类也要创建,所以首先创建BoatController 、ShoreController 、RoleController 、MoveController 这四个控制类,和模型部分以及视图部分相对应,由于游戏对象需要点击才能移动,所以也创建一个ClickController 类,处理点击事件,整个游戏可以创建一个主控制类MainController ,其中包含所有具体的游戏角色对应的控制器,比如船控制器、左岸控制器、右岸控制器、以及所有角色的6个控制器,最后创建一个单例对象类SingleObject ,里面有唯一一个主控制类,用来使其它类能获取主控制类的唯一实例从而向主控制类传递信息,完成相应逻辑:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace PriestsAndDevils {
/* 河岸岸边,左岸终点岸为-1,右岸出发岸为1 */
enum ShoreSide {
Left = -1, Right = 1
};
/* 移动状态,0表示没有移动,1表示正在移动到中间位置,2表示正在从中间位置移动到最后位置 */
enum MoveState {
Not_Moving = 0, Moving_To_Middle = 1, Moving_To_End = 2
};
/* 角色类型,0为牧师,1为魔鬼 */
enum RoleType {
NoRole = -1, Priest = 0, Devil = 1
};
/* 游戏状态,0为正在进行,1为游戏失败,2为游戏成功 */
enum GameState {
Playing = 0, Lose = 1, Win = 2
};
/* 移动控制器,一般会挂载到某个具体的游戏对象上 */
public class MoveController : MonoBehaviour {
private MoveModel moveModel;
private MoveView moveView;
void Start() {
moveModel = new MoveModel();
moveView = gameObject.AddComponent<MoveView>() as MoveView;
}
void Update() {
int state = moveModel.GetState();
Vector3 middlePos = moveModel.GetMiddlePos();
Vector3 endPos = moveModel.GetEndPos();
int speed = moveModel.GetSpeed();
// 根据速度、中间位置、终点位置、移动状态来移动物体
Move(state, middlePos, endPos, speed);
}
/* 初始化控制器,设置物体不移动 */
public void InitMoveController() {
moveModel.SetState((int)MoveState.Not_Moving);
}
/* 根据速度、中间位置、终点位置、移动状态来移动物体 */
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:
// 移动物体到中间位置,移动到后,设置物体的下一个状态为移动到终点
moveView.MoveTo(middlePos, speed);
if (transform.position == middlePos) {
moveModel.SetState((int)MoveState.Moving_To_End);
}
break;
case (int)MoveState.Moving_To_End:
// 移动物体到终点位置,移动到后,设置物体的下一个状态为不移动
moveView.MoveTo(endPos, speed);
if (transform.position == endPos) {
moveModel.SetState((int)MoveState.Not_Moving);
}
break;
}
}
/* 设置物体要移动到的位置 */
public void SetMovePos(Vector3 pos) {
// 设置物体开始往中间位置移动
moveModel.SetState((int)MoveState.Moving_To_Middle);
// 设置最终移动位置为pos
moveModel.SetEndPos(pos);
// 如果要移动到的位置的y坐标等于物体所在位置的y坐标,说明是船在移动
if (pos.y == transform.position.y) {
// 船沿直线运动,所以中间位置也可设为最终位置
moveModel.SetMiddlePos(pos);
// 移动状态可以直接设为往终点移动
moveModel.SetState((int)MoveState.Moving_To_End);
}
// 如果要移动到的位置的y坐标小于物体所在位置的y坐标,说明是物体从岸上移动到船上
else if (pos.y < transform.position.y) {
moveModel.SetMiddlePos(new Vector3(pos.x, transform.position.y, pos.z));
}
// 如果要移动到的位置的y坐标小于物体所在位置的y坐标,说明是物体从船上移动到岸上
else {
moveModel.SetMiddlePos(new Vector3(transform.position.x, pos.y, pos.z));
}
}
}
/* 点击控制器,一般会挂载在某个游戏对象上 */
public class ClickController : MonoBehaviour {
RoleController clickRole; // 如果点击的是角色,那么记录点击的对象的控制器
public void SetClickRole(RoleController role) {
clickRole = role;
}
void OnMouseDown() {
// 如果鼠标点击的对象是船,那么移动船只
if (gameObject.name == "Boat") {
SingleObject.getInstance().GetMainController().MoveBoat();
} else {
// 如果鼠标点击的对象是角色,那么移动对象
SingleObject.getInstance().GetMainController().MoveRole(clickRole);
}
}
}
public class BoatController {
// 船在左岸时装载角色的位置
private static Vector3 [] leftLoadPos = new Vector3 [] {new Vector3(-3, -0.5F, 0), new Vector3(-2, -0.5F, 0)};
// 船在右岸时装载角色的位置
private static Vector3 [] rightLoadPos = new Vector3 [] {new Vector3(2, -0.5F, 0), new Vector3(3, -0.5F, 0)};
private BoatModel boatModel; // 船模型
private BoatView boatView; // 船视图
private MoveController moveController; // 移动控制器
public BoatController() {
// 船开始在右岸
boatModel = new BoatModel((int)ShoreSide.Right);
boatView = new BoatView();
// 添加移动控制器
moveController = boatView.AddMoveScript();
// 添加点击控制器
boatView.AddClickScript();
}
/* 初始化船控制器 */
public void InitBoatController() {
// 先初始化移动控制器
moveController.InitMoveController();
// 获取船在哪边
int side = boatModel.GetSide();
// 在左边的话,船会回到右边去
if (side == (int)ShoreSide.Left) {
MoveToOtherSide();
}
// 初始化船模型没有乘客
boatModel.SetRoleOnBoat(new string [2]{"", ""});
}
// 获取船所在的岸边
public int GetBoatSide() {
return boatModel.GetSide();
}
// 获取船的游戏对象
public GameObject GetBoat() {
return boatView.GetGameObj();
}
/* 将船移动到岸的另一侧 */
public void MoveToOtherSide() {
// 先获取船在哪边
int side = boatModel.GetSide();
// 移动船到另一边
if (side == (int)ShoreSide.Left) {
moveController.SetMovePos(new Vector3(2.5F, -1, 0));
boatModel.SetSide((int)ShoreSide.Right);
} else {
moveController.SetMovePos(new Vector3(-2.5F, -1, 0));
boatModel.SetSide((int)ShoreSide.Left);
}
}
/* 获取船上空闲的位置 */
public int GetFreeIndex() {
string [] roleOnBoat = boatModel.GetRoleOnBoat();
// 按照顺序获取船上空闲的位置
if (roleOnBoat[0] == "") {
return 0;
} else if (roleOnBoat[1] == "") {
return 1;
} else {
// 如果没有空闲位置返回-1
return -1;
}
}
/* 判断船上是否没有角色 */
public bool IsNoRole() {
string [] roleOnBoat = boatModel.GetRoleOnBoat();
if (roleOnBoat[0] != "" || roleOnBoat[1] != "") {
return false;
} else {
return true;
}
}
/* 根据船靠岸的方向获取对应方向里船上空闲位置 */
public Vector3 GetFreePosition() {
string [] roleOnBoat = boatModel.GetRoleOnBoat();
int freeIndex = GetFreeIndex();
// 如果没有空闲位置,直接返回
if (freeIndex < 0) {
return new Vector3(-1, -1, -1);
}
int side = boatModel.GetSide();
if (side == (int)ShoreSide.Left) {
return leftLoadPos[freeIndex];
} else {
return rightLoadPos[freeIndex];
}
}
/* 将角色放到船上 */
public void PutRoleOnBoat(string roleName) {
// 获取船上空闲位置
int freeIndex = GetFreeIndex();
// 如果没有空闲位置,直接返回
if (freeIndex < 0) {
return;
}
// 利用角色名字将角色放入船
string [] roleOnBoat = boatModel.GetRoleOnBoat();
roleOnBoat[freeIndex] = roleName;
}
/* 将角色离开船上 */
public void PutRoleOffBoat(string roleName) {
string [] roleOnBoat = boatModel.GetRoleOnBoat();
// 如果船的相应位置有角色名字,将其置为空
for (int i = 0; i < roleOnBoat.Length; i++) {
if (roleOnBoat[i] == roleName) {
roleOnBoat [i] = "";
break;
}
}
}
/* 获取船上的各个角色的数目 */
public int[] GetRoleCountOnBoat() {
int [] count = {0, 0};
string [] roleOnBoat = boatModel.GetRoleOnBoat();
for (int i = 0; i < roleOnBoat.Length; i++) {
string roleName = roleOnBoat[i];
if (roleName == "") continue;
if (roleName.Remove(roleName.Length - 1, 1) == "Priest") {
count[0]++;
} else {
count[1]++;
}
}
return count;
}
}
/* 岸控制器 */
public class ShoreController {
private ShoreModel shoreModel; // 岸模型
private ShoreView shoreView; // 岸视图
// 右岸上可以放角色的位置,左岸的位置只需将坐标的x数值乘-1即可
private static Vector3 [] positions = new Vector3[] {new Vector3(4.5F, 0.25F, 0), new Vector3(5.5F, 0.25F, 0), new Vector3(6.5F, 0.25F, 0),
new Vector3(7.5F, 0.25F, 0), new Vector3(8.5F, 0.25F, 0), new Vector3(9.5F, 0.25F, 0)};
public ShoreController(int side, string sideName) {
shoreModel = new ShoreModel(side);
shoreView = new ShoreView(side, sideName);
}
public void InitShoreController() {
shoreModel.SetRoleOnShore(new string [6]{"", "", "", "", "", ""});
}
/* 获取岸边 */
public int GetShoreSide() {
return shoreModel.GetSide();
}
/* 获取岸上空闲的位置 */
public int GetFreeIndex() {
string [] roleOnShore = shoreModel.GetRoleOnShore();
for (int i = 0; i < roleOnShore.Length; i++) {
if (roleOnShore[i] == "") {
return i;
}
}
// 如果没有空闲位置返回-1
return -1;
}
/* 根据船靠岸的方向获取对应方向里岸上空闲位置 */
public Vector3 GetFreePosition() {
int freeIndex = GetFreeIndex();
// 如果没有空闲位置,直接返回
if (freeIndex < 0) {
return new Vector3(-1, -1, -1);
}
Vector3 pos = positions[freeIndex];
// 坐标的x数值乘1是右边岸上的位置,乘-1即可得到左边岸上的位置
pos.x *= shoreModel.GetSide();
return pos;
}
/* 将角色放到岸上 */
public void PutRoleOnShore(string roleName) {
// 获取岸上空闲位置
int freeIndex = GetFreeIndex();
// 如果没有空闲位置,直接返回
if (freeIndex < 0) {
return;
}
// 利用角色名字将角色放上岸
string [] roleOnShore = shoreModel.GetRoleOnShore();
roleOnShore[freeIndex] = roleName;
}
/* 将角色离开岸上 */
public void PutRoleOffShore(string roleName) { // 0->priest, 1->devil
string [] roleOnShore = shoreModel.GetRoleOnShore();
// 如果岸的相应位置有角色名字,将其置为空
for (int i = 0; i < roleOnShore.Length; i++) {
if (roleOnShore[i] == roleName) {
roleOnShore [i] = "";
break;
}
}
}
/* 获取岸上的各个角色的数目 */
public int [] GetRoleCountOnShore() {
int [] count = {0, 0};
string [] roleOnShore = shoreModel.GetRoleOnShore();
for (int i = 0; i < roleOnShore.Length; i++) {
string roleName = roleOnShore[i];
if (roleName == "") continue;
if (roleName.Remove(roleName.Length - 1, 1) == "Priest") {
count[0]++;
} else {
count[1]++;
}
}
return count;
}
}
/* 角色控制器 */
public class RoleController {
private RoleModel roleModel; // 角色模型
private RoleView roleView; // 角色视图
private MoveController moveController; // 移动控制器
private ClickController clickController; // 点击控制器
ShoreController shoreController; // 角色所在相应岸上的岸控制器
public RoleController(int roleType, string roleName, int number) {
roleModel = new RoleModel(roleType);
roleView = new RoleView(roleName, number);
// 添加移动控制器
moveController = roleView.AddMoveScript();
// 添加点击控制器,并记录点击对象的控制器
clickController = roleView.AddClickScript();
clickController.SetClickRole(this);
}
public void InitRoleController() {
// 初始化移动控制器
moveController.InitMoveController();
// 获取主控制器中的右岸控制器
shoreController = (SingleObject.getInstance().GetMainController() as MainController).GetRightShore();
// 将角色放到右岸上
PutRoleOnShore(shoreController);
SetRolePos(shoreController.GetFreePosition());
// 右岸控制器中关于角色的信息也被初始化
shoreController.PutRoleOnShore(this.GetRoleViewName());
}
public ShoreController GetShoreController() {
return shoreController;
}
/* 设置角色游戏对象位置 */
public void SetRolePos(Vector3 pos) {
roleView.SetPos(pos);
}
/* 将角色移动到指定位置 */
public void MoveToPosition(Vector3 endPosination) {
moveController.SetMovePos(endPosination);
}
/* 获取角色类型 */
public int GetRoleModelType() {
return roleModel.GetRoleType();
}
/* 获取角色游戏对象名字 */
public string GetRoleViewName() {
return roleView.GetName();
}
/* 获取游戏对象是否在船上 */
public bool IsOnBoat() {
return roleModel.GetIsOnBoat();
}
/* 将角色放到船上 */
public void PutRoleOnBoat(BoatController boatController) {
// 设置角色不在岸上,所以也没有岸控制器
shoreController = null;
// 设置角色在船上
roleModel.SetIsOnBoat(true);
// 设置角色游戏对象的父对象是船只
roleView.SetRoleParentTrans(boatController.GetBoat().transform);
}
/* 将角色放到岸上 */
public void PutRoleOnShore(ShoreController shoreController) {
// 设置角色在相应岸上的岸控制器
this.shoreController = shoreController;
// 设置角色不在船上
roleModel.SetIsOnBoat(false);
// 设置角色游戏对象的父对象为没有
roleView.SetRoleParentTrans(null);
}
}
/* 主控制器 */
public class MainController : MonoBehaviour {
private BoatController boat; // 船控制器
private ShoreController leftShore; // 左岸控制器
private ShoreController rightShore; // 右岸控制器
private RoleController [] roles; // 所有角色的控制器
private RiverView riverView; // 河流视图
private FunctionView functionView; // 功能视图,包括提示框,游戏信息等
private int gameState = (int)GameState.Playing; // 游戏状态,0表示游戏正在进行,1表示游戏失败,2表示游戏成功
void Awake() {
// 设置单例对象中只有唯一一个主控制器
SingleObject instance = SingleObject.getInstance();
instance.SetMainController(this);
// 展现游戏视图
ShowView();
}
/* 通过创建控制器的方式初始化游戏视图 */
public void ShowView() {
boat = new BoatController();
leftShore = new ShoreController((int)ShoreSide.Left, "LeftShore");
rightShore = new ShoreController((int)ShoreSide.Right, "RightShore");
roles = new RoleController[6];
CreateRolesController();
riverView = new RiverView();
functionView = gameObject.AddComponent<FunctionView>() as FunctionView;
}
/* 为每个角色创建控制器并初始化视图 */
private void CreateRolesController() {
for (int i = 0; i < 3; i++) {
roles[i] = new RoleController(0, "Priest", i + 1);
roles[i].SetRolePos(rightShore.GetFreePosition());
roles[i].PutRoleOnShore(rightShore);
rightShore.PutRoleOnShore(roles[i].GetRoleViewName());
}
for (int i = 0; i < 3; i++) {
roles[i + 3] = new RoleController(1, "Devil", i + 1);
roles[i + 3].SetRolePos(rightShore.GetFreePosition());
roles[i + 3].PutRoleOnShore(rightShore);
rightShore.PutRoleOnShore(roles[i + 3].GetRoleViewName());
}
}
/* 通过初始化控制器和视图的方式初始化游戏 */
public void InitGame() {
boat.InitBoatController();
leftShore.InitShoreController();
rightShore.InitShoreController();
for (int i = 0; i < roles.Length; i++) {
roles[i].InitRoleController();
}
functionView.InitFunctionView();
gameState = (int)GameState.Playing;
}
public ShoreController GetRightShore() {
return rightShore;
}
/* 根据不同的游戏状态返回不同的提示框内容 */
public string StateToTip(int gameState) {
switch (gameState) {
case (int)GameState.Playing:
return "Click and Play the Game";
case (int)GameState.Lose:
return "You lose! Click \"Reset\" to play again!";
case (int)GameState.Win:
return "You win! Click \"Reset\" to play again!";
default:
return "";
}
}
/* 通过船控制器来移动船只 */
public void MoveBoat() {
// 如果游戏状态不是正在进行,那么不移动
if (gameState != (int)GameState.Playing) {
return;
}
// 如果船上没有角色,不能开船
if (boat.IsNoRole()) {
return;
} else {
// 否则直接将船开到另一边
boat.MoveToOtherSide();
}
// 检查游戏状态
gameState = CheckGameState();
// 显示相应提示
functionView.SetTipContent(StateToTip(gameState));
}
/* 通过角色控制器移动角色 */
public void MoveRole(RoleController role) {
// 如果游戏状态不是正在进行,那么不移动
if (gameState != (int)GameState.Playing) {
return;
}
// 如果角色在船上,那么要将角色放上相应岸边
if (role.IsOnBoat()) {
// 获取船所在的岸边
ShoreController boatShore;
if (boat.GetBoatSide() == (int)ShoreSide.Left) {
boatShore = leftShore;
} else {
boatShore = rightShore;
}
/* 设置船和岸以及角色控制器以将角色放到岸上 */
role.MoveToPosition(boatShore.GetFreePosition());
boat.PutRoleOffBoat(role.GetRoleViewName());
role.PutRoleOnShore(boatShore);
boatShore.PutRoleOnShore(role.GetRoleViewName());
} else {
// 否则角色在岸上,要将角色放到船上,首先获取角色所在岸边的控制器
ShoreController boatShore = role.GetShoreController();
// 如果船上没有位置,或者船和物体所在的岸不是一边,直接返回
if (boat.GetFreeIndex() == -1 || boatShore.GetShoreSide() != boat.GetBoatSide()) {
return;
}
/* 设置船和岸以及角色控制器以将角色放到船上 */
role.MoveToPosition(boat.GetFreePosition());
boat.PutRoleOnBoat(role.GetRoleViewName());
role.PutRoleOnBoat(boat);
boatShore.PutRoleOffShore(role.GetRoleViewName());
}
// 检查游戏状态
gameState = CheckGameState();
// 显示相应提示
functionView.SetTipContent(StateToTip(gameState));
}
/* 检查游戏状态 */
public int CheckGameState() {
// 初始化左边和右边的牧师和魔鬼数量都为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) {
return (int)GameState.Win;
} else if (leftPriest < leftDevil && leftPriest > 0) {
// 如果任意一边牧师的数量小于魔鬼的数量且有牧师,那么游戏失败
return (int)GameState.Lose;
} else if (rightPriest < rightDevil && rightPriest > 0) {
return (int)GameState.Lose;
} else {
// 否则游戏正在进行中
return (int)GameState.Playing;
}
}
}
/* 单例对象,里面有唯一一个主控制类 */
public class SingleObject {
private static SingleObject instance = new SingleObject();
private MainController mainController;
public static SingleObject getInstance() {
return instance;
}
public void SetMainController(MainController controller) {
mainController = controller;
}
public MainController GetMainController() {
return mainController;
}
}
}
最后在主文件中,调用主控制器,进行游戏,就实现了一个基本的MVC模式:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace PriestsAndDevils {
public class Main : MonoBehaviour {
void Start() {
// 创建主控制器
MainController mainController = gameObject.AddComponent<MainController>() as MainController;
}
}
}
总结: 所以在实现MVC模式时,可以先将最后的效果图画出来,创建相应的视图类,由视图类进行分析,设计相应的模型类和控制器类,基本没有逻辑的可以不创建模型,直接在主控制类中实现相应视图或逻辑控制,最后实现MVC模式的开发。
游戏截图:
正在进行游戏:
游戏失败:
游戏成功:
|