Unity 自定义事件

Unity 自定义事件


EventId.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Assets.Scripts.Event
{

    //事件ID
    public enum EventId
    {
        event1,
        event2,
        Count,//必须写在最后 用于表示所有Event的个数以及存储时间数组长度
    }
}

EventEatResponse.cs

using UnityEngine;
using System.Collections;


namespace Assets.Scripts.Event
{
    public enum EventEatResponse
    {
        /// 继续向下一个已经注册该事件的游戏体传递当前事件
        NotEaten,

        /// 停止向下一个已经注册该事件的游戏体传递当前事件
        Eaten,
    }
}

EventObservers.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Assets.Scripts.DataStructures;
using Assets.Scripts.Core;
namespace Assets.Scripts.Event
{
    /// <summary>
    /// 事件监听列表
    /// </summary>
    public class EventObservers
    {
        public PriorityList<IEventObserver> List { get; private set; }

       
        public MutableIterator Iter { get; private set; }

        public EventObservers()
        {
            List = new PriorityList<IEventObserver>();
            Iter = new MutableIterator();
        }
    }
}

EventPriority.cs
using UnityEngine;
using System.Collections;

namespace Assets.Scripts.Event
{
    /// <summary>
    /// 事件优先级
    /// </summar>
    public enum EventPriority
    {
        
        AfterDefault,
        Default,
        BeforeDefault,
        Notification,
    }
}

IEventObserver.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Assets.Scripts.Event
{
    /// <summary>
    /// 事件接口  所有要注册事件的类都要实现
    /// </summary>
    /// 

    
    public interface IEventObserver
    {
        // 接到事件后会调用该接口
        EventEatResponse OnEvent(EventId id, object cookie);
    }
}

EventManager.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Assets.Scripts.Core;
using Assets.Scripts.DataStructures;
namespace Assets.Scripts.Event
{
    /// <summary>
    /// 事件管理类
    /// </summary>
    public class EventManager
    {
        //已经注册事件的游戏体列表  根据事件优先级分组
        private EventObservers[] eventIdToObservers;

        public EventManager()
        {
            Service.Set<EventManager>(this);

            int count = (int)EventId.Count;
            eventIdToObservers = new EventObservers[count];

            // Fill with nulls until someone decides to listen for a given event.
            // .Net does this for us.  Just being explicit.
            for (int i = 0; i < count; i++)
            {
                eventIdToObservers[i] = null;
            }
        }

        // 注册默认优先级别的事件
        public void RegisterObserver(IEventObserver observer, EventId id)
        {
            RegisterObserver(observer, id, EventPriority.Default);
        }

        // 根据优先级来注册事件
        public void RegisterObserver(IEventObserver observer, EventId id, EventPriority priority)
        {
            if (observer == null)
            {
                return;
            }

            int index = (int)id;
            EventObservers observers = eventIdToObservers[index];
            if (observers == null)
            {
                observers = new EventObservers();
                eventIdToObservers[index] = observers;
            }
            PriorityList<IEventObserver> list = observers.List;

            if (list.IndexOf(observer) < 0)
            {
                list.Add(observer, (int)priority);
            }
        }

        // 根据id接触已经注册的事件
        public void UnregisterObserver(IEventObserver observer, EventId id)
        {
            int index = (int)id;
            EventObservers observers = eventIdToObservers[index];
            if (observers != null)
            {
                PriorityList<IEventObserver> list = observers.List;
                MutableIterator miter = observers.Iter;

                int i = list.IndexOf(observer);
                if (i >= 0)
                {
                    list.RemoveAt(i);
                    miter.OnRemove(i);

                    if (list.Count == 0)
                    {
                        eventIdToObservers[index] = null;
                    }
                }
            }
        }

        // 根据ID发送事件
        public void SendEvent(EventId id, object cookie)
        {
            int index = (int)id;
            EventObservers observers = eventIdToObservers[index];
            if (observers != null)
            {
                PriorityList<IEventObserver> list = observers.List;
                MutableIterator miter = observers.Iter;

                for (miter.Init(list.Count); miter.Active(); miter.Next())
                {
                    IEventObserver observer = list.GetElement(miter.Index);
                    if (observer.OnEvent(id, cookie) == EventEatResponse.Eaten)
                    {
                        break;
                    }
                }
                miter.Reset();
            }
        }
    }
}
ElementPriorityPair.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Assets.Scripts.Event
{
    public class ElementPriorityPair<T>
    {
        public T Element { get; set; }
        public int Priority { get; set; }

        public ElementPriorityPair(T element, int priority)
        {
            Element = element;
            Priority = priority;
        }
    }
}

MutableIterator.cs
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;

namespace Assets.Scripts.Event
{
    public class MutableIterator
    {
        int index;
        int count;

        public MutableIterator()
        {
            Reset();
        }

        public void Reset()
        {
            index = 0;
            count = 0;
        }

        public void Init(int count)
        {
            index = 0;
            this.count = count;
        }

        public void Init(ICollection list)
        {
            index = 0;
            this.count = list.Count;
        }

        public bool Active()
        {
            return index < count;
        }

        public void Next()
        {
            index++;
        }

        public int Index
        {
            get { return index; }
            set
            {
                // Only allow manual index setting if we haven't yet started iterating.
                if (index == 0)
                {
                    index = value;
                }
            }
        }

