Jump to content
  • Advertisement

hyyou

Member
  • Content Count

    60
  • Joined

  • Last visited

Everything posted by hyyou

  1. Thank Julien. In a more real case, I structure it like this :- rocket = HP + physic_owner + graphic_owner + .... Physic body = physic_ownee + bulletBodyAndShape_holder + cache_physicAttr(pos,v,gravity,mass,mask) + ... Graphic body = graphic_ownee + ogreBody_holder (Ogre2.1 graphic body) + cache_renderAttribute(pos,blend_mode,layer) + mesh_owner mesh = mesh_ownee + filename + ogreMeshPtr(point to vertex buffer) The physic_owner / graphic_owner / physic_ownee / graphic_ownee are just attach-point. If I want to create a rocket, I tend to create 1 rocket entity attach to 2-3 new physic body, 2-3 new graphic body. The graphic body attach to a shared mesh. Thus, for a single rocket, I create around 5-7 entities. I copied the idea from https://gamedev.stackexchange.com/questions/31888/in-an-entity-component-system-engine-how-do-i-deal-with-groups-of-dependent-ent , not sure if it smells. ... For me, it works pretty good, but I may overlook something. P.S. Your comment in another topic of mine boosted my engine's overall performance by 5%. Thank a lot. That is enlightening, thank. @0r0d You are right. I have edited the post
  2. I have recently read T-machine's Entity Component System (ECS) data structure. (link) Its "best" version (4th iteration) can be summarized into a single image (copy from T-machine's web) :- This approach also appears in a VDO , with slide and source code ( https://github.com/CppCon/CppCon2015/tree/master/Tutorials/Implementation of a component-based entity system in modern C++ ) . There are many people (including me) believe that the above approach lacks data locality, because Position-1,Position-2,Position-3, ... are not stored in a contiguous array. However, many attempts failed to elegantly make it contiguous. (e.g. stackoverflow's link) I also realized that, to make it contiguous, the cost of query Entity<-->Component is unavoidably significantly higher. (I profiled) I would like to hear that .... Is such mega-array (T-machine's 4th) generally better (performance-wise) than storing each type component to its own contiguous array? (like http://www.randygaul.net/2013/05/20/component-based-engine-design/ ) ? My references (those links) are quite old. Now, are there any others better approaches? (If you happen to know) I know that its depend on data access pattern (i.e. cache miss). I still want to hear more opinion/argument about it, because I may need to rewrite a large part of my engine to make it support 30,000+ entity (personal greed). Thank.
  3. I improved my engine from 3->2, and got performance boost ~60%. Thank!! Do you generally pass entity around as (1) an entity OR (2) a component pointer? The first is more flexible approach, but query "entity->component pointer" costs me a lot. (need 2 distinct area) The second is less flexible. It need only 1 distinct area. Are there any other approaches? By the way, your posts help me a lot. Do you write some books? I've visited your website ( http://blog.ebonyfortress.com/), but find none. I agree with the whole post. Physic-Graphic pair that I mentioned is not a good example. In sometimes, I love to have this feature to easily get some performance boost from data locality. For example, in the last cycle of development, I may discover that 2 certain components are always access together. If an entity has one component, it always has the other one. The example (PhysicsSystemItem) is interesting. Thank. I took a look at it. Never know such thing exist. Thank.
  4. That would be very flexible and high performance at the same time. I believe it is possible by using template trick to notify (+custom type id manipulator) e.g. :- ECSUtility::setPlaceNearby<Component_graphic,Component_physic>() Sadly, I can't find any concrete example. .... It is not a trivial task.
  5. That is very insightful, thank a lot. It is so hard to find a weak milestone (of other engines - Unreal/Unity) to find how many generic entities an engine should support roughly. Yes, I agree that it is a serious trade-off. In theory, T-machine probably offers better performance when query inside every information of a single entity. However, I found out later that it is not so fast because of complexity of custom Assemblage.
  6. @Juliean Thank! It is consistent with the profiler result. I always thought that the profile result is wrong, because I use stack-allocator to allocate this as return result :- entities.WithComponents<Position>() Copying array shouldn't very expensive, right? I was wrong. Thank a lot, Juliean!!! If you didn't say it explicitly, I will ignore it .... perhaps forever.
  7. In my flawed prototype, I mixed both of them. Every entity is stored in a single array. Each and every entity must use less than 1024 bytes. In the stress test, I reserved it [Entity 1st=1024 bytes][2nd=1024]....[1024] = 30,000 contiguous block. Ex. In some bad cases, it can be :- Entity 1st= [Position 8 bytes][Velocity 16 bytes][ waste 1010 bytes ] Entity 2st= [GraphicHuge 524 bytes][Position 8 bytes][ waste 492 bytes ] .... There are some ways to optimize it (e.g. buddy allocator), but in nutshell, it is like that.
  8. hyyou

    Framework Design OOP vs Other

    it's chaos if every subsystem can access every other subsystem I am very interested in this statement, and would be very glad to hear the reason. Most part of my engine is divided like :- SystemRenderInternal SystemRenderForOgre SystemPhysicForUser SystemPhysicInternalFactory SystemPhysicContraintManager They can access each other freely via service pattern :- getService<ServiceRenderInternal>()->Update(); So far, I have around 100 systems+. I am so glad that they can access each other. I don't have any problem about it. Am I missing something? Is it about performance? If the reason is about encapsulation, I think the chaos can be alleviated mostly by careful thought e.g. minimize such call / draw diagram & verify if it make senses.
  9. The biggest problem can be (arguably) solved by using assemblage. https://gamedev.stackexchange.com/questions/58693/grouping-entities-of-the-same-component-set-into-linear-memory/58701#58701 However, this approach introduces a lot of inherent disadvantages : Micro memory management is needed harder to code hard to remove component lose some data locality of the same components pooling is less efficient at entity level entity type must be established before create it. I believed the most tempting performance advantage might be that every query inside a certain entity is very fast. However, my profiling result suggest that I was wrong again. Oh, I used ~2 weeks to appreciate and believe this fact (sad face)
  10. Because of curiosity + stubbornness, I converted my engine to use T-machine's approaches. Today, I find that T-machine's technique is slower by 2-3% for my game. It is a little depressing though from the fact that T-machine's is far more difficult to implement. Kylotan is absolutely correct. IMHO, it is very hard for ECS to reach 30,000 non-trivial entities (without multithread) while maintaining 60fps.
  11. I am considering to allocate most persistent data of my ECS framework on a one-frame allocator. To extend their life to exist on > 1 frame, I will need to copy it to another buffer. Initialization I create Buffer X and Y. Each has 50-300MB. 1st timestep : every Entity / Components will use buffer X to allocate. 1st-end : copy every Entity/Component that are not marked as deleted to buffer Y, clear X. 2st timestep : every Entity / Components will use buffer Y to allocate. 2st-end : copy every Entity/Component that are not marked as deleted to buffer X, clear Y. ... Advantage almost 0 fragmentation cost, pool is not needed anymore very low cache miss in game-logic Disadvantage high cost of memory swapping (X<-->Y 50-300 MB every timestep) Reason : computer can read or write memory at 10 GB/s = 170 MB/timestep (reference : https://stackoverflow.com/questions/25827416/ ) (minor) pointer become invalidated, I must use ID instead Note: Luckily, every components are POD (plain old data = no pointer as field). After some draft, it strongly believe it is possible to implement. Question Does it sound bad? Is it a good practice / technique? Is "ping-pong buffer" a correct name of this technique? What are other names?
  12. Thank a lot, swiftcoder, DvDmanDT and ApochPiQ. Your valuable knowledge save me several working days.
  13. I see the things that worry you. I believe you profiled it .... if not, you should do it before trying to optimize. If it is really a bottleneck of your game :- 1. Hash is too slow ? use sparse set Every entity may have its own unique ID : https://programmingpraxis.com/2012/03/09/sparse-sets/ Your game engine may need overhaul 2. Inserting / deleting causes too much ? try to optimize the data structure instead of trying to reduce inserting/deleting 3. Query every frame is too expensive ? AABB should be fast enough for the task if you deploy Octree appropriately. http://www.bulletphysics.org/mediawiki-1.5.8/index.php/BtDbvt_dynamic_aabb_tree https://en.wikipedia.org/wiki/Octree For me, cache miss always causes more CPU times than "often" hash-query.
  14. Thank a lot Hiwas, Shaarigan and Hodgman. Now I can sleep well again.
  15. I am using my own game/library/engine. use Bullet + Ogre3D use custom allocator in most places high modularity - a lot of independent classes ECS architecture it is well designed / decoupling (at least in my opinion) How hard to port PC game with in-house engine to console (e.g. nintendo switch, xbox one x, or even mobile)? Every site states that it takes 1 year to port PC game to nintendo switch if only I develop a game using Unreal/unity (not free). Should I make my custom game engine to support those console since the beginning? How? What design pattern/technique that I should adopt since beginning to make my PC game to be ported easily? What are difficulty to port? What type of features are hard to port? Where can I find more information about it? Reference (every site states the same thing):- http://www.cinemablend.com/games/1586130/why-porting-games-to-the-nintendo-switch-should-be-easy-according-to-nvidia http://www.tweaktown.com/news/56171/devs-easily-port-pc-games-nintendo-switch/index.html https://www.reddit.com/r/NintendoSwitch/comments/5rkmws/miyamoto_games_made_with_pc_as_a_base_can_be/
  16. Thank Shaarigan! In my case, it is a real in-house engine without network or multithread (yet). I don't mind if I have to refactoring some graphic / controller later. Mainly, I am afraid that the refactoring will become very deep into the game-logic. I doubt there are other such things (like custom allocator) that are really hard to adapt later, and I should concern about them at the beginning.
  17. Yes, it is a good way to learn new thing. I suggest you to search the one you like and apply to that team directly (with private message). As a general guideline, it is easier if .... You apply to the one that doesn't finish in producing any (successful) game yet. You don't pick a job. (i.e. don't mind about any language) You offer to do it for free. Doesn't forget to show your best game/prototype you develop yourself! Good luck.
  18. Thank a lot, Hiwas! That is very useful.
  19. It is totally reasonable and also enlightens me, thank!    What if the result value has some pointer inside? For example, it is a data-structure that may or may not the owner of the underlying data,  should I create 2 classes like this? :-    //old version template<class T>class CustomArray{ //type of return result unique_pointer<void*> database; //underlying data }; //new version template<class T>class WeakArray{ T* database; }; template<class T>class StrongArray{ unique_pointer_toArray<Bullet*> database;//just example }; //inside a function of some system WeakArray<Bullet> arr; arr.t = scopeAllocator->makeWeakArray<Bullet>(5);//similar as new Bullet[5]; return arr;
  20. As I know, tools for managing object lifetime are :-  std::unique_ptr std::move move constructor move assignment delete copy constructor delete copy assigment With those tools, it is very obvious to determine owner of any certain object - the owner is the one who stores std::unique_ptr as a field. However, it is obscure which class actually controls memory allocation. There are only few tools to help :- the second template parameter of std::unique_ptr the second template parameter of std::vector and other datastructure None of them indicate which instance of allocator is the ownership of such address. In a scope of class, it is alarming that underlying memory of a std::unique_ptr (that a class owns) can be deallocated any times. (e.g. from pop operation of scope allocators). std::unique_ptr<SomeThing> a=scopeAllocator->makeUnique<SomeThing>(); scopeAllocator->pop(); //memory of "a" is invalid! Are there any tools/techniques to help/prevent it, or at least make thing more obvious for coder?      
  21. Thank a lot Hodgman!  It sounds very nice.   How to make an allocator own the objects?    Should I cache them by void* and cache the correct deleter (function pointer) for each one?    If I understand correctly, any one-frame allocator should also return weak pointer. (?) i.e. are there any good practice to follow?     What if the return result is a bit obscure? template<class T>class CustomVector{     T* t;// }; class AISystem{ public: static CustomVector<NPC_ID> reportAllNearNPC(){ //use "scopeAllocator" to allocate "CustomVector::t" } }; CustomVector<NPC_ID> a=aiSystem->reportAllNearNPC(); scopeAllocator->pop(); //"a.t" become dangling pointer Your comment is very valuable - it is better than the chapter "allocator" in every C++ books I have read, thank! I desire to know more.  If it is not too much to ask, may you recommend name of some good books :D please?
  22. I am trying to develop a heap allocator that has following properties :- I will assign a contiguous memory chunk (begin-end address) to it. It will allocate using memory only in the assigned chunk. (not a property of std::allocator) I can ask it to allocate any size. If the chunk is not large enough / it is full, it will return null. reasonable performance (It is totally ok to be slower than poll, scope, linear allocators.) Something like this :-   HeapAllocator heap; void* beginByte=...; int numByte=...; heap.assignMemory(beginByte,numByte); .... int iWantNumByte=sizeof(SomeClass); void* iGetYou=heap.allocate(iWantNumByte); heap.deallocate(iGetYou); To avoid reinventing the wheel, here are such libraries I found :-    slow : http://jinie.github.io/memmgr/ (code at https://github.com/jinie/memmgr)  slow : http:// eli.thegreenplace.net/2008/10/17/memmgr-a-fixed-pool-memory-allocator/     (code at https://github.com/eliben/code-for-blog/tree/master/2008/memmgr) https://www.codeproject.com/Articles/14525/Heap-Manager-for-Allocating-Memory-from-a-Shared-M slow : https://www.gamedev.net/resources/_/technical/general-programming/c-custom-memory-allocation-r3010 As I skimmed the code :- 1 and 2 and 4 : cost max cost of allocate/deallocate = O(amountOfFreeBlock).  They are very easy to understand. 3 : cost =  O( log(amountOfFreeBlock))  The document is quite good, but it doesn't cover every aspect.  3 : also has a bug ( comment in that page) Are there more libraries that I can copy study?  Are there any good books/articles I should read?
  23. Bregma, thank for a good link to the so-satisfying big code. In my code, here is how I allocate/deallocate a new byte array (I do it without mutex).  ::operator new(numByte); ::operator delete(void_star_pointer); Is it the same as malloc()/alloc() you mentioned? (clarify) My prototype performance linear allocator is generally better than standard new/delete :- allocator->makeStrong<SomeClass>()   .... faster than ....... new SomeClass(). Is it partially because my class is not thread-safe comparing to new SomeClass()?
  24. Thank a lot, everyone, for good advises!   I found out later that even using std::map AND a lot of function pointer (my poor skill) to implement custom heap ->       an experimental custom heap allocator still faster than the standard new/delete!       (It is an evidence that it is somehow a premature optimizaton, as ninnghazad mentioned.)   I still want to know where should I read more / find more library though .... Thanks.  Does anyone know any others open source library?     It is interesting!   :D  I believe there is no guarantee how std::map allocated, so I think I can't adapt that concept, though.  
  25. Thank a lot, ninnghazad. Seeing an expert recommends that it usually does not cost too much (i.e. it is a premature optimization) make me clam down and start to seek for a solution which is a little more expensive but much easier-to-code.   Now, I can use std::multimap, then might optimize later.  :D
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!