您的位置:首页 > 移动开发 > Unity3D

Unity 从Apex学到的一种提高模块扩展性的方法

2017-07-26 08:50 204 查看
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");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: