1. 程式人生 > >該怎麼樣用C++來實現類Unity3d的AddComponent

該怎麼樣用C++來實現類Unity3d的AddComponent

Unity3d 越來越完善,朝著它學習的人也越來越多。一是因為Unity3d是一整套開發工具,使用起來簡單快捷。二是 Mono C#的快速開發上手簡單。

在Unity編輯器中,新增一個GameObject , 然後把一個繼承自MonoBehavior的指令碼拖到GameObject上,即可對GameObject進行操作。或者在程式碼中new 一個GameObject,然後用AddComponet 掛載一個指令碼到GameObject上。

AddComponet 這個函式,可以通過傳遞 String 來例項化一個類。該如何用C++來實現類似的功能呢?

首先介紹一下Unity 的一些原理:

(1) 我們編寫一個類繼承自MonoBehavior ,然後新增 Start 、Update 這些函式。但是這些函式其實是私有的,並不是從MonoBehavior中繼承而來,那這幾個函式是在哪裡呼叫的?

Unity中通過反射來判斷一個類中有沒有對應的函式,引自知乎中的一個回答:

Unity的確是通過反射來呼叫指令碼的方法的,並且這一過程會在執行時不停對所有MonoBehaviour遍歷進行。

Unity之所以統一地使用這一套固定的函式命名方案,便於明確地劃出了每個函式需要做些什麼。

這樣做的目的我猜測是有利用保留指令碼的靈活性。

這種做法被慣稱為“事件機制”,一旦某個指令碼被執行完成之後,它的控制權會重新回到排程管理處,可以輕鬆地再去執行下一個,

並且也能在執行時通過反射方式讓其它指令碼使用Component.SendMessage進行呼叫。

如果採用了抽象方式讓子類去實現這樣的方法,那麼對於Unity本身的物件管理是沒有任何好處的,並且對於擁有多個指令碼元件的物件來說,維護成本不但增加了,

還可能讓指令碼之間的管理變得混亂。

使用反射也許會丟失一些效能,但卻能讓每個不同的MonoBehaviour之間看起來都是獨立的,只需要在它提供的幾個內建方法中關注自己的邏輯就可以了。 

那 C++ 呢?C++判斷類是否有某個函式不好弄,所以還是採用繼承的方式來簡單實現 AddComponet 。

這種方法的關鍵就是如何使用類名來建立類例項

其中一種方式就是 , 讓通過類名例項化的類 繼承自 基類 ,然後通過靜態函式在程式最開始執行的時候,向基類註冊,然後在呼叫 AddComponet 的時候,通過基類的函式在最開始註冊的子類中尋找是否有對應名字的子類,如果有的話就例項化子類。

最終簡單實現Unity3d中的AddComponet 函式。

int main()
{
	GameObject* obj=new GameObject("Cube");
	NewMonoBehaviour* newmono=(NewMonoBehaviour*)obj->AddComponent("NewMonoBehaviour");
	MyMonoBehaviour* mymono=(MyMonoBehaviour*)obj->AddComponent("MyMonoBehaviour");

	for (int i=0;i<obj->m_componentVec.size();i++)
	{
		std::pair<string,Component*> compmap=obj->m_componentVec[i];
		MonoBehaviour* mono=(MonoBehaviour*)compmap.second;
		mono->Awake();
	}

	system("pause");
	return 0;
}

程式碼下載:

http://pan.baidu.com/s/1i3rcYPZ