DonerComponents adalah kerangka model objek game berbasis C ++ 14 untuk mengembangkan videogame.
Jika Anda tidak terbiasa dengan konsep ini, saya sarankan Anda untuk melihat ke proyek contoh atau tutorial dan mencobanya!
Anda dapat memperoleh rilis stabil di sini.
Atau, Anda dapat memeriksa versi pengembangan saat ini dengan:
git clone https://github.com/Donerkebap13/DonerComponents.git
Ingatlah untuk menjalankan git submodule update --init --recursive sesudahnya.
Anda dapat menghubungi saya langsung melalui email juga, jika Anda memiliki saran atau Anda menemukan bug, jangan ragu untuk membuat masalah baru.
DonerComponents_asteroids_example adalah contoh proyek yang saya buat untuk menunjukkan cara menggunakan DonerComponents . Ini adalah klon asteroid-wannabe yang sangat sederhana. Niat saya dengan proyek itu adalah untuk menunjukkan semua fitur yang didukung kerangka kerja saat ini, seperti:
Di sini saya akan mencoba mengilustrasikan penggunaan dasar sistem utama komponen doner. Setelah membaca ini, Anda akan memiliki pengetahuan dasar tentang bagaimana hal -hal diatur dan bagaimana mereka dapat digunakan. Untuk pemahaman yang lebih dalam, saya sarankan Anda untuk melihat -lihat proyek contoh.
CDonerComponentsSystems adalah singleton yang menginisialisasi dan memberikan akses ke semua sistem donercomponent yang berbeda. Itu harus diinisialisasi:
# include < DonerComponents/CDonerComponentsSystems.h >
DonerComponents::CDonerComponentsSystems::CreateInstance ();
DonerComponents::CDonerComponentsSystems::Get ()->Init();Diperbarui:
float elapsed = ...;
DonerComponents::CDonerComponentsSystems::Get ()->Update(elapsed);Dan hancur:
DonerComponents::CDonerComponentsSystems::DestroyInstance (); DonerComponents::CGameObject adalah aktor utama DonerComponents. Kelas ini dapat berisi DonerComponents::CComponent yang mendefinisikan perilakunya. Ia juga memiliki informasi tentang orang tuanya dan anak -anaknya. Itu juga dapat menerima pesan POD dan meneruskannya ke komponen dan anak -anaknya. Terakhir, itu juga bisa ditandai.
Membuat GameObject baru sesederhana:
# include < DonerComponents/gameObject/CGameObject.h >
DonerComponents::CGameObjectManager* gameObjectManager = DonerComponents::CDonerComponentsSystems::Get()-> GetGameObjectManager ();
DonerComponents::CGameObject *gameObject = gameObjectManager-> GetNewElement (); GetNewElement(); Akan mengembalikan DonerComponents::CGameObject selama itu belum kehabisan GameObjects untuk menghasilkan. Secara default, DonerComponents dapat memiliki 4096 GameObjects hidup pada saat yang sama. Nilai ini dapat dimodifikasi melalui bendera kompiler -DMAX_GAME_OBJECTS=4096 dengan maksimum 8.192 GameObjects.
DonerComponents mendukung definisi prefab, sehingga pengguna dapat mendefinisikan hierarki GameObject tertentu untuk menggunakannya kembali di mana pun dibutuhkan:
# include < DonerComponents/gameObject/CPrefabManager.h >
DonerComponents::CGameObjectManager* prefabManager = DonerComponents::CDonerComponentsSystems::Get()-> GetPrefabManager ();
prefabManager-> RegisterPrefab ( " prefabName " , anyGameObjectCreatedPreviously);Prefab juga dapat dimuat dari file JSON.
DonerComponents::CComponent adalah kelas dasar untuk setiap komponen di DonerComponents. Komponen mendefinisikan perilaku GameObject dengan agregasi. Mereka dapat mendengarkan pesan tertentu dan melakukan tindakan yang sesuai. Komponen baru apa pun harus mewarisi dari kelas ini dan dapat menerapkan beberapa metode dasar, jika diperlukan. Pengguna dapat mendaftar hingga 512 komponen yang berbeda.
Berikut adalah contoh kreasi komponen baru. Implementasi semua metodenya adalah opsional :
# 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;
};Untuk mendaftarkan komponen ini dalam sistem, sehingga setiap GameObject dapat menggunakannya, kita perlu melakukan hal berikut:
# include < DonerComponents/component/CComponentFactoryManager.h >
static constexpr int amountOfFooComponentsAvailable = 512 ;
ADD_COMPONENT_FACTORY ( " foo " , CCompFoo, amountOfFooComponentsAvailable); Setelah menginisialisasi DonerComponents::CDonerComponentsSystems kita dapat mulai mendaftarkan komponen kita ke dalam sistem menggunakan makro ADD_COMPONENT_FACTORY . String yang diterimanya adalah untuk mengidentifikasi komponen sambil mem -parsing GameObjects kami dari file JSON . Parameter terakhir adalah berapa banyak komponen yang akan tersedia. Seperti halnya GameObjects, ada maksimum 8,192 komponen dari jenis yang sama hidup pada saat yang sama.
Setelah komponet terdaftar ke dalam sistem, itu dapat ditambahkan ke GameObject dengan dua cara berbeda:
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 " );Di DonerComponents , komponen diperbarui berdasarkan jenis, satu jenis pada satu waktu, dalam urutan mereka terdaftar ke dalam sistem. Jadi dalam contoh:
ADD_COMPONENT_FACTORY ( " foo " , CCompFoo, 128 );
ADD_COMPONENT_FACTORY ( " bar " , CCompBar, 128 ); Semua CCompFoo yang ada akan diperbarui secara berurutan sebelum memperbarui semua komponen CCompBar yang ada.
Anda dapat mendefinisikan data mana yang akan diekspos untuk dimodifikasi di JSON menggunakan Donerserializer . Anda dapat memeriksa di sini cara menggunakannya. Di sini saya hanya akan menunjukkan contoh.
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 " )
) Setelah mengekspos m_dummy1 dan m_dummy2 , kita dapat menentukan nilainya di JSON seperti ini:
{
"root" : {
"name" : " test1 " ,
"components" : [
{
"name" : " foo " ,
"dummy1" : 1.0 ,
"dummy2" : [ " Test1 " , " Test2 " , " Test3 " ]
}
]
}
}Untuk tampilan yang lebih mendalam tentang cara membaca dari JSON , periksa ini .
DonerComponents mendukung sistem pesan untuk berinteraksi antara berbagai object dan komponen. Pesan bisa berupa struct/kelas yang ditentukan oleh pengguna. Biasanya hanya akan berisi data, tidak ada logika, tetapi tidak ada batasan untuk ini. Beginilah cara DonerComponents::CComponent dapat mendengarkan pesan tertentu:
// 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) {
// ...
}Setelah mendaftarkan pesan yang Anda inginkan, Anda dapat mulai mengirim pesan seperti ini:
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 mengirim pesan segera, dalam bingkai yang sama. Jika Anda ingin menunda mengirim pesan sampai akhir bingkai, gunakan PostMessage sebagai gantinya.
Terakhir tetapi tidak kalah pentingnya, jika Anda ingin mengirim pesan ke semua GameObjects Living, Anda dapat menggunakan BroadcastMessage :
SDummyMessage message ( 2 , 3 );
// This will propagate the message to all GameObjects alive.
gameObjectManager-> BroadcastMessage (message); DonerComponents::CHandle adalah semacam petunjuk pintar utas tunggal . Mereka menunjuk ke DonerComponents::CGameObject atau DonerComponents::CComponent , mengetahui pada saat -saat jika mereka masih valid atau tidak atau, dengan kata lain, jika mereka telah dihancurkan di tempat lain dalam kode. Ukuran DonerComponents::CHandle adalah 32 bit. Cara bekerja di DonerComponents adalah kami tidak pernah menyimpan petunjuk mentah DonerComponents::CGameObject atau DonerComponents::CComponent , kami selalu menyimpan DonerComponents::CHandle , sehingga kami dapat memeriksa apakah elemen yang mereka tunjukkan masih valid, jadi kami tidak mengakses pointer dangling. Setiap DonerComponents::CHandle dapat dilemparkan ke DonerComponents::CGameObject atau DonerComponents::CComponent . Jika gips valid dan elemen masih ada, itu akan mengembalikan pointer yang valid ke elemen. Kalau tidak, itu akan mengembalikan nullptr . Inilah contohnya:
# 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.Anda juga dapat mengirim pesan melalui pegangan. Jika pegangannya valid, pesan akan disebarkan dengan benar. Jika tidak, pesan tersebut akan diabaikan:
DonerComponents::CHandle handle = gameObject;
SDummyMessage message ( 2 , 3 );
handle.SendMessage(message);
Tag adalah cara untuk menambahkan lebih banyak informasi ke GameObjects Anda, jadi Anda dapat memfilternya, mengirim pesan hanya ke GameObjects dengan tag tertentu dll. Ada dua cara untuk menambahkan tag ke sistem, sehingga Anda dapat menggunakannya nanti. Yang pertama, mendeklarasikannya secara langsung dalam kode:
# include < DonerComponents/tags/CTagsManager.h >
DonerComponents::CTagsManager* tagsManager = DonerComponents::CDonerComponentsSystems::Get()-> GetTagsManager ();
tagsManager-> RegisterTag ( " Tag1 " );
tagsManager-> RegisterTag ( " TagN " );Yang kedua, parsing mereka dari file JSON:
tagsManager-> ParseTagsFromFile ( " path/to/your/tags.json " );Format file tags.json adalah sesuatu yang mirip dengan ini:
{ "tags" : [ " Tag1 " , " tag2 " , " tagN " ] }DonerComponents mendukung pemuatan dari disk menggunakan JSON berkat Donerserializer , jadi ada cara untuk membuat prefab atau adegan yang dapat disimpan sebagai aset alih -alih membangunnya dari awal dalam kode setiap kali kami menjalankan aplikasi kami. Penggunaan dasarnya adalah sebagai berikut:
# include < DonerComponents/GameObjects/CGameObjectParser.h >
DonerComponents::CGameObjectParser parser;
CGameObject* gameObject = parser.ParseSceneFromFile( " path/to/your/scene.json " );Format file scene.json adalah sesuatu yang mirip dengan ini:
{
"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
}
]
}
} Jika, alih -alih menguraikan adegan, kami ingin menguraikan prefab untuk mendaftarkannya secara otomatis ke DonerComponents::CPrefabManager , kami hanya perlu memanggil ParsePrefabFromFile :
# include < DonerComponents/GameObjects/CGameObjectParser.h >
DonerComponents::CGameObjectParser parser;
CGameObject* gameObject = parser.ParsePrefabFromFile( " path/to/your/prefab.json " );Setelah melakukan ini, prefab tersedia untuk setiap adegan parsed baru untuk digunakan.
DonerComponents mendukung prefab yang mencakup prefab lainnya, mampu mengesampingkan informasi komponennya:
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 "
}
]
}
}Scene.json
{
"root" : {
"name" : " root " ,
"prefab" : " Prefab2 " ,
"components" : [
{
"name" : " comp_location " ,
"x" : 0 ,
"y" : 0 ,
"z" : 0
}
]
}
}