游戏介绍:
与上一作业牧师与恶魔mvc版相同。

演示视频:
整体效果与上一作业相同,不再另外演示。详见作业4演示视频

具体介绍:
一、动作分离架构
相较于上一作业的mvc架构将动作与对象绑定,并尽数交由scenecontroller管理,这一架构将controller层另外分出一动作层,由actionmanager管理,而actionmanager又受scenecontroller调用。同时,所有动作类由ssaction特化,而ssaction又继承自非组件的scriptableobject,使得动作与对象解耦。由此,action与上下两层独立开来,获得了更好的可复用性。

二、代码框架
与上一作业相同,firstcontroller依旧与SSDirector等类有关联,此处不再重复绘制。
1698584998079.png

三、具体实现
SSAction类:

public class SSAction : ScriptableObject {

    public bool enable = true;
    public bool destory = false;

    public GameObject gameobject { get; set; }
    public Transform transform { get; set; }

    protected SSAction () {}

    // Use this for initialization
    public virtual void Start () {
        throw new System.NotImplementedException ();
    }
    
    // Update is called once per frame
    public virtual void Update () {
        throw new System.NotImplementedException ();
    }    
}

enable和destory用于标记动作状态,重点在于gameobject和transform成员,消除了原先的控制反转。

CCMoveToAction类:

public class CCMoveToAction : SSAction
{
    public Vector3 target;
    public float speed;

    public static CCMoveToAction GetSSAction(Vector3 target, float speed){
        CCMoveToAction action = ScriptableObject.CreateInstance<CCMoveToAction> ();
        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) {
            //waiting for destroy
            this.destory = true;  
        }
    }

    public override void Start () {
    }
}

getssaction返回一个ccmovetoaction实例,update执行动作

SSActionManager类:

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> ();

    // Update is called once per frame
    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.destory) { 
                waitingDelete.Add(ac.GetInstanceID()); // release action
            } else if (ac.enable) { 
                ac.Update (); // update action
            }
        }

        foreach (int key in waitingDelete) {
            SSAction ac = actions[key]; 
            actions.Remove(key); 
            Object.Destroy(ac);
        }
        waitingDelete.Clear ();
    }

    public void RunAction(GameObject gameobject, SSAction action) {
        action.gameobject = gameobject;
        action.transform = gameobject.transform;
        waitingAdd.Add (action);
        action.Start ();
    }


    // Use this for initialization
    protected void Start () {
    }
}

waitingAdd,actions和waitingDelete分别为存储待执行、正在执行和待销毁动作的列表。Update函数维护这三个列表并调用actions中动作的update函数。RunAction被外部调用以向waitingAdd列表添加动作。

CCActionManager类:

public class CCActionManager : SSActionManager {
    
    private FirstController sceneController;

    private CCMoveToAction moveToShip, moveToBank, moveShip;
    protected new void Start() {
        sceneController = (FirstController)SSDirector.getInstance ().currentSceneController;
        sceneController.actionManager = this;
    }

    // Update is called once per frame
    protected new void Update ()
    {
        base.Update ();
    }

    public void setMoveShip(GameObject gameobject, int boatstate){
        Vector3 vector;
        if(boatstate == 2)
            vector = new Vector3(4f, 0, 0);
        else
            vector = new Vector3(-4f, 0, 0);
        moveShip = CCMoveToAction.GetSSAction(vector, 10);
        this.RunAction(gameobject,moveShip);
    }
    public void setMoveToShip(GameObject gameobject,int seat,int boatstate){
        Vector3 vector;
        if(boatstate == 1)
            vector = new Vector3(-4f + (seat==1?1:-1), 0.5f, 0);
        else
            vector = new Vector3(4f + (seat==1?1:-1), 0.5f, 0);
        moveToShip = CCMoveToAction.GetSSAction(vector, 10);
        Debug.Log("movetoship,target:"+vector);
        this.RunAction(gameobject,moveToShip);
    }


    public void setMoveToBank(GameObject gameobject, int boatstate, int number){
        Vector3 vector;
        if(boatstate == 1)
            vector = new Vector3(-6.5f+(number>2?-1:0),1f,-1f+number%3);
        else
            vector = new Vector3(6.5f+(number>2?1:0),1f,-1f+number%3);
        moveToBank = CCMoveToAction.GetSSAction(vector,10);
        Debug.Log("movetobank,target:"+vector);
        this.RunAction(gameobject,moveToBank);
    }
}

sceneController保存当前场景控制器对象,moveToShip等为三个moveto动作。Start为初始化函数,三个set函数分别创建新的moveto动作对象并执行。

Judger类:

public class Judger : ScriptableObject
{
    private FirstController sceneController;
    public int[] leftbank;
    public int[] rightbank;
    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        
    }

    public void Initialize(){
        sceneController = (FirstController)SSDirector.getInstance ().currentSceneController;
        leftbank = new int[6]{1,1,1,-1,-1,-1};
        rightbank = new int[6]{0,0,0,0,0,0};
    }
    public void Check_if_lose(){
        if ((leftbank.Sum() < 0  && leftbank.Take(3).Sum() > 0)|| (rightbank.Sum() < 0 && rightbank.Take(3).Sum() > 0)){
            sceneController.winflag = false;
            sceneController.GameOver();
        }
    }

    public void Check_if_win(){
        sceneController.winflag = false;
        for(int i = 0;i<6;i++){
            if(rightbank[i] == 0)
                return;
        }
        sceneController.winflag = true;
        sceneController.GameOver();
    }
    public void UpdateBank(){
        for(int i = 0;i<3;i++){
            leftbank[i] = 0;
            leftbank[i+3] = 0;
            rightbank[i] = 0;
            rightbank[i+3] = 0;
            if(sceneController.chastate[i] == 1)
                leftbank[i] = 1;
            else if(sceneController.chastate[i] == 2)
                rightbank[i] = 1;
            if(sceneController.chastate[i+3] == 1)
                leftbank[i+3] = -1;
            else if(sceneController.chastate[i+3] == 2)
                rightbank[i+3] = -1;
        }
    }
}

将胜负判断逻辑独立于FirstController。

FirstController类基本与作业4一致,仅将对动作和对象的直接操作变为调用actionManager中函数,以及将胜负判断逻辑分离至Judger,故不再重复展示。


礼貌的羽毛球
1 声望0 粉丝