04.01 - Some Code to Ponder

Started by
41 comments, last by Teej 22 years ago
Okay folks, no more fooling around…time to learn something. Have your compiler running with the BaseCode1 project loaded, and be sure that your DirectX 7.0 SDK documentation is easily accessible. If you’re missing some files, try here. The Rise and Fall of BaseCode1 Let’s turn our attention first to the overall layout of the program:
  • Program execution starts at WinMain() (true for all Windows applications)
  • The OS is instructed to create a full-screen window (black)
  • Game_Initialize() is called
    • DirectDraw is initialized
    • DirectInput is initialized
    • DirectSound is initialized
  • The main message loop is entered (true for all Windows applications)
    • Windows messages are handled in WindowProc()
      • ESCAPE quits
    • If there are no messages waiting, Game_Main() is called
      • Check for input
      • Clear the display
      • Write a line of text
      • Play a sound if the spacebar was hit
  • Once the main message loop is exited (ESCAPE was hit), call Game_Terminate()
    • DirectSound is shutdown
    • DirectInput is shutdown
    • DirectDraw is shutdown
  • The program ends
  • Or, more simply stated (ignoring Windows-related procedures):
    • Game_Initialize() is called
    • Game_Main() is called (repeatedly)
    • Game_Terminate() is called
    It’s fairly common to see ‘entities’ such as our game code and the DirectX components asking for an opportunity to initialize before being used and a chance to take care of any shutdown tasks before they’re done. If our game requires memory for internal data, it would be a natural process to allocate the memory in Game_Initialize() which is called once at the beginning of the game, and free that memory in Game_Terminate() which is called before the game is completely terminated. Likewise, you’d expect that DirectX components don’t just work off-the-bat – we need to set them up first by calling their initialization functions and feeding them the correct information so that they work properly when they’re needed. Overall Layout The compiler doesn’t care if our template code is in one file or in fifty. It is only for readability that we ‘chop up’ the game’s functions into groups and assign them their own files. Face it – a game with 800 functions all in one file makes for messy game code. There will be an article discussing source files, header files and projects that will further explain the semantics to organizing code in files, so for now let’s just look at the contents of the files themselves:
    • WinBase.cpp contains all of the code that is specific to Windows. We need to at least create a window and process messages coming in from the OS to be considered a true Windows program, and this file keeps them all in one place. It also contains the proper start of execution, WinMain() . Once we dissect this function, the entire flow of the program will make perfect sense.
    • InitTerm.cpp contains, you’ve guessed it, all of the initialization and termination functions for our game template. Game_Initialize() calls other initialization functions, in a sense managing everything else in the game. In the same way, Game_Terminate() ensures that everything that would like a chance to shutdown gets called. This is our last chance to do things before our frame-by-frame code gets called repeatedly, so make sure everything’s prepared!
    • GameMain.cpp is where all of the action takes place. This function is called repeatedly from the message loop in WinMain() , which means that whatever you put in this function is going to execute many times a second. It’s our job to make sure that the code is written to fit this style. If every call to Game_Main() produces a frame of animation on the display, we’ve got ourselves the chassis for a game.
    • Utils.cpp is a convenient place to throw functions into that are used by other parts of the game. For instance, there are functions for loading bitmaps from disk in this file, which is used elsewhere.
    And there’s also a couple of header (.H) files:
    • Utils.h contains a ‘description’, called a prototype or declaration, for each of the functions implemented in Utils.cpp. As long as any other source file has access to this header file, it can use the functions contained inside.
    • Globals.h is the master header file for our game template code. Every source file needs to know about Globals.h in order to function properly. If we place any information inside of this header file, it is immediately accessible from anywhere in our entire game. Sounds like a good place for global variables, huh? That’s one of the primary purposes of this file.
    So, the rule of thumb is that every source file (.CPP) should include Globals.h so that we can use global variables properly, and any source file that needs to use a function from Utils.cpp should include Utils.h. As you can see at the top of each source file, including a header file is accomplished with the line #include “filename .h” , where filename is either Globals or Utils . Let’s look once more at our organizational ‘chart’ to really drive the point home:
    • Create a window for our game: WinBase.cpp WinMain()
    • Initialize our game: InitTerm.cpp Game_Initialize()
      • Initialize DirectX components
    • Draw animated frames: GameMain.cpp Game_Main()
    • Shutdown our game: InitTerm.cpp Game_Terminate()
      • Shutdown DirectX components
    • End of game
    Divide and Conquer What we’re doing here is setting ourselves up to understand the game template code by attacking each component separately. Each of the following has initialization, runtime and shutdown duties:
    • Our game code
    • DirectDraw
    • DirectInput
    • DirectSound
    Since we don’t have a game yet, the template code just fills in each section with something simple to serve as a placeholder. For instance, we use DirectDraw to set up our display, but all we’re doing is writing a line of text. Heck, it even goes through the trouble of loading RESOURCE.BMP onto an internal buffer, but we don’t (yet) do anything with it. For input, we have the code necessary to read the keyboard, and all that this program is interested in is the spacebar. Using DirectSound, we load a single sound into memory and play it whenever the spacebar is pressed. Nothing too complicated for any of these components, but just enough to say that we used them – they’re initialized, used and terminated properly. Definitely something good to build on! Of the three DirectX components, only DirectDraw is truly essential. We don’t need fancy sounds this early in our studies, and even input isn’t absolutely necessary, but without DirectDraw we wouldn’t even be able to set our resolution, color depth or display anything on the screen. Therefore, it should come as no surprise that we’ll concentrate our attack there first, but not before looking at DirectX as a whole. Part of the beauty of using DirectX is that the components are used rather consistently – once you get the hang of using one component, the rest aren’t so difficult to manipulate. Questions? Comments? Please reply to this topic. Edited by - teej on April 23, 2001 5:45:57 PM
    Advertisement
    I just wanted to say I think you are doing a HELL of a job Teej, hang in there and we''ll be coding games in our sleep. I really want to thank you for taking the time to put this together for us. SO once again GOOD JOB TEEJ!!!
    Awww, geez

    I''m hoping to get my computer running tomorrow again, and then I''ll give everyone something to be thankful for...

    Full speed ahead!

    Teej

    Hey, and thanks for this tutorial. Great doing it interactive, so people like me can hang around and ask questions on pretty obvious things that I just don''t understand
    I have a question on the ''G'' struct in ''Globals.h'' in the program BaseCode1; how do you define structures? Is it :

    struct { bla bla, bla bla..} G;

    I mean, does the name (here ''G'') always come after the whole thing, or at the beginning, as with classes, or doesn''t it matter?
    I think the struct statement looks something like this :

    struct structName
    {int varOne;
    int varTwo;}
    varName;


    You can omit structName IF you specify a varName but in that case you would NOT be able to define other variables of the same type (struct)

    Conversely you can omit the varName in which case you will have to define your variable at a later time like so:

    structName varName;
    structName otherVarName;

    By specifying structName you are in essence creating a new var type which you can use to create other variables of that type withing the scope of that struct.

    And by specifying a varName you are simply combining two statements together. The type definition AND the variable definition.


    Hope this help, and if i''m wrong please correct me anyone.


    Halek
    G at the end of the struct is an instance of this particular struct, but not the name of the actual struct. If you used:

    struct {blah blah blah} G,H,I;

    then you would have 3 structures built, one called "G", one called "H" and another called "I". Then you could access them by using G.blah or H.blah, etc.

    I have always used the method Teej used to build structs with the name of an instance of my struct at the end of the struct architecture. However you could build one this way:

    struct global_architecture
    {
    blah blah blah
    };

    and then build a variable of type global_architecture and name it G. Here you have named the struct, and you can build versions of it anytime you need it. It would then give you the exact same results as Teej has gotten. You see, structs are exactly the same as a class, except that members are public by default. In C++, struct is only really provided for backwards compatability. Using classes instead of structs is generally considered good pactice, but if all you need is a slightly more complicated kind of array, (as we do here) then a struct is easier to work with.
    Hi all,

    Teej, this is the most wonderful of tutorials out there on the net. I''ve already read a lot of them, but this is the first one that gives me the feeling you actually know what you''re talking about. Thanks.
    Can somebody please provide me with the files that were supposed to be on Teej''s website? They aren''t there.
    E-mail: seferis@pandora.be
    ICQ: 72428880

    Thanks in advance

    *** Hi! I''''m a signature virus. Copy me into your signature to help me spread! ***
    *** Hi! I''m a signature virus. Copy me into your signature to help me spread! ***
    Greetings, Teej.
    Several folks have posted this, but I think you have overlooked them. The file BaseCode1.zip is not found at the link on your website. We beginners cannot follow along in this great tutorial without it. Could you please fix it?

    Thanks!
    Shep
    To those who have not been able to download BaseCode1.zip:

    I did a little experimenting and came up with a different URL.

    Try this one instead:

    http://freehosting1.at.webjump.com/2a4a785c8/te/teejb-webjump/BaseCode1.zip

    Teej...tsk tsk. Methinks ye needs a different host, or somethin''.

    Shep
    way to go man, this tutorial is great. im excited to see more and get into the nitty gritty of C and DirectX. Ive analyzed your code (from basecode) 5000 times plus i read C books. I have always wanted to make games and you are my savior. -kaptan
    -kaptan"If you cant handle the heat, Get off the car hood"

    This topic is closed to new replies.

    Advertisement