下載 Fantasy Skybox FREE, 構建自己的遊戲場景
從Asset Store上下載的Skybox:
牧師與魔鬼 動作分離版
UML類圖
動作管理Actions類
動作基類 SSAction
要點
- ScriptableObject 是不需要綁定 GameObject 對象的可編程基類。這 些對象受 Unity 引擎場 景管理
- 防止用戶自己 new 對象
- 使用 virtual 申明虛方法,通過重寫實現多態。 這樣繼承者就明確使用 Start 和 Update 編程 遊戲對象行爲
- 利用接口實現消息通知, 避免與動作管理者直接 依賴。
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類,實現的功能有:
- 雙頰一個動作順序的執行序列
- 執行當前動作
- 收到當前動作執行完成,推下一個動 作,如果完成一次循環,減次數。如完 成,通知該動作的管理者。
- 執行動作前爲動作注入相應的遊戲對象,並將自己作爲動作事件接收者。
- 當自己被註銷時釋放管理的動作。
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
- 創建 MonoBehaiviour 管理一個動作 集合,動作做完自動回收動作。
- 提供了運行一個新動作的方法。該方 法把遊戲對象與動作綁定,並綁定該動 作事件的消息接收者。
- 執行該動作的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();
}
}
遊戲運行結果: