【Unity 3D事件優化】
公司項目開發中,大部分函數功能回調都是通過注冊,派發事件實作的。将回調的一個或多個對象方法綁定某個事件,當派發該事件時,綁定該事件的一個或多個對象接收到該事件後調用對應的方法。模式屬于:一對一或一對多。這樣的模式在處理大多數事件情況非常得體。
最近接策劃的一個案子,大體功能是組隊功能界面的多個隊員item,實時顯示更新隊員的血量。項目中所有玩家的血量改變都通過一個SM_HealthChange協定,該協定包含要改變血量的玩家Id号和改變的血量值。接收到這個協定,通過該協定的Id号,擷取對應玩家的entity實體table表,然後調用該entity的setHp函數處理血量。開始想到的組隊界面血量同步方法是:沿用項目已有的事件系統,所有隊員先注冊血量改變事件,當接收SM_HealthChange協定時,發送血量改變事件同時将改變血量的玩家Id号和改變的血量值作為參數傳遞。之前注冊了血量改變事件的隊員接到該事件後,先判斷血量改變的玩家id是不是自己的,如果是自己的改變自己的血量顯示,否則就不做處理。這樣就實作了血量同步方法。
但後面分析存在個問題,隻要接到SM_HealthChange協定就發送事件,不管綁定的對象id是不是協定中的玩家id,隻要發送事件就得接受,因為事件發送者沒法提前判斷多個綁定事件的對象誰才是真正要接收的對象,進而造成了不必要的開銷消耗。後來采取同僚的建議,可以采用c#自帶的事件功能event,每個玩家實體entity内建立一個血量改變事件,組隊界面每個隊員item将對應的玩家entity的血量改變事件和自身的血量更新函數綁定,這樣當對應的entity改變血量調用自身的setHp函數時就調用對應組隊界面隊員item綁定的血量改變函數,實作了誰的血量改變就調用對應玩家的血量同步函數,達到了一對一的事件處理,優化了不必要的開銷。
下面上熱騰騰的代碼
using System;
using System.Collections.Generic;
namespace 深入了解CShape
{
class Entity
{
public delegate void Func(float hp);
public event Func HP_ChangeEvent;
public readonly int ID;
private float hp;
public Entity(int id)
{
ID = id;
}
public float HP
{
get { return hp; }
set {
hp = value;
Console.WriteLine("玩家{0}的血量改變為{1}", ID, hp);
HP_ChangeEvent(hp);
}
}
}
class TeamMember
{
public readonly int ID;
private float m_Hp;
public TeamMember(int id)
{
ID = id;
}
public void SynchronousBlood(float hp)
{
m_Hp = hp;
Console.WriteLine("隊員{0}改變血量為{1}", ID, hp);
}
}
class Program
{
static void Main(string[] args)
{
Dictionary<int, Entity> entityList = new Dictionary<int, Entity>();
for(int i = 1; i <= 5; ++i)
{
entityList.Add(i, new Entity(i));
TeamMember teamMember = new TeamMember(i);
Entity entity = entityList[teamMember.ID];
entity.HP_ChangeEvent += teamMember.SynchronousBlood;
}
var iter = entityList.GetEnumerator();
Random random = new Random();
while (iter.MoveNext())
{
iter.Current.Value.HP = random.Next(50, 100);
Console.WriteLine();
}
Console.ReadLine();
}
}
}
運作結果

這樣一對一發送,保證了對應的事件改變發送給對應的監聽者,省去了不必要的開銷。個人對優化的了解就行,在保障功能不受影響的前提下,重複計算處理的,不需要計算的統統pass,隻留下真正起作用的部分,以保障性能開銷。