Jump to content

  • Log In with Google      Sign In   
  • Create Account

Pink Horror

Member Since 02 Jul 2013
Offline Last Active Today, 06:11 PM

#5289641 Which alignment to use?

Posted by Pink Horror on 01 May 2016 - 05:28 PM

On problem I see though is that default-move-ctors will not properly move PoD values like integers, which means that sometimes classes will be left in an invalid state. Not so much a problem for containers, in fact I'm not sure how much of a problem that actually is. I decided to keep some explicit move-ctors specifically due to this, but I might need to evaluate it again.

What do you think is the "proper" way to move an integer?




#5289183 Which alignment to use?

Posted by Pink Horror on 28 April 2016 - 08:40 PM

 

Also, be very wary of the code your example indicates you might have. A vector is a _very bad_ choice for the backing store of a generalized memory pool as it can and will reallocate and move objects in memory, which can lead to all kinds of undefined behavior if your Component types are not strictly PODs (as in is_pod_v<Component> == true). The reason is that when the vector resizes, it thinks its just moving char's, which are trivial to move. A general class however might have a complex move constructor. Even a seemingly-simple class can end up having back-references (hidden ones inserted by the compiler!) that will fail to be updated and lead to all kinds of crashes or other nastiness. Although in this particular example, since your ComponentPool is a class templated parameterized over Component, it makes far more sense to just have a vector<Component> and let vector deal with alignment and all that jazz.

 

Even if they are PODs, the reallocation also invalidates all the pointers to the Components you've created.




#5287705 Should you load assets/resources at runtime or compiletime?

Posted by Pink Horror on 19 April 2016 - 06:54 PM

"Compile-time" loading, that is, embedding the resource into the executable, has the advantage of the resource always being available. There's no (reasonable) way for the asset to "not be there," so it's a good thing to use for very important, low-level assets, such as your default shaders, fallback "object not found" models and materials, et cetera. However, every resource you embed this way bloats the size of your executable, and they're hard to change or update, so you should use them sparingly and only for things that are very important.

 

"Runtime loading" is reading the assets from a file on the disk or elsewhere. These are way easier to update and patch and you can usually control the layout of the file better (or at least with less effort), which is useful for optimizing loading and patching. The downside is that the data can go missing relatively easily, so you have to have fallbacks or error handling in place.

 

Most of your data should probably be loaded at runtime. The advantages in control (and thus in perf) are significant. It's not true that "compile time loaded" data is faster at all. That's basically never the case in practice, especially if you're going to put all your data into the executable like that. It still gets read from the disk and if there's enough of it will get paged in and out just like anything else. Embed only the most critical of resources.

If you wanted to go nuts with building assets into executables instead of reading files, you could put them in DLLs. Then you can load and unload the assets and the code that goes along with them at run time. Each level could have its own DLL. However, I must say, this is probably a bad idea.

I can swear I've worked on some project where they had a DLL filled with nothing but assets, but I don't remember what it was.




#5287548 Optimizing Generation

Posted by Pink Horror on 18 April 2016 - 05:32 PM

Thanks. So, it's a class. I wonder if it could be a struct, or just a simple enum.

Your generation program is probably still spending time allocating all of these objects, which each contain little to no data. Do any of the child classes have instance data they actually need? I don't see anything passed into their constructors.

If I was focused on generation speed, I would switch away from this object-oriented design for individual blocks. You could still create a data-oriented design that looks up a block processor based on its type and has all those same virtual functions in it. I suppose, theoretically, that might be slower to use, except you'll be scanning through a much smaller amount of memory when processing blocks. You always have to measure these things, of course. If blocks need some instance data, you could pack an enum for block type and an id and/or seed into a struct, and use the seed to figure out whatever other data the block needs on the fly.

As a half-measure, if the individual objects for any particular block type are all the same, you only need one instance of that class. Instead of assigning new blocks, you could reuse the same block instance over and over. For example, why does the system need more than one copy of BlockEmpty, ever? Of course, if you switch to a struct, this no longer applies.




#5287401 Memory Allocation

Posted by Pink Horror on 17 April 2016 - 10:42 PM

Why are you allocating sizeof(struct Node *) bytes?

Also, if you want to make sure your queue class works, try compiling a queue of something like std::string instead of int, and fix all of the compilation errors you'll get from that.




#5286941 Optimizing Generation

Posted by Pink Horror on 14 April 2016 - 05:27 PM

I'm curious, what is the definition of your Block type?




#5285950 A*, A Star: impassable nodes can just go on the closed list?

Posted by Pink Horror on 08 April 2016 - 10:16 PM

If a node is literally impassable, it shouldn't even be considered part of the graph. I wouldn't count them as even neighboring anything.




#5284812 Why is my struct destructor not called?

Posted by Pink Horror on 02 April 2016 - 08:19 PM

You have two instances of A. The variable named a, which has a "val" of 300 at the time it is destructed, and the temporary created on the line "a = A();".

To be clear, that quoted line creates a temporary A, copies its value into the variable named "a" via the assignment operator, and then destructs the temporary.




#5284408 Unit Vector

Posted by Pink Horror on 30 March 2016 - 08:49 PM

(0.8, 0.6) is a unit vector, because its length is 1. That's easy enough to verify.

(0.4, 0.3) is clearly half as long as the previous vector, so it is not a unit vector. Unit vectors are not fractions. You do not "reduce" them. You "normalize" a vector to get a unit vector. If you normalize (0.4, 0.3), you end up with (0.8, 0.6) again.

You use a unit vector when you are multiplying it in some way with something else, and you purposefully do not want the scale of that vector to influence the result of whatever else is involved. If, say, you're doing a dot product with a velocity, to figure out how quickly something is moving in some specific direction, that direction needs to be a unit vector. Otherwise, some scale will be mixed in with your result.

You didn't really mention what you're doing with this vector, so who knows what it can be? All I can offer is circular reasoning: if you need a unit vector, you better use a unit vector. If you don't need a unit vector, use whatever values you want.




#5283951 Making my game code cleaner/easier to work with

Posted by Pink Horror on 28 March 2016 - 05:10 PM


static State GameState;


With this in a header file, every cpp file that includes it is going to get its own internally-linked copy of the variable named GameState. This is probably not what you want.

Why does this variable need to be in the header, anyway? I searched for it in your github, and I only saw it in GameEngine.cpp. I suppose that's why you haven't noticed any bugs yet.


#5283750 queue of unique_ptr issue

Posted by Pink Horror on 27 March 2016 - 01:27 PM

I have never used xcode before. Are there any more lines to the error message? Usually, in Visual Studio or gcc, if there is an error like this, it would give some context about where it was trying to copy the unique_ptr. People shouldn't have to blindly guess about this.
 

 


Yay for obtuse C++ compile errors! The (deleted) copy constructor needs to be invoked to pass the parameter by value, and the error message references a missing constructor:

 

You do not need a copy constructor to pass a parameter by value.




#5282965 Should I give up?

Posted by Pink Horror on 23 March 2016 - 02:17 PM


I guess the first thing is to listen to your gust feeling and follow your dream.


"gust feeling" - I've never heard that before. I suppose the wind just hits you a certain way, and then you know what you have to do.


#5282164 Multi thread deadlock issue with a recursive mutex. Need ideas.

Posted by Pink Horror on 20 March 2016 - 12:30 PM


I need to review a larger scope of the code since the cause of this deadlock isn't obvious at first sight. I got 3 programmer to check the code and all of them think a deadlock shouldn't be happening. Perhaps the problem is elsewhere and the deadlock is a symptom of a bigger problem. Anyhow I'll keep in mind all of your suggestions and keep you posted when we find the issue .


In practically every one of these problems on gamedev I've tried to figure out - where someone posts a small section of code and expects the community to offer solutions - the problem is not in the small section of code posted.

When you're in the deadlock, you should be able to halt the program in the debugger, look at all the locks and the call stacks of all of your threads, and figure out the problem. These problems can sometimes be interesting to try to guess, but you're the one in position to fix it.

At the beginning, you mentioned how the boost code has a thread id inside. So, first, reproduce your deadlock. What is that id during the lock? What are the ids of all your threads? Have you ruled out the memory problem yet?


#5281594 Template madness - template operator not found

Posted by Pink Horror on 17 March 2016 - 12:18 AM

There is a very detailed, specific, complicated set of patterns that a C++ compiler is supposed to be able deduce as function template arguments.

One part of why this doesn't work is very simple: each parameter is deduced independently, so the float for the first argument doesn't help at all for the second one.

For the other part, I am not 100% sure, but generally there are strict restrictions regarding non-type template parameters and qualified name lookups, and you have both there. There is a simple example in the standard stating an argument type of the form A<T1>::B<T2> will not be deduced.

You might get closer to an acceptable pattern by taking B out of A.


#5281426 how could unlimited speed and ram simplify game code?

Posted by Pink Horror on 15 March 2016 - 08:16 PM

I look forward to the infinite AI in this dream world. Every NPC in a game would be able to choose what to do by running its own recursive tree of instances of the game.

I'd also like to add: unlimited RAM to me means no memory management: bye-bye free, delete, or garbage collection. I'd probably just write the whole game in an interpreter - someone's been making a good case for Javascript here tongue.png. Everything would be immutable - the game engine would take the previous immutable game state as input and compute a new one each frame. The entire history of previous game states would be kept in memory, of course.






PARTNERS