Topic : Allegro Vivace
Author : Filipe Medeiros
Page : << Previous 3  Next >>
Go to page :


Here, then, is the above structure in C code:

     #include <allegro.h>
     #include "game.h"

     int end_game;                    /* flag we'll set to end the game */

     int main (void) {
         allegro_init();              /* initialise the Allegro library */
         init();                      /* initialise the game */

         end_game = 0;                /* reset flag */
         do {                         /* loop */
             input();                 /* get input */
             process();               /* process it */
             output();                /* give output */
         } while (end_game == 0);     /* until the flag is set */

         shutdown();                  /* shut down anything that needs it */
         allegro_exit();              /* just for luck */
         return 0;                    /* tell the OS that all went well */

In the above example, `game.h' would be a header file prototyping the functions `init', `input', `process', `output' and `shutdown' which must be defined somewhere else in the project.

3.3 Multi-file projects

    I mentioned earlier that I was going to encourage you to split your source between files.  A lot of people find this hard to do at first, and don't see why it is worthwhile.  In this section of the tutorial I intend to justify it and present what I consider to be a good system for organising a project.

Firstly, then, why are multi-file projects a good thing?  They appear to complicate things no end, requiring header files, extern declarations, and meaning you need to search through more files to find the function you're looking for. In fact, though, there are strong pros to this argument.  When you modify a line of your code, gcc has to recompile everything to create a new executable.  However, if your project is in several files and you modify one of them, gcc already has the object files it generated from your source last time you compiled it, and so it only needs to recompile the file that was changed.  In a large project this can mean the difference
between a lengthy (5 minutes or more, depending on computer speed) recompile and a twenty second adjustment.
    With a little organisation, splitting a project between files can make it much easier to find the piece of code you are looking for.  It's simple -- you split the code between the files based on what it does.  Then if you're looking for the routine to draw the player, you know it will be in the graphics source file.
    Also, since your program is very modular with the minimum amount of sharing between files, bugs are easier to track down; if not many files have access to a certain variable, an erroneous value must be a bug in one of those files.

Suggested system
This is strictly IMHO; other people may prefer to lay things out differently.   But since I find these guidelines useful, I suggest you follow them.

* Don't make header files which span several source files (exception: library header files).  It's much easier to  track and usually more efficient if each header file    only declares symbols from one source file.
* Where appropriate, do use more than one header file for a source file.

* Don't duplicate information in several header files.  If you need to, `#include' one in the other, but don't write out the same header information twice.  This way, if  you change the information in the future you will only need to change it once, rather than hunting for duplicates which would also need modifying.

* Make each source file includes all the header files which declare information in the source file.  Doing this means that the compiler is more likely to pick out      mistakes, where a declaration in a header file does not match the definition in a source file.

    I hope you can see the advantages of splitting up your projects, but if you don't, by all means keep your project in a single file.  The examples I will use later on will normally be multi-file, based around the guidelines above and the game structure discussed earlier (see Section 3.2: Proposed structure), so there will be plenty more opportunities to see the benefits of this.
    If you are still confused about this, please have a look at the article I wrote for the electronic magazine C-Scene.  The URL for this keeps changing though; one way to find it is to IRC on Efnet and `/msg bjarne calc cscene'. The article is in issue 2, entitled `Multi-file projects and the GNU Make utility'.  It duplicates the information here, in more detail, and explains  some common problems newcomers have to this technique.

4. Introducing graphics

This section assumes you are familiar with the idea of graphics
programming, i.e. coordinate systems, resolution, etc.  If you
are not, try reading it anyway; if you don't understand you
should get a book on computer graphics.

4.1 Selecting a graphics mode

To put the computer into a graphics mode, you use this function:

     int set_gfx_mode (int CARD, int W, int H, int V_W, int V_H);

For CARD, you put one of the `GFX_*' constants, normally `GFX_AUTODETECT'.  W and H are the minimum width and height of screen space you want; the actual mode selected might have a slightly larger display area.  For now just pass 0 for V_W and V_H.

4.2 Drawing things

4.2.1 The BITMAP struct

Allegro's graphics routines aren't restricted to writing to the screen; they write to bitmaps.  A bitmap could be the screen, it could be a block of memory, or it could be a "subbitmap" (part of another bitmap).  When you call Allegro's graphics routines you pass them a pointer to a BITMAP struct, which contains information about the bitmap you want to write to. It's best to think of your pointer simply as a "handle" to the bitmap -- it's just like a reference number.  Allegro will   assign it initially, and you then pass it back to the graphics routines to tell them where to draw. The only interesting parts of the BITMAP struct as far as we're concerned are the `w' and `h' fields; these hold the width and height of the bitmap respectively, in pixels. Allegro defines the variable `screen' to be a pointer to a BITMAP struct representing the screen, so for example:

     clear_to_color (screen, 5);

will clear the screen to colour 5 (often magenta).

4.2.2 Plotting pixels

To plot a pixel you use the Allegro function:

     void putpixel (BITMAP *BMP, int X, int Y, int COLOR);

This sets the pixel in the bitmap referenced by BMP at coordinates X,Y to the colour COLOR.  Simple enough.
See the example program in `src/4.2/ii' for an example of the use of `set_gfx_mode', `clear_to_color' and `putpixel'.

4.2.3 Some other `primitives'

Functions like putpixel are called graphics "primitives", because they are the basic graphics output functions.
Some other simple graphics routines are:


Page : << Previous 3  Next >>