DonerComponents是一個基於C ++的14個基於組件的遊戲對像模型框架,用於開發電子遊戲。
如果您不熟悉這個概念,我建議您查看示例項目或教程,然後嘗試一下!
您可以在此處獲取穩定的發行版。
另外,您可以通過以下方式查看當前開發版本
git clone https://github.com/Donerkebap13/DonerComponents.git
請記住,以後運行git submodule update --init --recursive 。
您也可以直接通過電子郵件與我聯繫,如果您有任何建議或發現任何錯誤,請隨時創建一個新問題。
DonerComponents_asteroids_example是我創建的示例項目,以展示如何使用DonerComponents 。這是一個非常簡單的小行星 - 北方克隆。我對該項目的目的是顯示框架現在支持的所有功能,例如:
在這裡,我將嘗試說明Donercomponents主要係統的基本用法。閱讀本文後,您將獲得有關如何組織方式以及如何使用它們的基本知識。要深入了解,我建議您看看示例項目。
CDonerComponentsSystems是一個單身人士,可以初始化並訪問所有DonerComponents不同系統。它應該初始化:
# include < DonerComponents/CDonerComponentsSystems.h >
DonerComponents::CDonerComponentsSystems::CreateInstance ();
DonerComponents::CDonerComponentsSystems::Get ()->Init();更新:
float elapsed = ...;
DonerComponents::CDonerComponentsSystems::Get ()->Update(elapsed);並被摧毀:
DonerComponents::CDonerComponentsSystems::DestroyInstance ();DonerComponents::CGameObject是Donercomponents的主要演員。該類可以包含不同的DonerComponents::CComponent ,以定義其行為。它還具有有關其父母和子女的信息。它還可以接收POD消息並將其轉發到其組件和孩子。最後但並非最不重要的一點是,它也可以標記。
創建新的遊戲對像很簡單:
# include < DonerComponents/gameObject/CGameObject.h >
DonerComponents::CGameObjectManager* gameObjectManager = DonerComponents::CDonerComponentsSystems::Get()-> GetGameObjectManager ();
DonerComponents::CGameObject *gameObject = gameObjectManager-> GetNewElement (); GetNewElement();只要它沒有用完gameObject,就會返回有效的DonerComponents::CGameObject 。默認情況下,Donercomponents可以同時擁有4096個GameObject。通過編譯器標誌-DMAX_GAME_OBJECTS=4096可修改此值,最大為8.192 GAMEOBJECTS。
DonerComponents支持預製的定義,因此用戶可以定義特定的遊戲對象層次結構,以便在需要的任何地方重複使用:
# include < DonerComponents/gameObject/CPrefabManager.h >
DonerComponents::CGameObjectManager* prefabManager = DonerComponents::CDonerComponentsSystems::Get()-> GetPrefabManager ();
prefabManager-> RegisterPrefab ( " prefabName " , anyGameObjectCreatedPreviously);預製也可以從JSON文件中加載。
DonerComponents::CComponent是Donercomponents中任何組件的基類。組件通過匯總來定義遊戲對象的行為。他們可以收聽特定的消息並相應地執行操作。任何新組件都應從此類中繼承,並且可以在需要時實現一些基本方法。用戶最多可以註冊512個不同的組件。
這是新組件創建的示例。其所有方法的實現都是可選的:
# include < DonerComponents/component/CComponent.h >
class CCompFoo : public DonerComponents ::CComponent
{
public:
void DoInit () override { m_foo = 0 . 0f ; }
void DoUpdate ( float dt) override { m_foo += dt; }
void DoDestroy () override { m_foo = 0 . 0f ; }
void DoActivate () override { }
void DoDeactivate () override { }
private:
float m_foo;
};要在系統中註冊此組件,因此任何GameObject都可以使用它,我們需要執行以下操作:
# include < DonerComponents/component/CComponentFactoryManager.h >
static constexpr int amountOfFooComponentsAvailable = 512 ;
ADD_COMPONENT_FACTORY ( " foo " , CCompFoo, amountOfFooComponentsAvailable);初始化DonerComponents::CDonerComponentsSystems之後,我們可以使用Macro ADD_COMPONENT_FACTORY開始將組件註冊到系統中。它收到的字符串是在從JSON文件中解析我們的遊戲對象時識別組件。最後一個參數是將有多少個組件可用。與GameObject一樣,同一時間最多有8.192個組件。
將組件註冊到系統中後,可以通過兩種不同的方式將其添加到GameObject中:
DonerComponents::CComponent* component = gameObject->AddComponent<CCompFoo>();
// same as
CCompFoo* component = gameObject->AddComponent<CCompFoo>();
// or
DonerComponents::CComponent* component = gameObject-> AddComponent ( " foo " );
// same as
CCompFoo* component = gameObject-> AddComponent ( " foo " );在Donercomponents中,組件按類型進行更新,一次是一種類型,以將其註冊到系統中。因此,在示例中:
ADD_COMPONENT_FACTORY ( " foo " , CCompFoo, 128 );
ADD_COMPONENT_FACTORY ( " bar " , CCompBar, 128 );在更新所有現有的CCompBar組件之前,所有現有的CCompFoo都將依次更新。
您可以使用DonerSerializer定義哪些數據將在JSON中進行修改。您可以在這裡檢查如何使用它。在這裡,我將展示一個例子。
class CCompFoo : public DonerComponents ::CComponent
{
DONER_DECLARE_COMPONENT_AS_SERIALIZABLE (CCompFoo)
public:
CCompFoo ();
private:
float m_dummy1;
std::vector<std::string> m_dummy2;
};
DONER_DEFINE_REFLECTION_DATA (CCompFoo,
DONER_ADD_NAMED_VAR_INFO (m_dummy1, " dummy1 " ),
DONER_ADD_NAMED_VAR_INFO(m_dummy2, " dummy2 " )
)公開m_dummy1和m_dummy2之後,我們可以在JSON中定義它們的值:
{
"root" : {
"name" : " test1 " ,
"components" : [
{
"name" : " foo " ,
"dummy1" : 1.0 ,
"dummy2" : [ " Test1 " , " Test2 " , " Test3 " ]
}
]
}
}有關如何從JSON中閱讀的更深入的查看。
Donercomponents支持一個消息系統,以在不同的遊戲對象和組件之間進行交互。消息可以是用戶定義的任何結構/類。通常,它只包含數據,沒有邏輯,但是對此沒有任何限制。這就是DonerComponents::CComponent可以收聽特定消息的方式:
// Somewhere in your code
struct SDummyMessage {
SDummyMessage ( int foo, int bar)
: m_foo(foo), m_bar(bar) {}
int m_foo = 0 ;
int m_bar = 0 ;
}
// Inside your component
CCompFoo::RegisterMessages () {
RegisterMessage (&CCompFoo::OnDummyMessage);
}
void CCompFoo::OnDummyMessage ( const SDummyMessage& message) {
// ...
}註冊了所需的消息後,您可以開始發送這樣的消息:
SDummyMessage message ( 2 , 3 );
// This will propagate the message to all gameObject's components.
gameObject-> SendMessage (message);
// This will propagate the message to all gameObject's components and its children's components.
gameObject-> SendMessage (message, DonerComponents::ESendMessageType::Recursive);
// This won't send the message to the current gameObject but it's children.
gameObject-> SendMessageToChildren (message);
// Same as before but recursively through all gameObject's children and children's children.
gameObject-> SendMessageToChildren (message, DonerComponents::ESendMessageType::Recursive); SendMessage在同一幀中立即發送消息。如果要延遲發送消息直到框架結束,請改用後PostMessage 。
最後但並非最不重要的一點是,如果您想向所有活著的遊戲對象發送消息,則可以使用BroadcastMessage :
SDummyMessage message ( 2 , 3 );
// This will propagate the message to all GameObjects alive.
gameObjectManager-> BroadcastMessage (message); DonerComponents::CHandle是一種單線智能指針。他們指出了特定的DonerComponents::CGameObject或DonerComponents::CComponent ,在任何時刻都知道它們是否仍然有效,或者,換句話說,是否已被代碼中的其他地方銷毀。 DonerComponents::CHandle的大小為32位。在Donercomponents中工作的方式是,我們從不存儲Donercomponents的原始指針DonerComponents::CGameObject或DonerComponents::CComponent ,我們總是存儲DonerComponents::CHandle ,因此我們可以檢查他們指向的元素是否仍然有效,因此我們不訪問懸而未決的指針。任何DonerComponents::CHandle可以鑄造給DonerComponents::CGameObject或DonerComponents::CComponent 。如果演員表是有效的並且該元素仍然存在,則它將返回有效的指針到該元素。否則,它將返回nullptr 。這是一個例子:
# include < DonerComponents/handle/CHandle.h >
# include < DonerComponents/gameObject/CGameObjectManager.h >
using namespace DonerComponents ;
CHandle gameObjectHandle = m_gameObjectManager-> GetNewElement ();
if (gameObjectHandle) {
// CGameObjectManager has return a valid CGameObject
} else {
// CGameObjectManager has run out of CGameObjects
}
CGameObject* gameObject = gameObjectHandle;
// gameObject will be valid as gameObjectHandle points to an alive gameObject
m_gameObjectManager-> DestroyGameObject (&gameObject);
// gameObject is nullptr at this point
// gameObjectHandle == false as it points to a destroyed gameObject.另外,您可以通過手柄發送消息。如果手柄有效,則該消息將得到正確傳播。否則,該消息將被忽略:
DonerComponents::CHandle handle = gameObject;
SDummyMessage message ( 2 , 3 );
handle.SendMessage(message);
標籤是將更多信息添加到遊戲對象的一種方式,因此您可以過濾它們,僅將消息發送給具有特定標籤的GameObject。首先,用代碼直接宣布它們:
# include < DonerComponents/tags/CTagsManager.h >
DonerComponents::CTagsManager* tagsManager = DonerComponents::CDonerComponentsSystems::Get()-> GetTagsManager ();
tagsManager-> RegisterTag ( " Tag1 " );
tagsManager-> RegisterTag ( " TagN " );第二個,從JSON文件中解析它們:
tagsManager-> ParseTagsFromFile ( " path/to/your/tags.json " );標籤的格式。 JSON文件與此類似:
{ "tags" : [ " Tag1 " , " tag2 " , " tagN " ] }DonerComponents支持DonerSerializer使用JSON從磁盤上加載,因此,有一種創建預製措施或場景的方式可以作為資產存儲,而不是每次運行應用程序時都可以在代碼中從scratch中構建它們。基本用法如下:
# include < DonerComponents/GameObjects/CGameObjectParser.h >
DonerComponents::CGameObjectParser parser;
CGameObject* gameObject = parser.ParseSceneFromFile( " path/to/your/scene.json " );scene.json文件的格式與此類似:
{
"root" : {
"name" : " test1 " ,
"tags" : [ " tag1 " , " tag2 " , " tag3 " ],
"components" : [
{
"name" : " comp_location " ,
"x" : 1 ,
"y" : -3 ,
"z" : 9
},
{
"name" : " comp_rotation " ,
"radians" : 0.2
}
],
"children" : [
{
"name" : " test11 " ,
"tags" : [ " tag1 " , " tag3 " ]
},
{
"name" : " test12 " ,
"initiallyActive" : false
}
]
}
}如果沒有解析場景,我們想解析預製件將其自動註冊到DonerComponents::CPrefabManager ,我們只需要致電ParsePrefabFromFile :
# include < DonerComponents/GameObjects/CGameObjectParser.h >
DonerComponents::CGameObjectParser parser;
CGameObject* gameObject = parser.ParsePrefabFromFile( " path/to/your/prefab.json " );執行此操作後,預製可用於使用任何新的解析場景。
Donercomponents支持包括其他預製符號的預製,能夠覆蓋其組件的信息:
prefab1.json
{
"root" : {
"name" : " Prefab1 " ,
"components" : [
{
"name" : " comp_location " ,
"x" : 1 ,
"y" : -3 ,
"z" : 9
},
{
"name" : " comp_rotation " ,
"radians" : 0.2
},
{
"name" : " sprite " ,
"texture" : " res/common/textures/asteroid_med.png "
}
]
}
}prefab2.json
{
"root" : {
"name" : " Prefab2 " ,
"prefab" : " Prefab1 " ,
"components" : [
{
"name" : " sprite " ,
"texture" : " res/common/textures/flower_big.png "
}
]
}
}場景
{
"root" : {
"name" : " root " ,
"prefab" : " Prefab2 " ,
"components" : [
{
"name" : " comp_location " ,
"x" : 0 ,
"y" : 0 ,
"z" : 0
}
]
}
}