Priests and Devils
Priests and Devils is a puzzle game in which you will help the Priests and Devils to cross the river within the time limit. There are 3 priests and 3 devils at one side of the river. They all want to get to the other side of this river, but there is only one boat and this boat can only carry two persons each time. And there must be one person steering the boat from one side to the other side. In the flash game,you can click on them to move them and click the go button to move the devils on either side of the river, they get killed and the game is over. You can try it in many > ways. Keep all priests alive! Good luck!
简单说明一下就是:
在河的一岸有3个牧师和3个魔鬼,他们需要借助船渡到河的对岸,船最多同时承载2个游戏角色。
你的任务是:让所有游戏角色都渡到河的对岸,游戏胜利。
需要注意:当一侧岸上的魔鬼数量大于牧师数量时,魔鬼就会吃掉这个岸上的牧师,游戏失败。
游戏中提及的事物:魔鬼,牧师,船,两岸。
我们在设计该游戏时使用MVC架构(模型、界面、控制器)。
MVC是界面人机交互程序设计的一种架构模式。它把程序分为三个部分:
模型(Model):数据对象及关系,游戏对象、空间关系,在游戏中,一切实体都可以被视为是模型,这种实体可以是具体的,也可以是抽象的。
控制器(Controller):接受用户事件,控制模型的变化,一个场景一个主控制器,至少实现与玩家交互的接口(IPlayerAction,实现或管理运动
界面(View):显示模型,将人机交互事件交给控制器处理,处收 Input 事件,渲染 GUI ,接收事件。
我们将刚才提及的游戏中的事物或者说游戏对象都分为模型Model,他们受到Controller控制器的控制进行游戏行为,具体的模型类有:Boat(船)、Land(河岸/陆地)、Move(处理游戏对象的移动)、Position(处理游戏对象的初始坐标)、Role(调整游戏对象方向方便移动);
控制器类需要接受用户事件并控制模型的变化,比如Boat模型就会有BoatController,BoatController会控制一切以船为对象的行为,比如:处理船被点击时的事件、往船上添加一名乘客,往船上减少一名乘客。必须要注意的是,直接控制模型的控制器之间是没有耦合关系的,也就是说,BoatController只能知道当前船上有多少名乘客,但是不知道他们都是谁(这个信息应当由各RoleController保存),还有,因为移动船要同时移动船上的所有乘客,但是BoatController不能直接移动乘客,因此实际上真正移动船的逻辑不能直接写在BoatController里(具体应该写在哪下文说)。Move模型就会有MoveController,MoveController控制了谁要移动,而且负责判断当前是否有模型正在移动。另外还有一类很重要的控制器就是场景控制器和导演。游戏就像是一场话剧,话剧会有多个场景,同时有一个导演贯穿了所有场景,导演控制器必须被写成单例模式,这就确保了各控制器属于同一场“话剧”。每一个场景都会有一个单独的场景控制器,但是在这个游戏里,只有唯一一个场景(FirstController)。场景控制器管理所有该场景内的模型控制器,并且实现他们的综合行为。就这个游戏而言,FirstController会生成并且管理:一个BoatController,两个LandController,六个RoleController,一个MoveController。所有该场景内的综合行为都会在这个场景控制器内实现。比如:移动船,涉及到船和乘客的同时移动;移动角色,涉及到离岸、登船、人状态的转变三方信息;判断当前游戏是否成功或者失败。最后,以I开头的控制器都是接口,用于规范同一类型的控制器应当具有的行为,比如IObjectContoller应当被所有模型的控制器继承、IScenceController应当被所有场景的控制器继承、IUserAction负责与视图方面沟通的接口。
界面类显示游戏结果和提供用户交互渠道,具体的界面类为UserGUI(用户交互界面)管理比如说:标题、重新开始的按钮、游戏成功或者失败时的提示。
项目文件结构如下:
其中Resources为游戏对象的预制和材质,里面有四个游戏对象的预制及其材质
Scenes为游戏所用的场景,由于我们在该游戏中并没有切换场景,所以只需要使用默认场景即可
Scripts是代码部分也是我们设计中最重要的部分,我们按照MVC架构组织代码结构
Boat类:
public class Boat
{public GameObject boat;//船对象public Boat(Vector3 initPos){boat = GameObject.Instantiate(Resources.Load("Prefabs/boat", typeof(GameObject))) as ansform.position = initPos;boat.AddComponent<Click>();}}
Click类:
public class Click : MonoBehaviour
{IObjectController clickAction;public void setClickAction(IObjectController clickAction) {this.clickAction = clickAction;}void OnMouseDown() {clickAction.DealClick();}
}
Land类:
public class Land
{public GameObject land;public Land(Vector3 initPos){land = GameObject.Instantiate(Resources.Load("Prefabs/land", typeof(GameObject))) as ansform.position = initPos;}
}
Move类:
public class Move : MonoBehaviour
{public bool isMoving;public float speed = 5;public Vector3 destination;void Update(){if (transform.localPosition == destination) {isMoving = false;return;}isMoving = true;transform.localPosition = Vector3.MoveTowards(transform.localPosition, destination, speed * Time.deltaTime);}
}
Position类:
public class Position
{public static Vector3 boatLeftPos = new Vector3(-3.5f, -1, 12);public static Vector3 boatRightPos = new Vector3(3.5f, -1, 12);public static Vector3[] roleLeftPos = new Vector3[6]{new Vector3(-11, 0, 12), new Vector3(-10, 0, 12),new Vector3(-9, 0, 12),new Vector3(-8, 0, 12),new Vector3(-7, 0, 12),new Vector3(-6, 0, 12)};public static Vector3[] roleRightPos = new Vector3[6]{new Vector3(6, 0, 12), new Vector3(7, 0, 12),new Vector3(8, 0, 12),new Vector3(9, 0, 12),new Vector3(10, 0, 12),new Vector3(11, 0, 12)};public static Vector3[] landInitPos = new Vector3[2]{new Vector3(-8, -1, 12), new Vector3(8, -1, 12)};public static Vector3[] seatLeftPos = new Vector3[3]{new Vector3(-4.5f, 0, 12), new Vector3(-3.5f, 0, 12), new Vector3(-2.5f, 0, 12)};public static Vector3[] seatRightPos = new Vector3[3]{new Vector3(2.5f, 0, 12), new Vector3(3.5f, 0, 12), new Vector3(4.5f, 0, 12)};
}
Role类:
public class Role
{public GameObject role;public Role(int roleType, Vector3 initPos){string path = "Prefabs/" + ((roleType == FirstController.PRIEST) ? "priest" : "devil");role = GameObject.Instantiate(Resources.Load(path, typeof(GameObject))) as ansform.position = initPos;role.AddComponent<Click>();}
}
UserGUI类:
public class UserGUI : MonoBehaviour
{IUserAction userAction;GUIStyle msgStyle, titleStyle;void Start(){userAction = SSDirector.GetInstance().CurrentSceneController as IUserAction;msgStyle = new GUIStyle();Color = Color.white;msgStyle.alignment = TextAnchor.MiddleCenter;msgStyle.fontSize = 30;titleStyle = new GUIStyle();Color = Color.white;titleStyle.alignment = TextAnchor.MiddleCenter;titleStyle.fontSize = 60;}void OnGUI() {// 重新开始的按钮if(GUI.Button(new Rect(Screen.width*0.4f, Screen.height*0.65f, Screen.width*0.2f, Screen.height*0.1f), "Restart")){userAction.Restart();}// 检查是否正确GUI.Label(new Rect(0, 0, Screen.width, Screen.height*0.2f), "Preists and Devils", titleStyle);if(userAction.GetGameState() == FirstController.WIN){GUI.Label(new Rect(0, Screen.height*0.8f, Screen.width, Screen.height*0.2f), "You Win.", msgStyle);} else if(userAction.GetGameState() == FirstController.FAILED){GUI.Label(new Rect(0, Screen.height*0.8f, Screen.width, Screen.height*0.2f), "You failed.", msgStyle);}}
}
BoatController类:
public class BoatController : IObjectController
{public bool onLeftside;IUserAction userAction;public int[] seat;public Boat boatModel;public BoatController(){userAction = SSDirector.GetInstance().CurrentSceneController as IUserAction;seat = new int[3];Reset();}public void Reset(){onLeftside = true;for(int i = 0; i < 3; i++){seat[i] = -1;}}public int embark(int roleID){for(int i = 0; i < 3; i++){if(seat[i] == -1){seat[i] = roleID;return i;}}return -1;}public int getEmptySeat(){for(int i = 0; i < 3; i++){if(seat[i] == -1){return i;}}return -1;}public void disembark(int roleID){for(int i = 0; i < 3; i++){if(seat[i] == roleID){seat[i] = -1;return;}}}public void CreateModel(){boatModel = new Boat(Position.boatLeftPos);boatModel.boat.GetComponent<Click>().setClickAction(this);}public void DealClick(){userAction.MoveBoat();}public GameObject GetModelGameObject(){return boatModel.boat;}}
FirstController类:
public class FirstController : MonoBehaviour, ISceneController, IUserAction
{public static int LEFTLAND = 0;public static int RIGHTLAND = 1;public static int BOAT = 2;public static int PRIEST = 0;public static int DEVIL = 1;public static int PLAYING = 0;public static int WIN = 1;public static int FAILED = 2;BoatController BoatCtrl;RoleController[] RoleCtrl = new RoleController[6];LandController[] LandCtrl = new LandController[2];MoveController MoveCtrl;int[] rolesID = new int[6]{0,1,2,3,4,5};int gameState;void Awake(){SSDirector director = SSDirector.GetInstance();director.CurrentSceneController = this;director.CurrentSceneController.Initialize();}public void Initialize(){//如果有,则释放原有的GameObjectfor(int i = 0; i < 6; i++){if(RoleCtrl[i] != null){Destroy(RoleCtrl[i].GetModelGameObject());}}for(int i = 0; i < 2; i++){if(LandCtrl[i] != null){Destroy(LandCtrl[i].GetModelGameObject());}}if(BoatCtrl != null){Destroy(BoatCtrl.GetModelGameObject());}// 加载控制器和模型BoatCtrl = new BoatController();BoatCtrl.CreateModel();for(int i = 0; i < 6; i++){int roleType = (i < 3) ? PRIEST : DEVIL;RoleCtrl[i] = new RoleController(roleType, rolesID[i]);RoleCtrl[i].CreateModel();}LandCtrl[0] = new LandController(LEFTLAND, rolesID);LandCtrl[1] = new LandController(RIGHTLAND, rolesID);LandCtrl[0].CreateModel();LandCtrl[1].CreateModel();MoveCtrl = new MoveController();//开始游戏gameState = PLAYING;}//将角色的ID转换成数组的下标int IDToNumber(int ID){for(int i = 0; i < 6; i++){if(rolesID[i] == ID){return i;}}return -1;}//点击船时执行public void MoveBoat(){if(gameState != PLAYING || MoveCtrl.IsMoving()) return;CheckAndSetGameState();Leftside){MoveCtrl.SetMove(BoatCtrl.GetModelGameObject(), Position.boatRightPos);for(int i = 0; i < 3; i++){if(BoatCtrl.seat[i] != -1){RoleController r = RoleCtrl[IDToNumber(BoatCtrl.seat[i])];MoveCtrl.SetMove(r.GetModelGameObject(), Position.seatRightPos[i]);}}}else{MoveCtrl.SetMove(BoatCtrl.GetModelGameObject(), Position.boatLeftPos);for(int i = 0; i < 3; i++){if(BoatCtrl.seat[i] != -1){RoleController r = RoleCtrl[IDToNumber(BoatCtrl.seat[i])];MoveCtrl.SetMove(r.GetModelGameObject(), Position.seatLeftPos[i]);}} }Leftside = !Leftside;}//点击角色时执行public void MoveRole(int id){int num = IDToNumber(id);if(gameState != PLAYING || MoveCtrl.IsMoving()) return;int seat;switch(RoleCtrl[num].roleState){case 0: // LEFTLANDif(!Leftside) return;LandCtrl[0].LeaveLand(id);seat = bark(id);RoleCtrl[num].GoTo(BOAT);if(seat == -1) return;MoveCtrl.SetMove(RoleCtrl[num].GetModelGameObject(), Position.seatLeftPos[seat]);break;case 1: // Leftside) return;LandCtrl[1].LeaveLand(id);seat = bark(id);RoleCtrl[num].GoTo(BOAT);if(seat == -1) return;MoveCtrl.SetMove(RoleCtrl[num].GetModelGameObject(), Position.seatRightPos[seat]);break;case 2: //Leftside){seat = LandCtrl[0].getEmptySeat();BoatCtrl.disembark(id);LandCtrl[0].GoOnLand(id);RoleCtrl[num].GoTo(LEFTLAND);MoveCtrl.SetMove(RoleCtrl[num].GetModelGameObject(), leLeftPos[seat]);}else{seat = LandCtrl[1].getEmptySeat();BoatCtrl.disembark(id);LandCtrl[1].GoOnLand(id);RoleCtrl[num].GoTo(RIGHTLAND);MoveCtrl.SetMove(RoleCtrl[num].GetModelGameObject(), leRightPos[seat]);}break;default: break;}}//判断游戏状态public void CheckAndSetGameState(){if(gameState != PLAYING) return;//判断是否失败int[,] rolePos = new int[2, 3]{{0, 0, 0}, {0, 0, 0}};foreach(RoleController r in RoleCtrl){leType, r.roleState]++;}if((rolePos[0,0]>0 && rolePos[0,0]<rolePos[1,0]) || (rolePos[0,1]>0 && rolePos[0,1]<rolePos[1,1]) || (rolePos[0,2]>0 && rolePos[0,2] < rolePos[1,2])){gameState = FAILED;return;} //判断是否成功foreach(RoleController r in RoleCtrl){leType == 0 && r.roleState != RIGHTLAND){return;}}gameState = WIN;return;}//Reset按钮执行的功能public void Restart(){Initialize();gameState = PLAYING;}//获取游戏当前状态public int GetGameState(){return gameState;}
}
IObjectController类:
public interface IObjectController
{void DealClick();void CreateModel();void Reset();GameObject GetModelGameObject();
}
ISceneController类:
public interface ISceneController
{void Initialize();
}
IUserAction类:
public interface IUserAction {void MoveBoat();void MoveRole(int id);int GetGameState();void Restart();
}
LandController类:
public class LandController: IObjectController
{public int side;public int[] seat;IUserAction userAction;Land landModel;public LandController(int side, int[] rolesID){userAction = SSDirector.GetInstance().CurrentSceneController as IUserAction;this.side = side;this.seat = new int[6]{-1,-1,-1,-1,-1,-1};if(this.side == FirstController.LEFTLAND){for(int i = 0; i < 6; i++){this.seat[i] = rolesID[i];}}}public bool LeaveLand(int roleID){for(int i = 0; i < 6; i++){if(seat[i] == roleID){seat[i] = -1;return true;}}return false;}public bool GoOnLand(int roleID){for(int i = 0; i < 6; i++){if(seat[i] == -1){seat[i] = roleID;return true;}}return false;}public int getEmptySeat(){for(int i = 0; i < 6; i++){if(seat[i] == -1){return i;}}return -1;}public void CreateModel(){landModel = new Land(Position.landInitPos[side]);}public void Reset(){}public void DealClick(){}public GameObject GetModelGameObject(){return landModel.land;}
}
MoveController类:
public class MoveController
{GameObject moveObject;public bool IsMoving(){veObject != null && veObject.GetComponent<Move>().isMoving == true);}public void SetMove(GameObject moveObject, Vector3 destination) {// 设置一个新的移动Move veObject = moveObject;if (!moveObject.TryGetComponent<Move>(out test)) {moveObject.AddComponent<Move>();}veObject.GetComponent<Move>().destination = destination;}
}
RoleController类:
public class RoleController : IObjectController
{public int roleType;public int roleState;public int id;Role roleModel;IUserAction userAction;public RoleController(int roleType, int id){userAction = SSDirector.GetInstance().CurrentSceneController as leType = roleType;this.id = id;Reset();}public void Reset(){leState = FirstController.LEFTLAND;}public void GoTo(int pos){leState = pos;}public void CreateModel(){roleModel = new Role(roleType, leLeftPos[id]);le.GetComponent<Click>().setClickAction(this);}public void DealClick(){userAction.MoveRole(this.id);}public GameObject GetModelGameObject(){le;}
}
SSSirector类:
public class SSDirector : System.Object
{static SSDirector _instance;public ISceneController CurrentSceneController {get; set;}public static SSDirector GetInstance() {if (_instance == null) {_instance = new SSDirector();}return _instance;}
}
为了进一步说明代码是如何运作的,以下我就游戏行为“先点击一个牧师上船,再点击船移动,被判定游戏失败”为例介绍代码的工作流程。
游戏演示视频:unity 3d 牧师与魔鬼小游戏作业_哔哩哔哩bilibili
参考师兄的博客:Unity3D小游戏——牧师与魔鬼 - LoongChan - 博客园 (cnblogs)
写的很好,谢谢师兄!
本文发布于:2024-02-02 13:26:51,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170685161144104.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |