Jump to content
  • Advertisement
suliman

C++ Using pointers and id for referencing game objects?

Recommended Posts

Hi

Im making a city builder/simulation game where a building can house up to 15 units. Units and buildings are located in a list (std::list <unit> unitList). 

They need to keep track of eachother (the building: which units live here, how many free slots do I have) (unit: where do I live, where do i work, is workplace full of resources, is food missing at home etc).

Pointers between these is quicker but seems unreliable. Also, when I load/save the game i need to do same special handling of the pointers.

The other idea is to just save the IDs of the building/units. IDs are unique so a ID relates to a single unit/building. But then each time I need to find the units inside a building or whatever i need to getUnitFromID(myID) and use that function to loop through the entire list of objects and return the correct one. Might be slow with hundreds of objects looking for other object all the time.

Or a combination? Or something completely else?
Thanks!
Erik

Share this post


Link to post
Share on other sites
Advertisement
24 minutes ago, suliman said:

Im making a city builder/simulation game where a building can house up to 15 units. Units and buildings are located in a list (std::list <unit> unitList). 

First of, you'd probably not want to have an std::list, but rather an std::vector. While lists technically have some benefits over (dynamic) arrays, in practice their non-linear memory layout makes them really imperformant for anything but removing an object by its list-node (when do you have that anyways?). I'd go for a vector by default any time unless you have very specific needs that justify a list.

27 minutes ago, suliman said:

Pointers between these is quicker but seems unreliable. Also, when I load/save the game i need to do same special handling of the pointers.

How are pointers unreliable? The only point where they should become invalid is when eigther a unit or building is destroyed, but you can simply notify the other connected entities to let them know when that happens. Otherwise, if you still feel they are unsafe, you could use a smart-pointer like std::shared_ptr/std::weak_ptr. They impose some overhead over raw points, but those are neglectible for what you need.

29 minutes ago, suliman said:

The other idea is to just save the IDs of the building/units. IDs are unique so a ID relates to a single unit/building. But then each time I need to find the units inside a building or whatever i need to getUnitFromID(myID) and use that function to loop through the entire list of objects and return the correct one. Might be slow with hundreds of objects looking for other object all the time.

Or a combination? Or something completely else?

I personally use a combination of both: pointers for storing stuff at runtime, and for serialization, write the entities unqiue ID, and later on loadup just make a one-time lookup by that ID to reaquire the pointer. Other people just save the pointer and modulate it at runtime to point to the correct entity, but that probably requires some advanced memory management to work (I belive, havn't tried it myself). Also, its totally possible, and can even have significant benefits to store a handle/ID instead of a pointer, as it allows you ie. to switch out the entire object, makes the case of deleting entities easier, etc...

So I couldn't give you a clear "do this, do that" answer - since there isn't really a clear best-way. I hope I still gave you some ideas that help you choose what to do.

 

Share this post


Link to post
Share on other sites

it did, thanks. I might just use pointers and lookup by ID when saving/loading.

But isnt a list better when I remove objects from the middle? (such as when i destroy buildings or kill units). I always add to the end though. Otherwise I loop through them alot so thats important for speed.

Both buildings and units are somethat large classes with lots of members. Would that make lists a better option?

Share this post


Link to post
Share on other sites
55 minutes ago, suliman said:

But isnt a list better when I remove objects from the middle? (such as when i destroy buildings or kill units). I always add to the end though. Otherwise I loop through them alot so thats important for speed.

Well, it depends. Do you have the list-node ready when you remove from the middle? Otherwise, you have to search for it first, which is way slower in a list. Also, while remove from the node is O(1) and from vector is O(N) for the worst case, there exists a pattern for arrays called erase & swap, where you put the last element to the position of the one you erased, making it O(1) as well. So I'd say, specially if you need to loop through a lot like you said, there's really no reason to use a list for you :)

55 minutes ago, suliman said:

Both buildings and units are somethat large classes with lots of members. Would that make lists a better option?

Nope, doesn't make a difference in your case - since you are storing the pointer, which is always equally large regardless of what you actually store. If you were to store large classes by value, which can't take advantage of move-semantics/can't use C++11, and you can't use erase&swap, then yeah, theoretically lists would gain some advantage. Though, unless you erase/insert more then you actually iterate (which i find doubtful for most cases, its still not worth thinking about).

