Apex有一種很好的擴展機制,當你不附加自定義腳本的時候,按照默認的Apex邏輯走,比如Steering算法。但是當你新建一個MonoBehavior腳本,並且實現了IMoveUnit方法之後。把這個腳本貼到原本的Unit的GameObecjt上的時候,就可以自動識別並執行擴展的Steering算法。
研究了一下之後,發現這個過程是這樣的。
定義接口,在基本行爲中實現這個接口,然後在OnEnable或者Start裏面檢測是否有實現了這個接口的擴展MoveBehavior的Compoent,如果有,執行擴展行爲,如果沒有,執行基本行爲。
如圖:基本行爲
擴展行爲
實現方式,先定義一個查找Interface組件的擴展方法:ToInterfaxe<T>
public static class GameObjectUtil
{
public static void DestroyAllChild(this Component c)
{
Transform root = c.transform;
if (root.childCount > 0)
{
//從後往前刪除,效率高。
for (int i = root.childCount - 1; i >= 0; i--)
{
if (Application.isPlaying)
{
GameObject.Destroy(root.GetChild(i).gameObject);
}
else
{
GameObject.DestroyImmediate(root.GetChild(i).gameObject);
}
}
}
}
/// <summary>
/// 將當前Component轉換成指定接口,如果當前GameOjbect上有繼承了接口的組件,則返回真,否則,返回null。
/// 可以實現這樣的效果:
/// 如果查找到某個腳本(因爲他實現了某個接口),則執行某個操作,否則,執行默認行爲。並且這種實現是針對接口的,非常靈活
/// 比較耗,不要在Update中調用,比較適合在初始化的時候調用一次。
/// 參考來源:Apex->SharedUnityExtension
///
/// 用法 this.ToInterface<IMessageHandler> 如果有某個腳本繼承了這個接口,那麼就會返回,否則,返回NULL。
/// 這樣就可以做到,只有當附加了繼承handler的腳本,纔會發送對應的消息協議,否則,不發送,或者走默認邏輯。
/// 這樣做也可以非常方便讓用戶自己擴展某些邏輯,比如Apex自己寫了一個基礎的Steering,實現了IMoveUnit接口
/// 默認邏輯的時候,返回的 IMoveUnit接口爲空,這時候使用默認的Steering Move邏輯
/// 當你想要實現自己的Steering方法時,直接填寫實現了IMoveUnit的腳本,附加到GameObeject上即可。灰常靈活。新技能Get
public static T ToInterface<T>(this Component c, bool searchParent = false, bool required = false) where T : class
{
if (c.Equals(null))
{
return null;
}
return ToInterface<T>(c.gameObject, searchParent, required);
}
public static T ToInterface<T>(this GameObject go, bool searchParent = false, bool required = false) where T : class
{
if (go.Equals(null))
{
return null;
}
var c = go.GetComponent(typeof(T)) as T;
if (c == null && searchParent && go.transform.parent != null)
{
return ToInterface<T>(go.transform.parent.gameObject, false, required);
}
if (c == null && required)
{
throw new MissingComponentException(string.Format("Game object {0} does not have a component of type {1}.", go.name, typeof(T).Name));
}
return c;
}
}
基本方法:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using GameUtil;
public interface iBehave
{
void Execute();
}
public class DefaultBehave:iBehave
{
public void Execute()
{
Debug.Log("Default Behavior");
}
}
public class BasicBehav : MonoBehaviour
{
iBehave execut_behave;
void OnEnable()
{
execut_behave = this.ToInterface<iBehave>();
if (execut_behave == null)
{
execut_behave = new DefaultBehave();
}
}
void Update()
{
execut_behave.Execute();
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ExtentBehav : MonoBehaviour,iBehave
{
public void Execute()
{
Debug.Log("Extent Behav");
}
}