牧师与魔鬼——动作分离版


在上周的作业中,牧师与魔鬼游戏中的各个事件,都是写在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图表示出其中关系的时候,才认识到面向对象编程的博大精深、真是太机智了,对代码的利用和复用达到了极大值。
这是程序的传送门

牧师与魔鬼——动作分离版相关推荐

  1. unity编程实践-牧师与魔鬼动作分离版

    作业要求 牧师与魔鬼 动作分离版 [2019开始的新要求]:设计一个裁判类,当游戏达到结束条件时,通知场景控制器游戏结束 目标:建立动作管理器,使动作抽象出来,可以应用到任何游戏对象上,以此提高代码复 ...

  2. 【3D游戏编程与设计】四 游戏对象与图形基础 : 构建游戏场景+牧师与魔鬼 动作分离版

    [3D游戏编程与设计]四 游戏对象与图形基础 : 构建游戏场景+牧师与魔鬼 动作分离版 基本操作演练 下载 Fantasy Skybox FREE, 构建自己的游戏场景 下载 Fantasy Skyb ...

  3. 牧师与魔鬼 动作分离版

    1.基本操作演练 下载 Fantasy Skybox FREE 在unityAssetStore中下载Fantasy Skybox FREE 构建游戏场景: GameObject->3D Obj ...

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

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

  5. 基于Unity开发的牧师与魔鬼动作分离版游戏设计

    1 作业要求 牧师与魔鬼 动作分离版 设计一个裁判类,当游戏达到结束条件时,通知场景控制器游戏结束 2 实现细节 在原来代码的基础上,修改如下: 将UserGUI的sign成员变量和Controlle ...

  6. 牧师与魔鬼-动作分离版

    源码传送门 视频展示传送门,展示效果与第三次作业相同 运行说明:将Controllor.cs挂载Main Camera上,然后点击运行即可 1. 动作分离 目的:将物体的动作与空间属性分开来,从而降低 ...

  7. 牧师与魔鬼动作分离版

    本次游戏实现参照课件的框架,将动作管理与游戏场景分离. 完全按照课件的思路实现 动作基类SSAction 简单动作MoveToAction 组合动作SequenceAction 动作管理基类SSAct ...

  8. 用Unity3D实现简单的牧师与魔鬼游戏(动作分离版)

    用Unity3D实现简单的牧师与魔鬼游戏(动作分离版) 项目地址 牧师与魔鬼游戏(动作分离版) 完成效果图 上次博客链接 牧师与魔鬼游戏 实现心得 这次作业是在上次作业的基础上完成的,具体做出的改变是 ...

  9. Unity3D游戏编程-牧师与恶魔 动作分离版

    Unity3D游戏编程-牧师与恶魔 动作分离版 文章目录 Unity3D游戏编程-牧师与恶魔 动作分离版 作业要求 项目配置 项目演示 视频演示 项目下载 文字说明 项目截图 实现过程和方法(算法) ...

最新文章

  1. docker $PWD路径_深入浅出Docker 镜像
  2. PJ:细菌挥发性物质和光合信号激活低铁响应途径
  3. 转:软件设计漫谈之三:30分钟掌握面向对象类的设计原则
  4. 2020 mse 清华_ICSMSE 2020
  5. iOS UITableView
  6. 计算机网络传输层和应用层作业,计算机网络传输层作业.doc
  7. Win10电脑如何打开任务管理器界面
  8. C++ Aggregate 与 POD(Plain Old Data)的解释
  9. java如何操作视图
  10. 怎么删除远程桌面连接IP记录 删除连接信息
  11. 阿里P9技术:我来聊聊百万年薪
  12. Spring Data Elasticsearch 基本语法及使用
  13. 护眼灯频闪是什么意思?如何消除led灯频闪
  14. 天梯赛:L2-016 愿天下有情人都是失散多年的兄妹 (25 分)
  15. JAVA大数据需要学什么
  16. 【搜索】洛谷 P1460 健康的荷斯坦奶牛 Healthy Holsteins
  17. IQ 智力题 有答案
  18. CG-23H 超声波风速风向传感器--易风(加热型)
  19. python统计次数正则_Python提取信息必学基础——正则表达式
  20. CF489C Given Length and Sum of Digits

热门文章

  1. C#画K线实现画K线和截图保存
  2. 中国最实用的十大网站
  3. 没有群晖却要共享文件?试试HFS搭建精简版NAS吧
  4. 【学以致用】JavaScript
  5. 庄子 “唯至人乃能游于世不避,顺人而不失己。”
  6. 简单典型二阶系统_微波战术通信系统空域抗干扰方法综述
  7. MATLAB——Z变换与Z反变换
  8. 华为最新鸿蒙消息,飞象网项立刚:华为鸿蒙7年后全球第一!网友:oppo第一个反对!...
  9. “掌商工程”让海派盆景与白领互添绿意
  10. Async await的使用