![]() |
|
|
Main Lectures Assignments Demos Groups Requirements Resources C++ Help MSDNAA CVS |
Programming and C++ ResourcesGetting GameX to work on your home machine:Some people have asked how to compile GameX applications on their home machines. These instructions assume that you have Windows XP and a DirectX 9.0 compliant video card.)
Compiler errors, source and header files, and file organization in C++ Arrays and C-strings in C++ How to use templates in C++ Some good development practices Some good coding practices Finally, here are a few more things that are important to know: ASSERT:
Whenever you assume something is true, call assert( ) on it to make sure it really is true. Things like If you're not familiar with the concept, it might sound like unnecessary extra work, but getting in the habit of using assert is one of the biggest timesavers possible. It basically corners bugs before they can even happen. As soon something you assert fails to be true, you'll be told when and where, but if the assert hadn't been there, (unless you get lucky) your game will keep running, some completely unrelated code will screw up, and you'll have no idea why. Note that asserts don't even get compiled in optimized Release builds, so your game won't run any faster if you don't use them. TEMPORARY OBJECTS IN C++: Suppose you have a function called SetPosition( ) that takes a Vec3f object and puts a character at the position you pass in. If you're coming from a Java background, you might write a call to put the character at the origin like this: character.SetPosition(*new Vec3f(0, 0, 0)); // wrong But, there is a major problem with that. You're calling "new", and because C++ doesn't have a garbage collector, that means you'll leak memory unless you call "delete" on it when you're done with it. So you might think that you need to change the above code to:
Vec3f* temp = new Vec3f(0, 0, 0); // bad But, that is also not the best way to do it. It works, but it's inconvenient - you shouldn't have to write 3 lines of code just to do this 1 thing. So, C++ allows for the easy creation of "temporary objects", which are basically objects that are automatically deleted as soon as they go out of scope. The right way to write the above code is: character.SetPosition(Vec3f(0,0,0)); // makes a temporary object and passes it into a function It's as simple as that. You're still creating a Vec3f object, but because you didn't call "new", you don't have to call "delete" on it yourself, and depending on the optimizing compiler it might even run faster than using new/delete to do the same thing. This also works in other ways besides passing objects into functions: Vec3f temp (0,0,0); // makes temporary object Vec3(0,0,0) and assigns it to a variable called temp return temp; // returns a temporary object variable, which waits to be deleted until outside the scope of the calling function return Vec3f (0,0,0); // makes a temporary object and immediately returns it without bothering to give it a variable name A NOTE ABOUT DOUBLES AND FLOATS: No matter what you might hear, doubles ARE slower than floats even on current (circa 2005) systems, and they take up twice as much memory. Use float instead of double in your game, except where extremely high precision is absolutely necessary (which, in my experience, is basically never). When you type a decimal number in your code like 0.5, that automatically means it's a double. You should instead type these values like 0.5f (append an f to the number), to tell the compiler it's a float and not a double. Also, when using the common math functions (from <math.h>) for things like square root, sine, power, absolute value, and ceiling, you should use the floating point variety of these functions. For instance, use sqrtf( ), sinf( ), powf( ), fabsf( ), and ceilf( ) instead of sqrt( ), sin( ), pow( ), fabs( ), and ceil( ). Note that it is fine and valid to compare a float for exact equality to another float variable or value if you know they can be exactly the same, but in many cases you will want to check to see if the floats are within a certain range of tolerance within each other, i.e. if(fabsf(floatA - floatB) < 0.001f) instead of if(floatA == floatB). If you are relying on super-high precision for your game to work, you are doing something wrong anyway that high precision won't be enough to fix in all cases. ROUNDING and CASTING FLOAT TO INT: When you cast a float like this: int myInt = (int)myFloat; You are truncating (flooring) the float, which is actually an expensive calculation on most systems. If you don't mind rounding the float to an int instead, or especially if you actually want to round the float, and if you are at all concerned about performance (which you probably are), then you should use a fast rounding function instead of the built-in casting. In your specific case, GameX gives you a global inlined function called Round( ) which is (very roughly) about 5 times faster than casting a float to an int, and even faster compared to the alternative method of rounding (which is (int)(myFloat + 0.5f)). In any case, if you find yourself doing a lot of conversions between ints and floats, consider moving it all to floats to avoid having to go back and forth so much, unless there is a really good reason for using ints for those variables (such as needing to use them to index directly into an array). That's all for now. More information may appear here at a later date... |