遊戲對象與圖形基礎——作業與練習

下載 Fantasy Skybox FREE, 構建自己的遊戲場景

從Asset Store上下載的Skybox:

牧師與魔鬼 動作分離版

UML類圖

動作管理Actions類

動作基類 SSAction
要點

  1. ScriptableObject 是不需要綁定 GameObject 對象的可編程基類。這 些對象受 Unity 引擎場 景管理
  2. 防止用戶自己 new 對象
  3. 使用 virtual 申明虛方法,通過重寫實現多態。 這樣繼承者就明確使用 Start 和 Update 編程 遊戲對象行爲
  4. 利用接口實現消息通知, 避免與動作管理者直接 依賴。

    public bool enable = true;                      
    public bool destroy = false;                    

    public GameObject gameobject;                   
    public Transform transform;                  
    public ISSActionCallback callback;


    protected SSAction() { }                        

    public virtual void Start()                    
    {
        throw new System.NotImplementedException();
    }

    public virtual void Update()
    {
        throw new System.NotImplementedException();
    }

簡單動作實現 CCMoveToAction
CCMoveAction讓Untiy自己創建一個動作類,確保了內存的正確回收。此外,重寫了Update()和Start()函數。target和speed分別代表遊戲對象移動的目標和速度。

    public Vector3 target;        
    public float speed;           

    private SSMoveToAction() { }
    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 override void Start()
    {
        
    }

組合動作實現 SequenceAction

繼承了SSAction和ISSActionCallback類,實現的功能有:

  1. 雙頰一個動作順序的執行序列
  2. 執行當前動作
  3. 收到當前動作執行完成,推下一個動 作,如果完成一次循環,減次數。如完 成,通知該動作的管理者。
  4. 執行動作前爲動作注入相應的遊戲對象,並將自己作爲動作事件接收者。
  5. 當自己被註銷時釋放管理的動作。
    public List<SSAction> sequence;    
    public int repeat = -1;            
    public int start = 0;              

    public static SequenceAction GetSSAcition(int repeat, int start, List<SSAction> sequence)
    {
        SequenceAction action = ScriptableObject.CreateInstance<SequenceAction>();
        action.repeat = repeat;
        action.sequence = sequence;
        action.start = start;
        return action;
    }

    public override void Update()
    {
        if (sequence.Count == 0) return;
        if (start < sequence.Count)
        {
            sequence[start].Update();    
        }
    }

    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); 
            }
        }
    public override void Start()
    {
        foreach (SSAction action in sequence)
        {
            action.gameobject = this.gameobject;
            action.transform = this.transform;
            action.callback = this;                
            action.Start();
        }
    }

    void OnDestroy()
    {
        
    }

動作事件接口

使用枚舉變量定義,定義了事件的處理接口,所有事件管理者都必須實現這個接口。

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

動作管理基類 SSActionManager

  1. 創建 MonoBehaiviour 管理一個動作 集合,動作做完自動回收動作。
  2. 提供了運行一個新動作的方法。該方 法把遊戲對象與動作綁定,並綁定該動 作事件的消息接收者。
  3. 執行該動作的Start方法
   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);
            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();
    }

    public void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted,
        int intParam = 0, string strParam = null, Object objectParam = null)
    {
        
    }

實戰動作管理 MySceneActionManager

接收了場景控制的指令,管理動作的執行,它創建了四個CCMoveToAction,兩個有管理器管理,另外兩個組成一個順序執行組合。

    protected new void Start()
    {
        sceneController = (FirstControllor)SSDirector.GetInstance().CurrentSceneController;
        sceneController.actionManager = this;
    }
    public void moveBoat(GameObject boat, Vector3 target, float speed)
    {
        moveBoatToEndOrStart = SSMoveToAction.GetSSAction(target, speed);
        this.RunAction(boat, moveBoatToEndOrStart, this);
    }

    public void moveRole(GameObject role, Vector3 middle_pos, Vector3 end_pos, float speed)
    {
        SSAction action1 = SSMoveToAction.GetSSAction(middle_pos, speed);
        SSAction action2 = SSMoveToAction.GetSSAction(end_pos, speed);
        moveRoleToLandorBoat = SequenceAction.GetSSAcition(1, 0, new List<SSAction> { action1, action2 });
        this.RunAction(role, moveRoleToLandorBoat, this);
    }

其他代碼也要相應地做出一些改動,例如,在V1的各個Controller中的控制物體的函數全部改爲由actions中的一個ActionManager來實現,船和人物只需傳遞target和speed等參數給actionmanager就行了,實現了動作的分離。

//moveBoat
actionManager.moveBoat(boat.getGameObject(), boat.BoatMoveToPosition(), boat.move_speed);

//moveRole
 Vector3 end_pos = land.GetEmptyPosition();
                Vector3 middle_pos = new Vector3(role.getGameObject().transform.position.x, end_pos.y, end_pos.z);
actionManager.moveRole(role.getGameObject(), middle_pos, end_pos, role.move_speed);

裁判類 Judge
當遊戲達到結束條件時,通知場景控制器遊戲結束
通過MoveBoat()和MoveRole()函數過程中UserGUI.status的數值來判斷是否達到了結束的條件

    private IUserAction userAction;

    void Start()
    {
        userAction = SSDirector.GetInstance().CurrentSceneController as IUserAction;


    }
    // Start is called before the first frame update
    public void judge(int sign)
    {
        if (sign == 1)
        {
            Debug.Log("Game Scene End.");
            userAction.Restart();
        }

    }

遊戲運行結果:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章