        public int Count
        {
            get { return count; }
        }

        public void OnRemove(int i)
        {
            if (count > 0)
            {
                count--;
                if (i <= index)
                {
                    index--;
                }
            }
        }
    }
}

PriorityList.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Assets.Scripts.Event
{
    public class PriorityList<T>
    {
        private List<ElementPriorityPair<T>> list;

        public PriorityList()
        {
            list = new List<ElementPriorityPair<T>>();
        }

        // Just like List<T>.Count.
        public int Count
        {
            get { return list.Count; }
        }

        // Similar to List<T>.Add() but inserts based on priority.
        // Returns the index where the element was inserted.
        // Returns -1 on failure.
        public virtual int Add(T element, int priority)
        {
            // Prevent null from being added.  It's just one of the features of this class.
            if (element == null)
            {
                return -1;
            }

            for (int i = 0, count = list.Count; i < count; i++)
            {
                ElementPriorityPair<T> pair = list[i];
                if (object.ReferenceEquals(pair.Element, element))
                {
                    // Already added.
                    return -1;
                }

                // Keep the list sorted, higher priority first.
                // For equal priorities, we'll add ourselves to the end of that range.
                if (priority > pair.Priority)
                {
                    // Found insertion point.
                    list.Insert(i, new ElementPriorityPair<T>(element, priority));
                    return i;
                }
            }

            // Didn't find an insertion point.  Add new currently-lowest-priority element.
            list.Add(new ElementPriorityPair<T>(element, priority));
            return list.Count - 1;
        }

        public ElementPriorityPair<T> Get(int i)
        {
            return list[i];
        }

        // Similar to List<T>[i].
        public T GetElement(int i)
        {
            return list[i].Element;
        }

        // Get the associated prioriity of the i'th element.
        public int GetPriority(int i)
        {
            return list[i].Priority;
        }

        // Alternative for when you want both the element and its associated prioiryt.
        public void GetElementPriority(int i, out T element, out int priority)
        {
            ElementPriorityPair<T> pair = list[i];
            element = pair.Element;
            priority = pair.Priority;
        }

        // Just like List<T>.IndexOf(element).
        public int IndexOf(T element)
        {
            for (int i = 0, count = list.Count; i < count; i++)
            {
                if (object.ReferenceEquals(list[i].Element, element))
                {
                    return i;
                }
            }

            return -1;
        }

        // No Remove(T t), to discourage misuse.  Callers must know the index to remove.
        // Remove(T t) can always be implemented is "if ((i = IndexOf(t)) >= 0) RemoveAt(i);".
        public void RemoveAt(int i)
        {
            list.RemoveAt(i);
        }
    }
}

Service.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Assets.Scripts.Event
{
    public static class Service
    {
#if SERVER
        [ThreadStatic]
#endif
        private static List<IServiceWrapper> serviceWrapperList;

        public static void Set<T>(T instance)
        {
            if (ServiceWrapper<T>.instance != null)
            {
                throw new Exception("An instance of this service class has already been set!");
            }

            ServiceWrapper<T>.instance = instance;

            if (serviceWrapperList == null)
            {
                serviceWrapperList = new List<IServiceWrapper>();
            }

            serviceWrapperList.Add(new ServiceWrapper<T>());
        }

        public static T Get<T>()
        {
            return ServiceWrapper<T>.instance;
        }

        public static bool IsSet<T>()
        {
            return ServiceWrapper<T>.instance != null;
        }

        // Resets references to all services back to null so that they can go out of scope and
        // be subjected to garbage collection.
        // * Services that reference each other will be garbage collected.
        // * AssetBundles should be manually unloaded by an asset manager.
        // * GameObjects will be destroyed by the next level load done by the caller.
        // * Any application statics should be reset by the caller as well.
        // * If there are any unmanaged objects, those need to be released by the caller, too.
        public static void ResetAll()
        {
            if (serviceWrapperList == null)
            {
                return;
            }

            // Unset in the reverse order in which services were set.  Probably doesn't matter.
            for (int i = serviceWrapperList.Count - 1; i >= 0; i--)
            {
                serviceWrapperList[i].Unset();
            }

            serviceWrapperList = null;
        }
    }

    internal class ServiceWrapper<T> : IServiceWrapper
    {
#if SERVER
        [ThreadStatic]
#endif
        public static T instance = default(T);

        public void Unset()
        {
            ServiceWrapper<T>.instance = default(T);
        }
    }

    internal interface IServiceWrapper
    {
        void Unset();
    }
}


具体使用:
void Start () {
        Debug.Log("MyCube Start");
        //注册事件
         Service.Get<EventManager>().RegisterObserver(this, EventId.event1,
                EventPriority.Default);
         Service.Get<EventManager>().RegisterObserver(this, EventId.event2,
                 EventPriority.Default);
	}


发送事件:
Service.Get<EventManager>().SendEvent(EventId.event1, null);

发送事件后会根据优先级调用注册当前EventId的那个游戏体,  继而执行 相应的OnEvent()
例如给myCube分别注册事件1 和 事件2  mySphere只注册事件1

(如果在OnEvent当中返回的是Eaten)则不会继续向下一个注册改事件的游戏体传递这个事件)

Unity 自定义事件_第1张图片



你可能感兴趣的:(Unity 自定义事件)