牧师与魔鬼-动作分离版
面向对象基于职责的思考:
场记(控制器)管的事太多,不仅要处理用户交互事件,还要游戏对象加载、游戏规则实现、运动实现等等,而显得非常臃肿。一个最直观的想法就是让更多的人(角色)来管理不同方面的工作。例如:用专用的对象来管理运动,专用的对象管理播放视频,专用的对象管理规则。就和踢足球一样,自己踢5人场,一个裁判就够了,如果是国际比赛,就需要主裁判、边裁判、电子裁判等角色通过消息协同来完成更为复杂的工作。
什么是动作管理器
动作管理器就是一个对象,管理整个场景中所有的动作。
一个SceneController(场景管理器)只配备一个动作管理器对象。
不管是游戏角色的移动还是船的移动,都归这个对象管;
动作管理器可以添加动作(添加的时候要指定动作所作用的GameObject),监测已经完成的动作并清除。
UML图实现
该图呈现了一个基本的编程框架,为了避免过多的动作影响对整体框架的理解,这篇博客只实现了一个SSMoveToAction动作。
动作管理类分析
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是所有动作的基类。SSActionManager通过这个接口来管理动作。
SSAction只是一个动作的抽象,具体如何实现动作要让它的子类来实现Update方法。
注意SSAction并不是MonoBehaviour的子类,它的Start和Update方法不会主动调用,我们会在后面一个MonoBehaviour类的Update中调用这个对象的Update方法。这个类还定义了一个ISSActionCallback的成员,用来保存动作完成时要通知的对象。
为什么要继承ScriptableObject呢?因为ScriptableObject有一些生命周期方法,等一下它的子类就要用到OnDestroy。
public class SSAction : ScriptableObject //动作
{
public bool enable = true; //是否正在进行此动作
public bool destroy = false; //是否需要被销毁
public GameObject gameobject; //动作对象
public Transform transform; //动作对象的transform
public ISSActionCallback callback; //回调函数
protected SSAction() {
} //防止用户自己 new 对象
public virtual void Start() //子类可以使用这两个函数
{
throw new System.NotImplementedException();
}
public virtual void Update()
{
throw new System.NotImplementedException();
}
}
SSMoveToAction
SSMoveToAction是SSAction的一个实现,它包含一个Vector3.MoveForward()的动作,用来实现船或角色的直线位移。
SSMoveToAction不能直接通过new来得到对象,只能通过它的静态方法GetSSAction()来新建实例。
当SSMoveToAction发现自己的动作完成的时候,它会将自己标识为“要被销毁”并告诉动作管理或动作组合这个动作已完成。
public class SSMoveToAction : SSAction //移动
{
public Vector3 target; //移动到的目的地
public float speed; //移动的速度