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

主要的代码结构为:

动作分离主要是将动作通过门面模式交给动作控制管理器来管理,外界可以通过调用动作管理器中的函数来控制动作的发生,将管理和实现分离。

回调函数接口

这里采用接口来表示,每一个动作完成后,调用者会进行的操作,这一操作被放置在了回调函数里。

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)
public class SSAction : ScriptableObject {
    public bool enable = true;                      //是否可进行
    public bool destroy = false;                    //是否已完成
​
    public GameObject gameobject;                   //动作对象
    public Transform transform;                     //动作对象的transform
    public ISSActionCallback callback;              //回调函数
​
    /*防止用户自己new对象*/
    protected SSAction() { }                      
​
    public virtual void Start() {
        throw new System.NotImplementedException();
    }
​
    public virtual void Update() {
        throw new System.NotImplementedException();
    }
}

动作分为单个动作组合动作

单个动作

单个动作主要有两个操作,一个是对对象的初始化,另一个是动作完成的通知动作管理者或者动作组合。

具体代码如下:

//这里利用Unity自带的构造函数创建对象,并初始化
public static SSMoveToAction GetSSAction(Vector3 _target, float _speed) {
    SSMoveToAction action = ScriptableObject.CreateInstance<SSMoveToAction>();
    action.target = _target;
    action.speed = _speed;
    return action;
}
​
public override void Update() {
    this.transform.position = Vector3.MoveTowards(this.transform.position, target, speed * Time.deltaTime);
    //动作完成,通知动作管理者或动作组合
    if (this.transform.position == target) {
        this.destroy = true;
        this.callback.SSActionEvent(this);      
    }
}
组合动作

组合动作有三个,如下所示:

public List<SSAction> sequence;    //动作的列表
public int repeat = -1;            //-1就是无限循环
public int start = 0;              //当前做的动作的标号
​
//让序列中的每一个动作都执行
public override void Update() {
    if (sequence.Count == 0) return;
    if (start < sequence.Count) {
        sequence[start].Update();               //执行之后,通过回调函数让start值递增
    }
}
​
//回调函数
public void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted, int intParam = 0, string strParam = null, Object objectParam = null) {
    source.destroy = false;                     //由于可能还会再次调用,因此先不删除
    this.start++;                               
    if (this.start >= sequence.Count) {
        this.start = 0;
        if (repeat > 0) repeat--;               
        if (repeat == 0) {                      
            this.destroy = true;                //删除
            this.callback.SSActionEvent(this);  //通知管理者
        }
    }
}
动作管理器基类(SSActionManager)

该类可以自己实现对于动作的控制,并且可以提供接口给外部函数调用。

这里有两个队列,一个是等待添加队列,一个是等待删除的队列,因为每次update的过程中不可能立刻对新增动作和已执行动作进行处理,因此需要一个队列进行缓冲。

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>();                              //等待删除的key列表                
​
    protected 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);
            Object.Destroy(ac);//让Unity帮着删除
        }
        waitingDelete.Clear();
    }
​
    //外界只需要调用动作管理类的RunAction函数即可完成动作。
    public void RunAction(GameObject gameobject, SSAction action, ISSActionCallback manager) {
        action.gameobject = gameobject;
        action.transform = gameobject.transform;
        action.callback = manager;
        waitingAdd.Add(action);
        action.Start();
    }
}
动作管理器

这里对移动船和移动对象进行了封装,现在用户只需要提供对象,终点和速度即可。

public void moveBoat(GameObject boat, Vector3 end, float speed) {
    boatMove = SSMoveToAction.GetSSAction(end, speed);
    this.RunAction(boat, boatMove, this);
}
​
public void moveRole(GameObject role, Vector3 middle, Vector3 end, float speed) {
    //两段移动
    SSAction action1 = SSMoveToAction.GetSSAction(middle, speed);
    SSAction action2 = SSMoveToAction.GetSSAction(end, speed);
    //两个动作,都只重复一次
    roleMove = SequenceAction.GetSSAcition(1, 0, new List<SSAction> { action1, action2 });
    this.RunAction(role, roleMove, this);
}
GameCheck(游戏结束判断)

该类主要用于判断游戏是否结束。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using GhostBoatGame;
​
public class GameCheck : MonoBehaviour {
    public Controller sceneController;
​
    protected void Start() {
        sceneController = (Controller)SSDirector.GetInstance().CurrentScenceController;
    }
​
    public int GameJudge()
    {
        int src_priest = sceneController.src_land.GetTotal(0);
        int src_ghost = sceneController.src_land.GetTotal(1);
        int des_priest = sceneController.des_land.GetTotal(0);
        int des_ghost = sceneController.des_land.GetTotal(1);
​
        if (des_priest == 3)
        {    //全部到终点,获胜
            return 1;
        }
​
        if (sceneController.boat.GetBoatMark() == 1)//由于在这一边船还没开,因此只需检测另一边的数量即可。
        {
            if (des_priest < des_ghost && des_priest > 0)
            {//失败
                return -1;
            }
        }
        else
        {
            if (src_priest < src_ghost && src_priest > 0)
            {//失败
                return -1;
            }
        }
​
        return 0;//游戏继续进行
    }
}

从判断方程看出,只需要在终点牧师数量为3即可。

github链接

clement2048/priest_and_devil_dzfl (github.com)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值