|
Programiranje Programski jezici, tehnike, alatke... |
|
Alatke vezane za temu | Vrste prikaza |
10.7.2014, 21:15 | #1 |
V.I.P. Programiranje
Član od: 29.8.2007.
Lokacija: Valjevo
Poruke: 1.349
Zahvalnice: 983
Zahvaljeno 371 puta na 280 poruka
|
[C++] Unity sistem komponenti
Posle duze pauze rek'o da se vratim malo programiranju, a vidim da je i nesto slabo aktivan ovaj deo foruma.
Imao sam priliku da probam malo Unity endzin, posto je postao veoma popularan pa rek'o da vidim i ja o cemu se radi. Ukratko, mnogo mi se svideo njihov "component system" pa sam probao da implementiram nesto slicno sa C++-som. Postavicu kod ovde pa cu ispod malo da izkomentarisem. Kod:
#include <iostream> #include <string> #include <unordered_map> #include <type_traits> #include <memory> #include <cassert> #include <vector> #include <algorithm> template<typename T> struct type { static void id() { } }; template<typename T> std::size_t type_id() { return reinterpret_cast<std::size_t>(&type<T>::id); } class Component { public: Component() { } virtual ~Component() {} }; class Transform final : public Component { public: int x, y; Transform(int x, int y) : x(x), y(y) {} }; class Renderable final : public Component { public: std::string data; Renderable(std::string d) : data(d) {} }; class Other final : public Component { public: }; typedef std::shared_ptr<Transform> sp_Transform; typedef std::shared_ptr<Renderable> sp_Renderable; class RenderSystem { private: friend class SceneManager; typedef std::vector< std::weak_ptr<Renderable> > t_Renderable; t_Renderable vRend; void AddRenderable(sp_Renderable r) { vRend.push_back(r); } public: void Update() { for (std::size_t i = 0; i < vRend.size(); ++i) { if (auto sp = vRend[i].lock()) // not expired { std::cout << sp->data << std::endl; } else // component removed, swap - pop_back { std::swap(vRend[i--], vRend.back()); vRend.pop_back(); } } } }; class PhysicsSystem { private: friend class SceneManager; typedef std::vector< std::weak_ptr<Transform> > t_Transform; t_Transform vTransform; void AddTransform(sp_Transform t) { vTransform.push_back(t); } public: void Update() { for (std::size_t i = 0; i < vTransform.size(); ++i) { if (auto sp = vTransform[i].lock()) // not expired { sp->x += 3; sp->y += 7; std::cout << sp->x << ", " << sp->y << std::endl; } else // component removed, swap - pop_back { std::swap(vTransform[i--], vTransform.back()); vTransform.pop_back(); } } } }; class GameObject; typedef std::shared_ptr<GameObject> sp_GameObject; class SceneManager { private: std::unique_ptr<PhysicsSystem> psys; std::unique_ptr<RenderSystem> rsys; public: SceneManager() { psys = std::make_unique<PhysicsSystem>(); rsys = std::make_unique<RenderSystem>(); } sp_GameObject CreateObject() { return std::make_shared<GameObject>(this); } template < typename T > void EnqueueComponent(T t) { } // do nothing void Update() { psys->Update(); rsys->Update(); } }; template <> // specialization for Renderable void SceneManager::EnqueueComponent<sp_Renderable>(sp_Renderable t) { rsys->AddRenderable(t); } template <> // specialization for Transform void SceneManager::EnqueueComponent<sp_Transform>(sp_Transform t) { psys->AddTransform(t); } class GameObject { SceneManager* smgr; std::unordered_map<std::size_t, std::shared_ptr<Component>> components; public: GameObject(SceneManager* s) : smgr(s) {} template < typename C, typename... Args > void AddComponent(Args&&... args) { assert("Already have that component!" && components.count(type_id<C>()) == 0); auto c = std::make_shared<C>(std::forward<Args>(args)...); smgr->EnqueueComponent(c); components.insert({ type_id<C>(), c }); } template < typename C > bool HaveComponent() { return components.count(type_id<C>()) != 0; } template <typename C> std::shared_ptr<C> GetComponent() { assert("No such component!" && HaveComponent<C>()); return std::static_pointer_cast<C>(components[type_id<C>()]); } template <typename C> void RemoveComponent() { components.erase(type_id<C>()); } }; int main() { auto s = std::make_unique<SceneManager>(); auto o1 = s->CreateObject(); o1->AddComponent<Transform>(5, 9); o1->AddComponent<Renderable>("Hello obj1!"); auto o2 = s->CreateObject(); o2->AddComponent<Transform>(11, 22); o2->AddComponent<Renderable>("Hello obj2!"); //auto z = o1->GetComponent<Other>(); // error //auto r = o1->GetComponent<Renderable>(); //auto p = o1->GetComponent<Transform>(); s->Update(); o1->RemoveComponent<Transform>(); s->Update(); return 0; } Znaci imam GameObject koji sadrzi listu unikatnih komponenti koristeci unordered_map, gde je key size_t tip (koristeci type_id funkciju iz navedenog treda) a value je shared_ptr Component (bazna klasa svih komponenti), dodavanje/pristup komponenti bi trebalo biti veoma efikasno. Onda imam "sisteme" koji operisu na specificnim komponentama (RenderSystem, PhysicsSystem...) i SceneManager koji azurira ove sisteme i kreira objekte. final kljucnu rec na izvedene klase sam koristio jer sam cuo da moze biti hint kompajleru da uradi devirtualizaciju a i ne ocekujem neko daljnje nasledjivanje. Ne svidja mi se sto sam morao da embedujem pokazivac na SceneManager u sam GameObject jer moram nekako da ubacim komponente i u sisteme, a ne bih da menjam "sintaksu" koriscenja ovog sistema. Da li vidite neki fejl u kodu, da li ste radili nesto slicno, imate neke predloge? Posto sam radio u VS 2013 okruzenju, a zna se da VS nije uvek u saglasnosti sa c++ standardom, moze da se desiti da kod ne bude radio sa drugim kompajlerima. |
Bookmarks sajtovi |
Alatke vezane za temu | |
Vrste prikaza | |
|
|
Slične teme | ||||
tema | temu započeo | forum | Odgovora | Poslednja poruka |
Avioni | Dr Zoidberg | Brbljaonica | 3931 | 17.4.2022 21:11 |
Laptop HP dv3600 nece da podigne sistem | igor7 | Prenosni računari | 10 | 2.4.2014 19:37 |
Ne mogu da biram koji sistem | BMWM5 | Kvarovi | 2 | 16.9.2010 19:40 |
Upomoc, ljudi, sistem mi je nacisto odlepio! | Fibonacci | Kvarovi | 7 | 16.9.2010 12:04 |
Opera mi ubi sistem | Monk Psycho | Operativni sistemi | 12 | 12.3.2006 5:09 |