Share this post


Link to post
Share on other sites

In many large games it is somewhat common to use a placeholder object, a proxy for the real thing that will never move and never become invalid over the course of the game.  Inside the various systems the real object can be present and the proxy object forwards everything to the real object, or the object can be unloaded and a placeholder object is used.  In debug builds the placeholder is something obvious like a huge box or a rapid spinning animation or a checkerboard hot pink texture, something that lets people know the placeholder is being used. In release builds the placeholder is something that can still be manipulated but isn't distracting like a small cube, or a static animation, or a light gray texture.  This also avoids issues with null pointers or missing objects because there is ALWAYS something there, even if it is just the placeholder object or an "error object".

When external systems are involved I love using constant IDs. The ID can remain the same all through development, be used by tools outside the game as well as all the systems within the game. You need to follow careful practices that IDs are never reused and each one is fully identified, but they are very fast to work with, small, and never change, making them ideal for most purposes.  There are usually few drawbacks for working with IDs. If you want to convert an ID to a pointer that is easy enough, even if you've got 10,000 IDs you can maintain a simple array of pointers for about 40KB or 80KB. That gives instant lookup to convert an ID to pointer, and less than a half microsecond to look up an ID by pointer (if it wasn't in the object already).

Your concerns about searching through hundreds of objects are probably not a concern. The CPU is amazingly good at identifying linear searches and will prefetch the data so the search is near instant.  For many data types and classes it is faster to do a linear search than a binary search even when there are thousands of items in the collection. A binary search may only hit 13 items where the linear search will average around 2500 items, but thanks to cache effects the linear search may require 200 nanoseconds versus 400 nanoseconds to jump around for the binary search, and while it requires thousands of times more effort, even a worst-case linear search is still on par with the time required for a binary search.

Share this post


Link to post
Share on other sites
10 hours ago, Juliean said:

Do you have the list-node ready when you remove from the middle?

I dont understand this. I just remove whatever unit needs to be removed. I create units at other times, and these are always added to the end of the list : "unitList.push_back(unit());"

 

10 hours ago, Juliean said:

Nope, doesn't make a difference in your case - since you are storing the pointer, which is always equally large regardless of what you actually store.

Lets be clear: you are talking about storing the "which 15 guys live inside this house" as pointers right? I better store them as non-pointers in the main list right?

Also can I really use vector for the "main" collection? If i want to use pointers to these and remove some, wouldnt that corrupt the pointers set to others in the vector? Wouldnt many of them need to be moved  in memory often if I have a vector of 500+ units and start to remove some of them from somewhere in the middle of the vector? While this wouldnt be a problem in a list right?

Thanks for the help!

Edited by suliman

Share this post


Link to post
Share on other sites

std::list is almost never the correct structure to use.

If you store pointers in the vector, then you can delete them from the vector and all your other pointers in the program will still work fine. You have to delete the object itself separately, and ensure there are no pointers to it elsewhere.

If you store objects in the pointer, then sure, when you delete objects from it, pointers to any object in the vector will break.

I'm pretty sure we covered - or at least touched upon - some of this in your other thread: https://www.gamedev.net/forums/topic/690589-debug-assertion-failure-c/ . Note that an iterator, in vector terms, is basically a pointer, and the same rules apply.

As a general rule of thumb, when objects need to be aware of each other, try to do this with the minimum number of pointers and data structures. Sometimes this will mean having to iterate over a structure to find something by name or ID instead of having a direct pointer - but it will save you a lot of grief in terms of not having to meticulously keep all these references valid and synchronised.

And for the other situations, I'd suggest becoming familiar with std::shared_ptr and std::weak_ptr. Weak_ptr is perfect for times when you feel that you need a pointer to something, but will find it awkward to update that pointer if the target gets destroyed. Weak_ptr handles that situation for you by automatically clearing itself when the object is destroyed.

 

Share this post


Link to post
Share on other sites
1 hour ago, suliman said:

I dont understand this. I just remove whatever unit needs to be removed. I create units at other times, and these are always added to the end of the list : "unitList.push_back(unit());"

Yeah, forget that part. I was thinking about a special list implementation we used at work, std::list probaby doesn't support this. Which only furthers my point, because deleting from a list by "removing whathever unit needs to be removed" is way slower than in a vector for most cases since you have to find which position to erase at.

1 hour ago, suliman said:

Lets be clear: you are talking about storing the "which 15 guys live inside this house" as pointers right? I better store them as non-pointers in the main list right?

Yeah, I was talking about that.

1 hour ago, suliman said:

Also can I really use vector for the "main" collection? If i want to use pointers to these and remove some, wouldnt that corrupt the pointers set to others in the vector? Wouldnt many of them need to be moved  in memory often if I have a vector of 500+ units and start to remove some of them from somewhere in the middle of the vector? While this wouldnt be a problem in a list right?

If you intent to store pointers to the objects, then you also have to store them as pointers in the main list, otherwise the pointers will become invalide when the vector has to interally grow in size, or you delete from a certain element. So your main list would become:

std::vector<std::unique_ptr<Object>> vObjects;

If you're not familiar with std::unique_ptr, get familiar with it ;) Otherwise you could also use smart-pointers as discussed.

As for the need to move objects in memory on removal, if you store pointers it doesn't matter. In C++11 with move-semantics, moving objects probably also doesn't matter that much (previously, you'd have to deep-copy objects around the vector). Otherwise, there is still the erase & swap-idiom that I mentioned:

auto itr = std::find(vObjects.begin(), vObjects.end(), object);

*itr = std::move(vObjects.back()); // instead of erasing, copy/move last object to this slot
vObjects.pop_back(); // then, remove the last object

If you do this, then there literally is no advantage to a list anymore whatsoever. The only downside is that you cannot do that if order is important (which it shouldn't in your case).

Share this post


Link to post
Share on other sites

I'll try to take all of this in:) Thanks!

I actually used <*unit> and iterators so I could delete the "loose" object. But I always though this handling was kinda messy.

So basically i COULD use a LISTof non-pointers (as my main collection) and pointers to these wouldnt be invalidated when I add/delete? It would however be slower that using a vector for looping through and such. If using a vector the pointers would be invalidated on add/delete (unless using <*unit> instead of <unit>). Is this correct?

Share this post


Link to post
Share on other sites

Yes, if you have a std::list<Whatever>, and your list has objects A, B, and C, then removing object B from the list will destroy object B, and preserve pointers and iterators to objects A and C.

Obviously you still need to make sure that anything else that refers to B is informed that the object has now gone, or is forced to access the object via a look-up that can also confirm the object is now gone. (e.g. iterate through the list, looking it up by ID.) There are a few ways you can 'delete the loose object' and that's actually the easy part - the hard part is maintaining all the other refererences. After all, if you're so sure that you need to preserve pointers or iterators to objects A and C when deleting B, that implies that there are probably pointers and iterators to B in your system as well.

And yes, it is a bit slower to iterate through a std::list than a std::vector, especially when the number of things you're iterating through is going up towards the hundreds or thousands.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
  • Advertisement
  • Popular Tags

  • Similar Content

    • By Andrew Parkes
      I am a talented 2D/3D artist with 3 years animation working experience and a Degree in Illustration and Animation. I have won a world-wide art competition hosted by SFX magazine and am looking to develop a survival game. I have some knowledge of C sharp and have notes for a survival based game with flexible storyline and PVP. Looking for developers to team up with. I can create models, animations and artwork and I have beginner knowledge of C sharp with Unity. The idea is Inventory menu based gameplay and is inspired by games like DAYZ.
      Here is some early sci-fi concept art to give you an idea of the work level. Hope to work with like minded people and create something special. email me andrewparkesanim@gmail.com.
      Developers who share the same passion please contact me, or if you have a similar project and want me to join your team email me. 
      Many thanks, Andrew.

    • By mike44
      Hi
      saw in dependency walker that my app still needs msvcp140d.dll even after disabling debug.
      What did I forget in the VS2017 release settings? After setting to multithreaded dll I get linker errors.
      Thanks
       
    • By 3dmodelerguy
      So I have been playing around with yaml-cpp as I want to use YAML for most of my game data files however I am running into some pretty big performance issues and not sure if it is something I am doing or the library itself.
      I created this code in order to test a moderately sized file:
      Player newPlayer = Player(); newPlayer.name = "new player"; newPlayer.maximumHealth = 1000; newPlayer.currentHealth = 1; Inventory newInventory; newInventory.maximumWeight = 10.9f; for (int z = 0; z < 10000; z++) { InventoryItem* newItem = new InventoryItem(); newItem->name = "Stone"; newItem->baseValue = 1; newItem->weight = 0.1f; newInventory.items.push_back(newItem); } YAML::Node newSavedGame; newSavedGame["player"] = newPlayer; newSavedGame["inventory"] = newInventory; This is where I ran into my first issue, memory consumption.
      Before I added this code, the memory usage of my game was about 22MB. After I added everything expect the YAML::Node stuff, it went up to 23MB, so far nothing unexpected. Then when I added the YAML::Node and added data to it, the memory went up to 108MB. I am not sure why when I add the class instance it only adds like 1MB of memory but then copying that data to a YAML:Node instance, it take another 85MB of memory.
      So putting that issue aside, I want want to test the performance of writing out the files. the initial attempt looked like this:
      void YamlUtility::saveAsFile(YAML::Node node, std::string filePath) { std::ofstream myfile; myfile.open(filePath); myfile << node << std::endl; myfile.close(); } To write out the file (that ends up to be about 570KB), it took about 8 seconds to do that. That seems really slow to me.
      After read the documentation a little more I decide to try a different route using the YAML::Emitter, the implemntation looked like this:
      static void buildYamlManually(std::ofstream& file, YAML::Node node) { YAML::Emitter out; out << YAML::BeginMap << YAML::Key << "player" << YAML::Value << YAML::BeginMap << YAML::Key << "name" << YAML::Value << node["player"]["name"].as<std::string>() << YAML::Key << "maximumHealth" << YAML::Value << node["player"]["maximumHealth"].as<int>() << YAML::Key << "currentHealth" << YAML::Value << node["player"]["currentHealth"].as<int>() << YAML::EndMap; out << YAML::BeginSeq; std::vector<InventoryItem*> items = node["inventory"]["items"].as<std::vector<InventoryItem*>>(); for (InventoryItem* const value : items) { out << YAML::BeginMap << YAML::Key << "name" << YAML::Value << value->name << YAML::Key << "baseValue" << YAML::Value << value->baseValue << YAML::Key << "weight" << YAML::Value << value->weight << YAML::EndMap; } out << YAML::EndSeq; out << YAML::EndMap; file << out.c_str() << std::endl; } While this did seem to improve the speed, it was still take about 7 seconds instead of 8 seconds.
      Since it has been a while since I used C++ and was not sure if this was normal, I decided to for testing just write a simple method to manually generate the YAMLin this use case, that looked something like this:
      static void buildYamlManually(std::ofstream& file, SavedGame savedGame) { file << "player: \n" << " name: " << savedGame.player.name << "\n maximumHealth: " << savedGame.player.maximumHealth << "\n currentHealth: " << savedGame.player.currentHealth << "\ninventory:" << "\n maximumWeight: " << savedGame.inventory.maximumWeight << "\n items:"; for (InventoryItem* const value : savedGame.inventory.items) { file << "\n - name: " << value->name << "\n baseValue: " << value->baseValue << "\n weight: " << value->weight; } } This wrote the same file and it took about 0.15 seconds which seemed a lot more to what I was expecting.
      While I would expect some overhead in using yaml-cpp to manage and write out YAML files, it consuming 70X+ the amount of memory and it being 40X+ slower in writing files seems really bad.
      I am not sure if I am doing something wrong with how I am using yaml-cpp that would be causing this issue or maybe it was never design to handle large files but was just wondering if anyone has any insight on what might be happening here (or an alternative to dealing with YAMLin C++)?
    • By 3dmodelerguy
      So I am trying to using Yaml as my game data files (mainly because it support comments, is a bit easier to read than JSON, and I am going to be working in these files a lot) with C++ and yaml-cpp (https://github.com/jbeder/yaml-cpp) seems like the most popular library for dealing with it however I am running into an issue when using pointers.
      Here is my code:
      struct InventoryItem { std::string name; int baseValue; float weight; }; struct Inventory { float maximumWeight; std::vector<InventoryItem*> items; }; namespace YAML { template <> struct convert<InventoryItem*> { static Node encode(const InventoryItem* inventoryItem) { Node node; node["name"] = inventoryItem->name; node["baseValue"] = inventoryItem->baseValue; node["weight"] = inventoryItem->weight; return node; } static bool decode(const Node& node, InventoryItem* inventoryItem) { // @todo validation inventoryItem->name = node["name"].as<std::string>(); inventoryItem->baseValue = node["baseValue"].as<int>(); inventoryItem->weight = node["weight"].as<float>(); return true; } }; template <> struct convert<Inventory> { static Node encode(const Inventory& inventory) { Node node; node["maximumWeight"] = inventory.maximumWeight; node["items"] = inventory.items; return node; } static bool decode(const Node& node, Inventory& inventory) { // @todo validation inventory.maximumWeight = node["maximumWeight"].as<float>(); inventory.items = node["items"].as<std::vector<InventoryItem*>>(); return true; } }; } if I just did `std::vector<InventoryItem> items` and had the encode / decode use `InventoryItem& inventoryItem` everything works fine however when I use the code above that has it as a pointer, I get the following error from code that is part of the yaml-cpp library:
      impl.h(123): error C4700: uninitialized local variable 't' used The code with the error is:
      template <typename T> struct as_if<T, void> { explicit as_if(const Node& node_) : node(node_) {} const Node& node; T operator()() const { if (!node.m_pNode) throw TypedBadConversion<T>(node.Mark()); T t; if (convert<T>::decode(node, t)) // NOTE: THIS IS THE LINE THE COMPILER ERROR IS REFERENCING return t; throw TypedBadConversion<T>(node.Mark()); } }; With my relative lack of experience in C++ and not being able to find any documentation for yaml-cpp using pointers, I am not exactly sure what is wrong with my code.
      Anyone have any ideas what I need to change with my code? 
    • By Gnollrunner
      I already asked this question on stack overflow, and they got pissed at me, down-voted me and so forth, LOL .... so I'm pretty sure the answer is NO, but I'll try again here anyway just in case..... Is there any way to get the size of a polymorphic object at run-time? I know you can create a virtual function that returns size and overload it for each child class, but I'm trying to avoid that since (a) it takes a virtual function call and I want it to be fast and (b) it's a pain to have to include the size function for every subclass. I figure since each object has a v-table their should be some way since the information is there, but perhaps there is no portable way to do it.
    • By MarcusAseth
      This is the code I have:
       //Create Window     DWORD windowStyle = WS_VISIBLE;     DWORD windowExStyle = WS_EX_OVERLAPPEDWINDOW;     SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_SYSTEM_AWARE);     RECT client{ 0, 0, 100, 40 };     UINT dpi = GetDpiForSystem();     AdjustWindowRectExForDpi(&client, windowStyle, false, windowExStyle, dpi);     UINT adjustedWidth = client.right - client.left;     UINT adjustedHeight = client.bottom - client.top;     m_hwnd = CreateWindowEx(windowExStyle,                             className.c_str(),                             windowName.c_str(),                             windowStyle,                             CW_USEDEFAULT,                             CW_USEDEFAULT,                             adjustedWidth,                             adjustedHeight,                             nullptr,                             nullptr,                             m_hInstance,                             m_emu     ); The generated window has a client area of 1 pixel in height, even though I'm asking for 40. so I'm always getting 39 pixel less than what I need...can someone help me with this? x_x
    • By SeraphLance
      I've spent quite a while (and probably far longer than I actually should) trying to design an allocator system.  I've bounced ideas around to various people in the past, but never really gotten something satisfactory.
      Basically, the requirements I'm trying to target are:
        Composability -- allocators that seamlessly allocate from memory allocated by other allocators.  This helps me to do things like, for example, write an allocator that pads allocations from its parent allocator with bit patterns to detect heap corruption.  It also allows me to easily create spillovers, or optionally assert on overflow with specialized fallbacks.   Handling the fact that some allocators have different interfaces than others in an elegant way.  For example, a regular allocator might have Allocate/Deallocate, but a linear allocator can't do itemized deallocation (but can deallocate everything at once).   I want to be able to tell how much I've allocated, and how much of that is actually being used.  I also want to be able to bucket that on subsystem, but as far as I can tell, that doesn't really impact the design outside of adding a new parameter to allocate calls. Note:  I'm avoiding implementation of allocation buckets and alignment from this, since it's largely orthogonal to what I'm asking and can be done with any of the designs.
       
      To meet those three requirements, I've come up with the following solutions, all of which have significant drawbacks.
      Static Policy-Based Allocators
      I originally built this off of this talk.
      Examples;
      struct AllocBlock { std::byte* ptr; size_t size; }; class Mallocator { size_t allocatedMemory; public: Mallocator(); AllocBlock Allocate(size_t size); void Deallocate(AllocBlock blk); }; template <typename BackingAllocator, size_t allocSize> class LinearAllocator : BackingAllocator { AllocBlock baseMemory; char* ptr; char* end; public: LinearAllocator() : baseMemory(BackingAllocator::Allocate(allocSize)) { /* stuff */ } AllocBlock Allocate(size_t size); }; template <typename BackingAllocator, size_t allocSize> class PoolAllocator : BackingAllocator { AllocBlock baseMemory; char* currentHead; public: PoolAllocator() : baseMemory(BackingAllocator::Allocate(allocSize)) { /* stuff */ } void* Allocate(); // note the different signature. void Deallocate(void*); }; // ex: auto allocator = PoolAllocator<Mallocator, size>; Advantages:
      SFINAE gives me a pseudo-duck-typing thing.  I don't need any kind of common interfaces, and I'll get a compile-time error if I try to do something like create a LinearAllocator backed by a PoolAllocator. It's composable. Disadvantages:
      Composability is type composability, meaning every allocator I create has an independent chain of compositions.  This makes tracking memory usage pretty hard, and presumably can cause me external fragmentation issues.  I might able to get around this with some kind of singleton kung-fu, but I'm unsure as I don't really have any experience with them. Owing to the above, all of my customization points have to be template parameters because the concept relies on empty constructors.  This isn't a huge issue, but it makes defining allocators cumbersome. Dynamic Allocator Dependency
      This is probably just the strategy pattern, but then again everything involving polymorphic type composition looks like the strategy pattern to me. 😃
      Examples:
      struct AllocBlock { std::byte* ptr; size_t size; }; class Allocator { virtual AllocBlock Allocate(size_t) = 0; virtual void Deallocate(AllocBlock) = 0; }; class Mallocator : Allocator { size_t allocatedMemory; public: Mallocator(); AllocBlock Allocate(size_t size); void Deallocate(AllocBlock blk); }; class LinearAllocator { Allocator* backingAllocator; AllocBlock baseMemory; char* ptr; char* end; public: LinearAllocator(Allocator* backingAllocator, size_t allocSize) : backingAllocator(backingAllocator) { baseMemory = backingAllocator->Allocate(allocSize); /* stuff */ } AllocBlock Allocate(size_t size); }; class PoolAllocator { Allocator* backingAllocator; AllocBlock baseMemory; char* currentHead; public: PoolAllocator(Allocator* backingAllocator, size_t allocSize) : backingAllocator(backingAllocator) { baseMemory = backingAllocator->Allocate(allocSize); /* stuff */ } void* Allocate(); // note the different signature. void Deallocate(void*); }; // ex: auto allocator = PoolAllocator(someGlobalMallocator, size); There's an obvious problem with the above:  Namely that PoolAllocator and LinearAllocator don't inherit from the generic Allocator interface.  They can't, because their interfaces provide different semantics.  There's to ways I can solve this:
        Inherit from Allocator anyway and assert on unsupported operations (delegates composition failure to runtime errors, which I'd rather avoid).   As above:  Don't inherit and just deal with the fact that some composability is lost (not ideal, because it means you can't do things like back a pool allocator with a linear allocator) As for the overall structure, I think it looks something like this:
      Advantages:
      Memory usage tracking is easy, since I can use the top-level mallocator(s) to keep track of total memory allocated, and all of the leaf allocators to track of used memory.  How to do that in particular is outside the scope of what I'm asking about, but I've got some ideas. I still have composability Disadvantages:
      The interface issues above.  There's no duck-typing-like mechanism to help here, and I'm strongly of the opinion that programmer errors in construction like that should fail at compile-time, not runtime. Composition on Allocated Memory instead of Allocators
      This is probably going to be somewhat buggy and poorly thought, since it's just an idea rather than something I've actually tried.
      Examples:
      struct AllocBlock { void* ptr; size_t size; std::function<void()> dealloc; } class Mallocator { size_t allocatedMemory; public: Mallocator(); AllocBlock Allocate(size_t size) { void* ptr = malloc(size); return {ptr, size, [ptr](){ free(ptr); }}; } }; class LinearAllocator { AllocBlock baseMemory; char* ptr; char* end; public: LinearAllocator(AllocBlock baseMemory) : baseMemory(baseMemory) {end = ptr = baseMemory.ptr;} AllocBlock Allocate(size_t); }; class PoolAllocator { AllocBlock baseMemory; char* head; public: PoolAllocator(AllocBlock baseMemory) : baseMemory(baseMemory) { /* stuff */ } void* Allocate(); }; // ex: auto allocator = PoolAllocator(someGlobalMallocator.Allocate(size)); I don't really like this design at first blush, but I haven't really tried it.

      Advantages:
      "Composable", since we've delegated most of what composition entails into the memory block rather than the allocator. Tracking memory is a bit more complex, but I *think* it's still doable. Disadvantages:
      Makes the interface more complex, since we have to allocate first and then pass that block into our "child" allocator. Can't do specialized deallocation (i.e. stack deallocation) since the memory blocks don't know anything about their parent allocation pool.  I might be able to get around this though.  
      I've done a lot of research against all of the source-available engines I can find, and it seems like most of them either have very small allocator systems or simply don't try to make them composable at all (CryEngine does this, for example).  That said, it seems like something that should have a lot of good examples, but I can't find a whole lot.  Does anyone have any good feedback/suggestions on this, or is composability in general just a pipe dream?
    • By RobMaddison
      Hi
      I’ve been working on a game engine for years and I’ve recently come back to it after a couple of years break.  Because my engine uses DirectX9.0c I thought maybe it would be a good idea to upgrade it to DX11. I then installed Windows 10 and starting tinkering around with the engine trying to refamiliarise myself with all the code.
      It all seems to work ok in the new OS but there’s something I’ve noticed that has caused a massive slowdown in frame rate. My engine has a relatively sophisticated terrain system which includes the ability to paint roads onto it, ala CryEngine. The roads are spline curves and built up with polygons matching the terrain surface. It used to work perfectly but I’ve noticed that when I’m dynamically adding the roads, which involves moving the spline curve control points around the surface of the terrain, the frame rate comes to a grinding halt.
      There’s some relatively complex processing going on each time the mouse moves - the road either side of the control point(s) being moved, is reconstructed in real time so you can position and bend the road precisely. On my previous OS, which was Win2k Pro, this worked really smoothly and in release mode there was barely any slow down in frame rate, but now it’s unusable. As part of the road reconstruction, I lock the vertex and index buffers and refill them with the new values so my question is, on windows 10 using DX9, is anyone aware of any locking issues? I’m aware that there can be contention when locking buffers dynamically but I’m locking with LOCK_DISCARD and this has never been an issue before.
      Any help would be greatly appreciated.
    • By LukeCassa005
      I'm writing a small 3D Vulkan game engine using C++. I'm working in a team, and the other members really don't know almost anything about C++. About three years ago i found this new programming language called D wich seems very interesting, as it's very similar to C++. My idea was to implement core systems like rendering, math, serialization and so on using C++ and then wrapping all with a D framework, easier to use and less complicated. Is it worth it or I should stick only to C++ ? Does it have less performance compared to a pure c++ application ?
    • By MarcusAseth
      Hi guys, I'm trying to learn this stuff but running into some problems 😕
      I've compiled my .hlsl into a header file which contains the global variable with the precompiled shader data:
      //... // Approximately 83 instruction slots used #endif const BYTE g_vs[] = { 68, 88, 66, 67, 143, 82, 13, 236, 152, 133, 219, 113, 173, 135, 18, 87, 122, 208, 124, 76, 1, 0, 0, 0, 16, 76, 0, 0, 6, 0, //.... And now following the "Compiling at build time to header files" example at this msdn link , I've included the header files in my main.cpp and I'm trying to create the vertex shader like this:
      hr = g_d3dDevice->CreateVertexShader(g_vs, sizeof(g_vs), nullptr, &g_d3dVertexShader); if (FAILED(hr)) { return -1; } and this is failing, entering the if and returing -1.
      Can someone point out what I'm doing wrong? 😕 
  • Advertisement
  • Popular Now

  • Forum Statistics

    • Total Topics
      631360
    • Total Posts
      2999554
×

Important Information

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

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!