Unity游戏设计 牧师与魔鬼

MVC游戏架构

  • MVC的全名是Model View Controller,是模型(Model)-视图(view)-控制器(controller)的缩写,是一种设计模式。它是用一种业务逻辑、数据与界面显示分离的方法来组织代码,将众多的业务逻辑聚集到一个部件里面,在需要改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑,达到减少编码的时间,提高代码复用性。
  • 使用的MVC的目的:它将这些对象、显示、控制分离以提高软件的的灵活性和复用性,MVC结构可以使程序具有对象化的特征,也更容易维护。
    MVC 模式中三个组件的详细介绍如下:
  • 模型(Model):用于封装与应用程序业务逻辑相关的数据以及对数据的处理方法。Model 有对数据直接访问的权力,例如对数据库的访问。Model 不依赖 View 和 Controller,也就是说, Model 不关心它会被如何显示或是如何被操作。但是 Model 中数据的变化一般会通过一种刷新机制被公布。为了实现这种机制,那些用于监视此 Model 的 View 必须事先在此 Model 上注册,由此,View 可以了解在数据 Model 上发生的改变。(如,软件设计模式中的“观察者模式”);
  • 视图(View):能够实现数据有目的的显示(理论上,这不是必需的)。在 View 中一般没有程序上的逻辑。为了实现 View 上的刷新功能,View 需要访问它监视的数据模型(即 Model),因此应该事先在被它监视的数据那里注册;
  • 控制器(Controller):起到不同层面间的组织作用,用于控制应用程序的流程。它处理事件并作出响应。“事件”包括用户的行为和数据 Model 上的改变。

完整代码见:github
演示视频 bilibili

一、游戏资源预制

游戏中的角色在脚本中使用场景控制器 Load’Resources 方法加载,因此先将各个游戏角色的模型设计好并放在Resources文件夹中。

使用不同大小比例的长方体代表游戏中的不同角色;
紫色正方体代表牧师,绿色长方体代表河岸,蓝色的长方体代表水流,黄色扁形长方体代表船。
红色小球代表恶魔。

二、导演类监控游戏状态

继承Object类实现Director,其他类通过获取Direcor类中的静态对象来实现控制。

 public class Director : System.Object { private static Director _instance;public SceneController currentSceneController { get; set; }public static Director getInstance() {if (_instance == null) {_instance = new Director ();}return _instance;}}

三、游戏对象运动的处理 —— Moveable类

游戏中存在游戏角色从河岸上船和从船上到河岸以及船在两个河岸来回运动的三个运动过程,因此需要引入一个变量记录运动方式 -> moving_status (int),当该变量的值为0时,不做运动;值为1时,以向量 middle 为运动终点;值为2时,以向量 dest 为运动终点。

 int moving_status;  Vector3 dest;Vector3 middle;

由于该类继承自 MonoBehaviour ,物体的运动就可以在Update()中使用 transform.position 来移动物体。

 void Update() {if (moving_status == 1) {transform.position = Vector3.MoveTowards (transform.position, middle, move_speed * Time.deltaTime);if (transform.position == middle) {moving_status = 2;}} else if (moving_status == 2) {transform.position = Vector3.MoveTowards (transform.position, dest, move_speed * Time.deltaTime);if (transform.position == dest) {moving_status = 0;}}}

不同的角色都是用Moveable 类来管理运动,类中的两个向量值需要不断做更改,为了保证类成员变量的安全性,通过函数setDestination()来实现更改向量变量值。

 public void setDestination(Vector3 _dest) {dest = _dest;middle = _dest;if (_dest.y == transform.position.y) {   // boat movingmoving_status = 2;}else if (_dest.y < transform.position.y) { // character from coast to boatmiddle.y = transform.position.y;} else {                                // character from boat to coastmiddle.x = transform.position.x;}moving_status = 1;}

reset()重置运动状态

 public void reset() {moving_status = 0;}

四、控制器 —— Control

  1. 场景控制器 —— loadResources()
    声明接口 loadResources(),在不同的角色类中实现该接口从而在不同类中加载不同资源。
 public interface SceneController {void loadResources ();}
  1. 角色控制 —— MyCharacterController
    游戏中的角色包括 牧师魔鬼 ,要实现对与这两种游戏角色的控制,首先需要获取对应的GameObject ,然后通过鼠标点击响应,改变 GameObject 的运动状态,即改变上面提到的 Moveable 类的属性,从而让Moveable 类实现角色的运动。
    游戏角色的运动可以划分为在船上和不在船上两种状态,这里使用布尔变量 _isOnBoat 记录角色是否在船上。
 readonly GameObject character;readonly Moveable moveableScript;readonly ClickGUI clickGUI;readonly int characterType;   // 0->priest, 1->devilbool _isOnBoat;CoastController coastController;

构造函数,通过传入的字符串(牧师还是魔鬼)加载对应的游戏资源

public MyCharacterController(string which_character) {if (which_character == "priest") {character = Object.Instantiate (Resources.Load ("Perfabs/Priest", typeof(GameObject)), Vector3.zero, Quaternion.identity, null) as GameObject;characterType = 0;} else {character = Object.Instantiate (Resources.Load ("Perfabs/Devil", typeof(GameObject)), Vector3.zero, Quaternion.identity, null) as GameObject;characterType = 1;}moveableScript = character.AddComponent (typeof(Moveable)) as Moveable;clickGUI = character.AddComponent (typeof(ClickGUI)) as ClickGUI;clickGUI.setController (this);
}

一些属性的设置和读取

public void setName(string name) {character.name = name;
}public void setPosition(Vector3 pos) {character.transform.position = pos;
}public void moveToPosition(Vector3 destination) {moveableScript.setDestination(destination);
}public int getType() { // 0->priest, 1->devilreturn characterType;
}public string getName() {return character.name;
}public void getOnBoat(BoatController boatCtrl) {coastController = null;character.transform.parent = boatCtrl.getGameobj().transform;_isOnBoat = true;
}public void getOnCoast(CoastController coastCtrl) {coastController = coastCtrl;character.transform.parent = null;_isOnBoat = false;
}public bool isOnBoat() {return _isOnBoat;
}public CoastController getCoastController() {return coastController;
}public void reset() {moveableScript.reset ();coastController = (Director.getInstance ().currentSceneController as FirstController).fromCoast;getOnCoast (coastController);setPosition (coastController.getEmptyPosition ());coastController.getOnCoast (this);
}
  1. 河岸控制 —— CoastController
    河岸控制类需要控制两个河岸,设置两个向量作为两个河岸的初始化位置,另外添加一个变量记录某一个河岸对象是两个河岸中的哪一个(to or from ?)
readonly GameObject coast;
readonly Vector3 from_pos = new Vector3(9,1,0);
readonly Vector3 to_pos = new Vector3(-9,1,0);
readonly Vector3[] positions;
readonly int to_or_from;    // to->-1, from->1
MyCharacterController[] passengerPlaner;

构造函数通过传入string字符串判断是两个河岸中的哪一个,同时加载对应资源。

public CoastController(string _to_or_from) {positions = new Vector3[] {new Vector3(6.5F,2.25F,0), new Vector3(7.5F,2.25F,0), new Vector3(8.5F,2.25F,0), new Vector3(9.5F,2.25F,0), new Vector3(10.5F,2.25F,0), new Vector3(11.5F,2.25F,0)};passengerPlaner = new MyCharacterController[6];if (_to_or_from == "from") {coast = Object.Instantiate (Resources.Load ("Perfabs/Stone", typeof(GameObject)), from_pos, Quaternion.identity, null) as GameObject;coast.name = "from";to_or_from = 1;} else {coast = Object.Instantiate (Resources.Load ("Perfabs/Stone", typeof(GameObject)), to_pos, Quaternion.identity, null) as GameObject;coast.name = "to";to_or_from = -1;}
}

为了实现游戏角色上下船的流畅性,每次从船上岸时需要获取目标河岸的空位,角色进入空位中。

public Vector3 getEmptyPosition() {Vector3 pos = positions [getEmptyIndex ()];pos.x *= to_or_from;return pos;
}public void getOnCoast(MyCharacterController characterCtrl) {int index = getEmptyIndex ();passengerPlaner [index] = characterCtrl;
}

角色从岸上上船时,返回上船的对象,在河岸对象中删除对应的对象。

public MyCharacterController getOffCoast(string passenger_name) {    for (int i = 0; i < passengerPlaner.Length; i++) {if (passengerPlaner [i] != null && passengerPlaner [i].getName () == passenger_name) {MyCharacterController charactorCtrl = passengerPlaner [i];passengerPlaner [i] = null;return charactorCtrl;}}return null;
}
  1. 船控制 —— BoatController
 public class BoatController {readonly GameObject boat;readonly Moveable moveableScript;readonly Vector3 fromPosition = new Vector3 (5, 1, 0);readonly Vector3 toPosition = new Vector3 (-5, 1, 0);readonly Vector3[] from_positions;readonly Vector3[] to_positions;int to_or_from; MyCharacterController[] passenger = new MyCharacterController[2];public BoatController() {to_or_from = 1;from_positions = new Vector3[] { new Vector3 (4.5F, 1.5F, 0), new Vector3 (5.5F, 1.5F, 0) };to_positions = new Vector3[] { new Vector3 (-5.5F, 1.5F, 0), new Vector3 (-4.5F, 1.5F, 0) };boat = Object.Instantiate (Resources.Load ("Perfabs/Boat", typeof(GameObject)), fromPosition, Quaternion.identity, null) as GameObject;boat.name = "boat";moveableScript = boat.AddComponent (typeof(Moveable)) as Moveable;boat.AddComponent (typeof(ClickGUI));}public void Move() {if (to_or_from == -1) {moveableScript.setDestination(fromPosition);to_or_from = 1;} else {moveableScript.setDestination(toPosition);to_or_from = -1;}}public int getEmptyIndex() {for (int i = 0; i < passenger.Length; i++) {if (passenger [i] == null) {return i;}}return -1;}public bool isEmpty() {for (int i = 0; i < passenger.Length; i++) {if (passenger [i] != null) {return false;}}return true;}public Vector3 getEmptyPosition() {Vector3 pos;int emptyIndex = getEmptyIndex ();if (to_or_from == -1) {pos = to_positions[emptyIndex];} else {pos = from_positions[emptyIndex];}return pos;}public void GetOnBoat(MyCharacterController characterCtrl) {int index = getEmptyIndex ();passenger [index] = characterCtrl;}public MyCharacterController GetOffBoat(string passenger_name) {for (int i = 0; i < passenger.Length; i++) {if (passenger [i] != null && passenger [i].getName () == passenger_name) {MyCharacterController charactorCtrl = passenger [i];passenger [i] = null;return charactorCtrl;}}return null;}public GameObject getGameobj() {return boat;}public int get_to_or_from() { return to_or_from;}public int[] getCharacterNum() {int[] count = {0, 0};for (int i = 0; i < passenger.Length; i++) {if (passenger [i] == null)continue;if (passenger [i].getType () == 0) {   // 0->priest, 1->devilcount[0]++;} else {count[1]++;}}return count;}public void reset() {moveableScript.reset ();if (to_or_from == -1) {Move ();}passenger = new MyCharacterController[2];}}

五、GUI

  1. UserGUI
    通过游戏状态来进行相应的GUI渲染,以标签来显示结果。
public class UserGUI : MonoBehaviour {private UserAction action;public int status = 0;GUIStyle style;GUIStyle buttonStyle;void Start() {action = Director.getInstance ().currentSceneController as UserAction;style = new GUIStyle();style.fontSize = 40;style.alignment = TextAnchor.MiddleCenter;buttonStyle = new GUIStyle("button");buttonStyle.fontSize = 30;}void OnGUI() {if (status == 1) {GUI.Label(new Rect(Screen.width/2-50, Screen.height/2-85, 100, 50), "Gameover!", style);if (GUI.Button(new Rect(Screen.width/2-70, Screen.height/2, 140, 70), "Restart", buttonStyle)) {status = 0;action.restart ();}} else if(status == 2) {GUI.Label(new Rect(Screen.width/2-50, Screen.height/2-85, 100, 50), "You win!", style);if (GUI.Button(new Rect(Screen.width/2-70, Screen.height/2, 140, 70), "Restart", buttonStyle)) {status = 0;action.restart ();}}}
}
  1. ClickGUI
    该类主要对于鼠标点击的不同对象做出不同响应
public class ClickGUI : MonoBehaviour {UserAction action;MyCharacterController characterController;public void setController(MyCharacterController characterCtrl) {characterController = characterCtrl;}void Start() {action = Director.getInstance ().currentSceneController as UserAction;}void OnMouseDown() {if (gameObject.name == "boat") {action.moveBoat ();} else {action.characterIsClicked (characterController);}}
}

六、场景加载效果


点击不同角色,做出响应动作。

点击船时如果船上有角色船会运动到对岸

运动到对岸后再点击角色,角色会上岸

七、游戏结果测试


Unity 游戏 牧师与魔鬼相关推荐

  1. unity 实现游戏——牧师与魔鬼

    unity 实现游戏--牧师与魔鬼 一.游戏介绍 Priests and Devils Priests and Devils is a puzzle game in which you will he ...

  2. unity实现牧师与魔鬼问题回答

    unity实现牧师与魔鬼&问题回答 简答题 游戏对象运动的本质是什么? 游戏运动本质就是使用矩阵变换(平移.旋转.缩放)改变游戏对象的空间属性. 请用三种方法以上方法,实现物体的抛物线运动.( ...

  3. unity实现牧师与魔鬼2.0(动作分离版) 基本操作演练

    unity实现牧师与魔鬼2.0(动作分离版)& 基本操作演练 & 材料与渲染联系 基本操作演练 下载 Fantasy Skybox FREE, 构建自己的游戏场景 在Window-&g ...

  4. Unity实战——牧师与魔鬼

    Unity实战--牧师与魔鬼 项目源码 最终效果 牧师与魔鬼游戏效果 背景描述 牧师与魔鬼是一款益智游戏,您将帮助牧师与魔鬼在规定时间内过河.河边有三个牧师和三个魔鬼.他们都想去这条河的对岸,但只有一 ...

  5. 基于Unity3D开发的3D小游戏牧师与魔鬼

    3D小游戏牧师与魔鬼 作业要求 编程实践,3D小游戏:牧师与魔鬼 列出游戏中提及的事物(Objects) 用表格列出玩家动作表(规则表),注意,动作越少越好 请将游戏中对象做成预制,并在 GenGam ...

  6. Unity实现牧师与魔鬼动作分离版

    牧师与魔鬼动作分离版 项目地址 动作管理器的设计 程序设计框架: 为了用一组简单的动作组合成复杂的动作,我们采用 cocos2d 的方案,建立与 CCAtion 类似的类. 通过门面模式(控制器模式) ...

  7. Unity牧师与魔鬼小游戏(动作分离版)

    Unity牧师与魔鬼小游戏(动作分离版) 前言 这是中大计算机学院3D游戏编程课的一次作业,在这里分享一下设计思路. 主要代码上传到了gitee上,请按照后文的操作运行. 项目地址:https://g ...

  8. Unity使用MVC架构制作牧师与魔鬼小游戏

    Unity使用MVC架构制作牧师与魔鬼小游戏 MVC架构简介 MVC概述 MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller) ...

  9. Unity牧师与魔鬼小游戏

    Unity牧师与魔鬼小游戏 前言 这是中大计算机学院3D游戏编程课的一次作业,在这里分享一下设计思路. 主要代码上传到了gitee上,请按照后文的操作运行. 项目地址:https://gitee.co ...

最新文章

  1. mysql 创建库 5.7_MySQL数据库之MySQL5.7创建用户时报错
  2. jsp注册里密码强弱怎么弄_jsp+servlet实战酷炫博客+聊天系统
  3. 计算机程序无法运行,win7电脑程序打不开解决方法
  4. 湖南大学第十四届ACM程序设计新生杯(重现赛)L-The Digits String (矩阵快速幂)
  5. ASP.NET---- Microsoft .NET Pet Shop 3.x(-)
  6. 湖南工商大学计算机网络原理,李小龙(湖南工商大学计算机与信息工程学院副院长)_百度百科...
  7. java td背景色_jQuery:无法更改表格单元格的背景颜色
  8. linux7.4 root密码,[RHEL 7.4] 忘记root密码,普通用户又没有sudo权限,怎么办?
  9. JQUERY 使用键盘左右键切换选项卡
  10. Item 27 避免使用ICloneable接口
  11. 让计算机桌面更加美丽课件,让计算机桌面更加美丽_1.doc
  12. 西门子界面官方精美触摸屏+WINCC程序模板 西门子官方触摸屏程序模板,炫酷的扁平式动画效果
  13. 请求接口时常见的数据请求类型
  14. MATLAB一元微积分实验
  15. 《Web安全之深度学习实战》笔记:第三章 循环神经网络
  16. osu计算机科学硕士,OSU的CSE「俄亥俄州立大学计算机科学与工程系」
  17. seo优化与html,HTML SEO 优化技巧
  18. Django - installing mysqlclient error: mysqlclient 1.4.0 or newer is required; you have 0.9.3
  19. Python微信远程控制摄像头-拍摄女朋友坐电脑前聊天时表情
  20. kali 2022.2 安装GVM

热门文章

  1. CSDN发生严重用户账号泄密事件
  2. [英语,iOS]美式英语语音语调基础
  3. mysql 之general_log日志
  4. WB蛋白质印迹法(Western blot)
  5. 粘贴板管理工具ditto的使用
  6. 每个女孩心中都有一个宋思明(少儿不宜) - 读《蜗居》有感
  7. 将日志文件从EC2实例自动备份到S3
  8. 蓝桥杯--世纪末的星期
  9. CIO40知识星球:IT中年男减肥20斤
  10. #include后用库路径与相对路径的区别