简单版牧师与魔鬼(动作分离版)

展示GIF(与之前版本的牧师与魔鬼运动一致)

 

 部署过程:

给摄像机添加RayCaster部件

 

船添加部件

 

 

给牧师与魔鬼添加部件

 

 

 然后就可以开始运行了!

 

 作业:基于下面的框架,结合第一次写的牧师与魔鬼。重构牧师与魔鬼

牧师与魔鬼 动作分离版

  • 【2019开始的新要求】:设计一个裁判类,当游戏达到结束条件时,通知场景控制器游戏结束

4.1 动作管理器的设计

为了用一组简单的动作组合成复杂的动作,我们采用 cocos2d 的方案,建立与 CCAtion 类似的类。先上设计图:

设计思路如下:

  • 通过门面模式(控制器模式)输出组合好的几个动作,共原来程序调用。
    • 好处,动作如何组合变成动作模块内部的事务
    • 这个门面就是 CCActionManager
  • 通过组合模式实现动作组合,按组合模式设计方法
    • 必须有一个抽象事物表示该类事物的共性,例如 SSAction,表示动作,不管是基本动作或是组合后动作
    • 基本动作,用户设计的基本动作类。 例如:CCMoveToAction
    • 组合动作,由(基本或组合)动作组合的类。例如:CCSequenceAction
  • 接口回调(函数回调)实现管理者与被管理者解耦
    • 如组合对象实现一个事件抽象接口(ISSCallback),作为监听器(listener)监听子动作的事件
    • 被组合对象使用监听器传递消息给管理者。至于管理者如何处理就是实现这个监听器的人说了算了
    • 例如:每个学生做完作业通过邮箱发消息给学委,学委是谁,如何处理,学生就不用操心了
  • 通过模板方法,让使用者减少对动作管理过程细节的要求
    • SSActionManager 作为 CCActionManager 基类

最终,程序员可以方便的定义动作并实现动作的自由组合,做到:

  • 程序更能适应需求变化
  • 对象更容易被 复用
  • 程序更易于维护

4.2 核心代码与设计解读

1、动作基类(SSAction)

直接给代码:

设计要点:

  • ScriptableObject 是不需要绑定 GameObject 对象的可编程基类。这些对象受 Unity 引擎场景管理
  • protected 防止用户自己 new 抽象的对象
  • 使用 virtual 申明虚方法,通过重写实现多态。这样继承者就明确使用 Start 和 Update 编程游戏对象行为
  • 利用接口(ISSACtionCallback)实现消息通知,避免与动作管理者直接依赖

2、简单动作实现

实现具体动作,将一个物体移动到目标位置,并通知任务完成:

设计要点:

  • 让 Unity 创建动作类,确保内存正确回收。别指望开发者是 c 语言高手。
  • 多态。C++ 语言必申明重写,Java则默认重写
  • 似曾相识的运动代码。动作完成,并发出事件通知,期望管理程序自动回收运行对象。

3、顺序动作组合类实现

实现一个动作组合序列,顺序播放动作:

 

设计要点:

  • 让动作组合继承抽象动作,能够被进一步组合;实现回调接受,能接收被组合动作的事件
  • 创建一个动作顺序执行序列,-1 表示无限循环,start 开始动作。
  • Update方法执行执行当前动作
  • SSActionEvent 收到当前动作执行完成,推下一个动作,如果完成一次循环,减次数。如完成,通知该动作的管理者
  • Start 执行动作前,为每个动作注入当前动作游戏对象,并将自己作为动作事件的接收者
  • OnDestory 如果自己被注销,应该释放自己管理的动作。

这是标准的组合设计模式。被组合的对象和组合对象属于同一种类型。通过组合模式,我们能实现几乎满足所有越位需要、非常复杂的动作管理。

4、动作事件接口定义

接口作为接收通知对象的抽象类型:

设计要点:

  • 事件类型定义,使用了 枚举变量
  • 定义了事件处理接口,所有事件管理者都必须实现这个接口,来实现事件调度。所以,组合事件需要实现它,事件管理器也必须实现它。
  • 这里展示了语言函数 默认参数 的写法。

5、动作管理基类 – SSActionManager

这是动作对象管理器的基类,实现了所有动作的基本管理


设计要点:

  • 创建 MonoBehaiviour 管理一个动作集合,动作做完自动回收动作。
    • 有一个动作字典。(字典是线程不安全的,有影响吗?)
    • 待加入、删除动作列表?
  • update 演示了由添加、删除等复杂集合对象的使用。
  • 提供了添加新动作的方法 RunAction。该方法把游戏对象与动作绑定,并绑定该动作事件的消息接收者。
  • 执行该动作的 Start 方法

4.3 使用动作组合

代码:

部署:

  • main 对象添加场景控制器脚本
  • main 对象添加运动控制器脚本,并将场景控制器拖入该对象控制器属性
  • 将游戏对象A和B拖入场景控制器属性 move1 和 move2
  • 运行

代码说明:

  • 初始化
    • 定义动作移动到 A 点
    • 将 对象1 移动到 A 点
    • 定义动作移动到 C 点,在移动到 D点序列
    • 将 对象2 执行移动序列
  • Update
    • Update 是方法覆盖,提醒编程人员重新该方法不会多态,且要用 base 调用原方法
  • 处理移动完成事件
    • 让 对象1 在 A 和 B 之间来回移动

 

 

 

 

******************************************************************** 个人思考作答 ******************************************************************** 

由于没有学系统分析的课程,所以UML图没有弄懂。

所以参考了网站https://blog.csdn.net/tfstone/article/details/81028752

 

GetInstanceID() 返回实例的ID,这在全局里是唯一的

GetInstance()返回一个类的实例,这个实例是唯一的。在游戏中,SSDirector导演类就使用了这个方法。

 

GameObject是不可以在类之间的函数来传递的,但是可以通过在生成GameObject的类赋值到SSDirector的变量中,

然后获取SSDdirctor的唯一实例来,使用生成GameObject的类,然后使用GameObject。

 

之前我没仔细看第三章的代码,吃了大亏。所以这次搞了好久。

 

 

搞清老师改的代码之后,就可以着手修改自己之前写的代码了

把之前分给船和人物部件控制的运动函数,交给ActionManager。

 

将船和人物的状态变量保留下来。如果触发了点击函数,就通知SSDirector。

SSDirector通过各种状态判断船和人物应该进行的动作,然后通知ActionManager进行相应的动作。

 

最后一步工作在于修改ActionManager,当动作结束的时候要修改船和人物的运动状态。

作用有:控制运状态:当人物在运动的时候,船不能动。当船动的时候,不能让人物动。

下面是修改了SSActionManager类中

 

 

关于其余代码的细节,请看我的上一个博客

https://www.cnblogs.com/woodx/p/13739684.html

改进代码,请看我的gitee

https://gitee.com/woodx9/unity-3D-homework/tree/master/PriestsAndDemons(SeparatedActionsVersion)

谢谢阅读

 

posted @   woodx  阅读(196)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
点击右上角即可分享
微信分享提示