使用组合模式现实MyComponent组件
组合模式的优点是分级,从图里可以看出StateEvent和MyEvent是以一种递归的结构组织的,也就是组件里包含一个StateEvent(记录所有状态对应的List
IStateEvent接口:
public interface IStateEvent {
void trigger(int sidHash, float time);
}
StateEvent类:
public class StateEvent : System.Object, IStateEvent {
public float time;
//int是对应状态的fullpathhash,每个状态对应一个事件帧列表
private Dictionary<int, List<MyEvent> > dict_myEvent = new Dictionary<int, List<MyEvent> >();
public Animator anim;
public AnimatorStateInfo pre_state;
public AnimatorStateInfo now_state;
public StateEvent(Animator a) {
time = 0f;
anim = a;
}
//根据状态的全名和要设定的时间点获取MyEvent
public MyEvent getMyEvent(string sid, float time) {
int hash = Animator.StringToHash(sid);
if (!dict_myEvent.ContainsKey(hash)) {
dict_myEvent[hash] = new List<MyEvent>();
}
//同一个时间点只需要一个MyEvent
foreach(MyEvent item in dict_myEvent[hash]) {
if (item.sameTime(time)) {
return item;
}
}
MyEvent me = new MyEvent(hash, time);
dict_myEvent[hash].Add(me);
return me;
}
public void UpdateState() {
time += Time.deltaTime;
now_state = anim.GetCurrentAnimatorStateInfo(0);
if(now_state.fullPathHash == pre_state.fullPathHash) {
trigger(now_state.fullPathHash,now_state.normalizedTime);
} else {
EnterState();
}
}
public void EnterState() {
pre_state = now_state;
time = 0f;
}
//实现trigger接口,调用状态机当前状态下所有MyEvent的trigger
public void trigger(int sidHash, float time) {
if (dict_myEvent.ContainsKey(sidHash)) {
foreach(MyEvent item in dict_myEvent[sidHash]) {
item.trigger(sidHash,time);
}
}
}
}
MyEvent类:
public class MyEvent : System.Object, IStateEvent {
public int stateNameHash;
public float triggerTime;
public StateTrigger st;
//使用委托(观察者模式)实现
public delegate void EventFrame();
public EventFrame eventFrame;
public bool sameTime(float time) {
if(time == triggerTime) {
return true;
} else {
return false;
}
}
public MyEvent(int hash, float time) {
stateNameHash = hash;
triggerTime = time;
st = new StateTrigger(time);
}
//实现trigger接口,执行所有的回调函数
public void trigger(int sidHash, float time) {
if (st.triggerIt(time)) {
eventFrame();
}
}
//添加回调函数的接口
public void AddEvent(EventFrame func) {
eventFrame += func;
}
public void removeEvent(EventFrame func) {
eventFrame -= func;
}
}
StateTrigger类(辅助类):
public class StateTrigger:System.Object {
public float time;
public bool fire;
public StateTrigger(float t) {
time = t;
fire = false;
}
public bool triggerIt(float t) {
if (t > time && !fire) {
fire = true;
return true;
}else if (t < time) {
fire = false;
}
return false;
}
}
MyComponent脚本:之所以生成一个StateEvent的原因是,我们实现的是一个组件,这个组件的功能是存储状态机动画中各个状态中的事件帧。并在对应的时间里执行对应的事件。用户只需要获取我们这个组件中的se,并使用里面的getMyEvent(StateName,Time).Add(callBackFunc),就可以实现这个功能。
public class MyComponent : MonoBehaviour {
public Animator ani;
public com.MyStateEvent.StateEvent se;
void Awake () {
//根据ani生成一个StateEvent
se = new com.MyStateEvent.StateEvent(ani);
}
void Update () {
se.UpdateState();
}
}
测试脚本:
//test2.cs
using UnityEngine;
using System.Collections;
public class test2 : MonoBehaviour {
// Use this for initialization
void Start () {
//获取MyComponent中的se属性
com.MyStateEvent.StateEvent se = GetComponent<MyComponent>().se;
se.getMyEvent("Base Layer.idle", 0.5f).AddEvent(HelloWorld);
se.getMyEvent("Base Layer.idle", 0.3f).AddEvent(HelloWorld2);
se.getMyEvent("Base Layer.idle", 0.5f).AddEvent(HelloWorld2);
}
// Update is called once per frame
void Update () {
}
void HelloWorld() {
print("HelloWorld");
}
void HelloWorld2() {
print("HelloWorld2");
}
}
结果:
1
FIN 4.26/00.00