牧师与魔鬼——动作分离版
牧师与魔鬼——动作分离版
在上周的作业中,牧师与魔鬼游戏中的各个事件,都是写在Director中,并且都是继承Monobehavior的。在这周动作分离的设计中,我将上船、下船以及船的移动都分离出来。参照老师给的设计模式,画出简略的UML图如下:
面向对象设计UML图
动作序列
在这里的设计中,参照之前师兄的设计模式,可以将动作序列分成如下几个:
文件名 | 功能 |
---|---|
CCActionManager | 具体动作作为类中的一个对象从而管理动作,同时继承SSActionManager |
CCBoatMoving | 船移动的具体方法,继承SSAction,将GenGameObject作为其中一个对象 |
CCGetOffBoat | 牧师或魔鬼对象下船的具体方法,继承SSAction,其中的对象有int型判断河岸,与GameObject型对象接收具体作用的游戏对象 |
CCGetOnTheBoat | 牧师或魔鬼对象上船的具体方法,继承SSAction,其中的对象有GameObject型接收具体作用的游戏对象 |
CCActionManager
CCActionManager是对具体游戏事件的控制,其中包含三个方法:Start(),Update(),和SSActionEvent()。Start()方法中用于将SSDirector实例化,Update()方法中用于实现具体的游戏事件,SSActionEvent()方法则是接口ISSActionCallback中的。
具体代码如下:
public class CCActionManager : SSActionManager, ISSActionCallback
{public GenGameObject sceneController;public CCGetOnTheBoat getonA;public CCGetOffBoat getoffB;public CCBoatMoving boatmovingC;// Use this for initializationprotected void Start(){sceneController = (GenGameObject)SSDirector.getInstance().currentScenceController;sceneController.actionManager = this;}// Update is called once per frameprotected new void Update(){if (Input.GetMouseButtonDown(0) && sceneController.game == 0){Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);RaycastHit hit;if (Physics.Raycast(ray, out hit)){if (hit.transform.tag == "Devil" || hit.transform.tag == "Priest"){if (hit.collider.gameObject == sceneController.boat[0] || hit.collider.gameObject == sceneController.boat[1]){if (hit.collider.gameObject == sceneController.boat[0]){getoffB = CCGetOffBoat.GetSSAction(0);this.RunAction(hit.collider.gameObject, getoffB, this);}else{getoffB = CCGetOffBoat.GetSSAction(1);this.RunAction(hit.collider.gameObject, getoffB, this);}}else{getonA = CCGetOnTheBoat.GetSSAction();this.RunAction(hit.collider.gameObject, getonA, this);}}else if (hit.transform.tag == "Boat" && sceneController.boatCapacity != 2){print(hit.transform.tag);boatmovingC = CCBoatMoving.GetSSAction();this.RunAction(hit.collider.gameObject, boatmovingC, this);}}}base.Update();}public void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted,int intParam = 0, string strParam = null, Object objectParam = null){//}
}
具体游戏事件实现方法
具体的事件类有三个,分别是,CCBoatMoving、CCGetOffBoat和CCGetOnTheBoat。以下是三个事件的代码:
CCBoatMoving的代码:
\\CCBoatMoving
public class CCBoatMoving : SSAction
{public GenGameObject sceneController;public static CCBoatMoving GetSSAction(){CCBoatMoving action = ScriptableObject.CreateInstance<CCBoatMoving>();return action;}// Use this for initializationpublic override void Start(){sceneController = (GenGameObject)SSDirector.getInstance().currentScenceController;}// Update is called once per framepublic override void Update(){if (sceneController.boat_position == 1){sceneController.boat_position = 0;while (this.transform.position != sceneController.boatStartPos)this.transform.position = Vector3.MoveTowards(this.transform.position, sceneController.boatStartPos, 1);}else if (sceneController.boat_position == 0){sceneController.boat_position = 1;while (this.transform.position != sceneController.boatEndPos)this.transform.position = Vector3.MoveTowards(this.transform.position, sceneController.boatEndPos, 1);}sceneController.check();this.destroy = true;this.callback.SSActionEvent(this);}
}
CCGetOffBoat的代码:
public class CCGetOffBoat : SSAction
{public int side;public GenGameObject sceneController;public static CCGetOffBoat GetSSAction(int side){CCGetOffBoat action = ScriptableObject.CreateInstance<CCGetOffBoat>();action.side = side;return action;}// Use this for initializationpublic override void Start(){sceneController = (GenGameObject)SSDirector.getInstance().currentScenceController;}// Update is called once per framepublic override void Update(){if (sceneController.boat[side] != null){sceneController.boat[side].transform.parent = null;if (sceneController.boat_position == 1){if (sceneController.boat[side].transform.tag == "Priest"){for (int i = 0; i < 3; i++){if (sceneController.priests_end[i] == null){sceneController.priests_end[i] = sceneController.boat[side];sceneController.boatCapacity++;break;}}}else if (sceneController.boat[side].transform.tag == "Devil"){for (int i = 0; i < 3; i++){if (sceneController.devils_end[i] == null){sceneController.devils_end[i] = sceneController.boat[side];sceneController.boatCapacity++;break;}}}}else if (sceneController.boat_position == 0){if (sceneController.boat[side].transform.tag == "Priest"){for (int i = 0; i < 3; i++){if (sceneController.priests_start[i] == null){sceneController.priests_start[i] = sceneController.boat[side];sceneController.boatCapacity++;break;}}}else if (sceneController.boat[side].transform.tag == "Devil"){for (int i = 0; i < 3; i++){if (sceneController.devils_start[i] == null){sceneController.devils_start[i] = sceneController.boat[side];sceneController.boatCapacity++;break;}}}}sceneController.boat[side] = null;}sceneController.check();this.destroy = true;this.callback.SSActionEvent(this);}
}
CCGetOnTheBoat的代码如下:
public class CCGetOnTheBoat : SSAction
{public GenGameObject sceneController;public static CCGetOnTheBoat GetSSAction(){CCGetOnTheBoat action = ScriptableObject.CreateInstance<CCGetOnTheBoat>();return action;}// Use this for initializationpublic override void Start(){sceneController = (GenGameObject)SSDirector.getInstance().currentScenceController;}// Update is called once per framepublic override void Update(){if (sceneController.boatCapacity != 0){if (sceneController.boat_position == 0){for (int i = 0; i < 3; i++){if (sceneController.devils_start[i] == gameobject){sceneController.devils_start[i] = null;sceneController.find = 1;}if (sceneController.priests_start[i] == gameobject){sceneController.priests_start[i] = null;sceneController.find = 1;}}}else if (sceneController.boat_position == 1){for (int i = 0; i < 3; i++){if (sceneController.devils_end[i] == gameobject){sceneController.devils_end[i] = null;sceneController.find = 1;}if (sceneController.priests_end[i] == gameobject){sceneController.priests_end[i] = null;sceneController.find = 1;}}}if (sceneController.find == 1)gameobject.transform.parent = sceneController.boat_obj.transform;if (sceneController.boat[0] == null && sceneController.find == 1){sceneController.boat[0] = gameobject;sceneController.boat[0].transform.tag = gameobject.transform.tag;sceneController.boatCapacity--;this.transform.localPosition = new Vector3(0, 1.2f, 0.19f);}else if (sceneController.boat[1] == null && sceneController.find == 1){sceneController.boat[1] = gameobject;sceneController.boat[1].transform.tag = gameobject.transform.tag;sceneController.boatCapacity--;this.transform.localPosition = new Vector3(0, 1.2f, -0.12f);}}sceneController.find = 0;this.destroy = true;this.callback.SSActionEvent(this);}
}
这三个具体的类全都继承SSAction类,也同时在Start()函数中实例化了SSDirector。在Update中则是各自完成各自操作的。
动作事件基本类型及回调
这一部分是定义在SSAction中的,其中SSActionEventType是一个枚举型,ISSActionCallback是一个接口,其中定义了函数SSActionEvent。具体代码如下:
public enum SSActionEventType : int { Started, Competeted }public interface ISSActionCallback
{void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted,int intParam = 0, string strParam = null, Object objectParam = null);
}
参考老师给出的SSAction,SSAction类的具体代码为:
public class SSAction : ScriptableObject
{public bool enable = true;public bool destroy = false;public GameObject gameobject { get; set; }public Transform transform { get; set; }public ISSActionCallback callback { get; set; }protected SSAction() { }public virtual void Start(){throw new System.NotImplementedException();}public virtual void Update(){throw new System.NotImplementedException();}
}
而在SSActionManager中,我绝大多数是按照老师课件上写的代码来的。我对SSActionManager的理解是,一个Action的队列,在队列中有等待处理的事件,以及处理完毕之后等待删除的事件。在其中的RunAction函数中,接收GameObject、SSAction的实例化和ISSActionCallback的回调接口,作用是将等待处理的游戏对象加入到队列中,用SSAction来处理事件。具体的代码如下:
public class SSActionManager : MonoBehaviour
{private Dictionary<int, SSAction> actions = new Dictionary<int, SSAction>();private List<SSAction> waitingAdd = new List<SSAction>();private List<int> waitingDelete = new List<int>();// Use this for initializationvoid Start(){}// Update is called once per frameprotected void Update(){foreach (SSAction ac in waitingAdd)actions[ac.GetInstanceID()] = ac;waitingAdd.Clear();foreach (KeyValuePair<int, SSAction> kv in actions){SSAction ac = kv.Value;if (ac.destroy){waitingDelete.Add(ac.GetInstanceID());}else if (ac.enable){ac.Update();}}foreach (int key in waitingDelete){SSAction ac = actions[key]; actions.Remove(key); DestroyObject(ac);}waitingDelete.Clear();}public void RunAction(GameObject gameobject, SSAction action, ISSActionCallback manager){action.gameobject = gameobject;action.transform = gameobject.transform;action.callback = manager;waitingAdd.Add(action);action.Start();}
}
加载资源、点击事件以及用户GUI
这几部分和之前作业全部相同,几乎没有改变,结合这星期学习的游戏场景,我加上了SkyBox。放上几张成品图:
当游戏成功时显示:
在本次作业中,主要是了解到了面向对象的编程方法。其实对于我本人来说,我对面向对象在刚开始学习的时候真的挺吃力的。各个部分太多,经常忘了各部分的分工和实现。这是我在学习碰上的主要问题。在往年师兄的代码和老师上课课件的参考下,我把需要的具体的动作序列类和动作管理类写在纸上,用UML图表示出其中关系的时候,才认识到面向对象编程的博大精深、真是太机智了,对代码的利用和复用达到了极大值。
这是程序的传送门
牧师与魔鬼——动作分离版相关推荐
- unity编程实践-牧师与魔鬼动作分离版
作业要求 牧师与魔鬼 动作分离版 [2019开始的新要求]:设计一个裁判类,当游戏达到结束条件时,通知场景控制器游戏结束 目标:建立动作管理器,使动作抽象出来,可以应用到任何游戏对象上,以此提高代码复 ...
- 【3D游戏编程与设计】四 游戏对象与图形基础 : 构建游戏场景+牧师与魔鬼 动作分离版
[3D游戏编程与设计]四 游戏对象与图形基础 : 构建游戏场景+牧师与魔鬼 动作分离版 基本操作演练 下载 Fantasy Skybox FREE, 构建自己的游戏场景 下载 Fantasy Skyb ...
- 牧师与魔鬼 动作分离版
1.基本操作演练 下载 Fantasy Skybox FREE 在unityAssetStore中下载Fantasy Skybox FREE 构建游戏场景: GameObject->3D Obj ...
- Unity实现牧师与魔鬼动作分离版
牧师与魔鬼动作分离版 项目地址 动作管理器的设计 程序设计框架: 为了用一组简单的动作组合成复杂的动作,我们采用 cocos2d 的方案,建立与 CCAtion 类似的类. 通过门面模式(控制器模式) ...
- 基于Unity开发的牧师与魔鬼动作分离版游戏设计
1 作业要求 牧师与魔鬼 动作分离版 设计一个裁判类,当游戏达到结束条件时,通知场景控制器游戏结束 2 实现细节 在原来代码的基础上,修改如下: 将UserGUI的sign成员变量和Controlle ...
- 牧师与魔鬼-动作分离版
源码传送门 视频展示传送门,展示效果与第三次作业相同 运行说明:将Controllor.cs挂载Main Camera上,然后点击运行即可 1. 动作分离 目的:将物体的动作与空间属性分开来,从而降低 ...
- 牧师与魔鬼动作分离版
本次游戏实现参照课件的框架,将动作管理与游戏场景分离. 完全按照课件的思路实现 动作基类SSAction 简单动作MoveToAction 组合动作SequenceAction 动作管理基类SSAct ...
- 用Unity3D实现简单的牧师与魔鬼游戏(动作分离版)
用Unity3D实现简单的牧师与魔鬼游戏(动作分离版) 项目地址 牧师与魔鬼游戏(动作分离版) 完成效果图 上次博客链接 牧师与魔鬼游戏 实现心得 这次作业是在上次作业的基础上完成的,具体做出的改变是 ...
- Unity3D游戏编程-牧师与恶魔 动作分离版
Unity3D游戏编程-牧师与恶魔 动作分离版 文章目录 Unity3D游戏编程-牧师与恶魔 动作分离版 作业要求 项目配置 项目演示 视频演示 项目下载 文字说明 项目截图 实现过程和方法(算法) ...
最新文章
- docker $PWD路径_深入浅出Docker 镜像
- PJ:细菌挥发性物质和光合信号激活低铁响应途径
- 转:软件设计漫谈之三:30分钟掌握面向对象类的设计原则
- 2020 mse 清华_ICSMSE 2020
- iOS UITableView
- 计算机网络传输层和应用层作业,计算机网络传输层作业.doc
- Win10电脑如何打开任务管理器界面
- C++ Aggregate 与 POD(Plain Old Data)的解释
- java如何操作视图
- 怎么删除远程桌面连接IP记录 删除连接信息
- 阿里P9技术:我来聊聊百万年薪
- Spring Data Elasticsearch 基本语法及使用
- 护眼灯频闪是什么意思?如何消除led灯频闪
- 天梯赛:L2-016 愿天下有情人都是失散多年的兄妹 (25 分)
- JAVA大数据需要学什么
- 【搜索】洛谷 P1460 健康的荷斯坦奶牛 Healthy Holsteins
- IQ 智力题 有答案
- CG-23H 超声波风速风向传感器--易风(加热型)
- python统计次数正则_Python提取信息必学基础——正则表达式
- CF489C Given Length and Sum of Digits