Cross-Platform Game Development for C++ Developers, Part II: The Allegro Platform

CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Good news, would-be game developers: I am extending my introduction to cross-platform game development (https://www.codeguru.com/Cpp/misc/samples/games/article.php/c10339/) into a weekly series. This week, I highlight the Allegro (Allegro Low LEvel Game ROutines) open source library, going into technical depth and providing a brief demo, so you can determine whether it’s the right platform for you.

An Engine for Many Environments

Allegro began on the venerable Atari ST platform in the late 1980s and quickly migrated to the popular DJGPP environment (a 32-bit MS-DOS extender popular in the early 90s). Since then, Allegro has been ported to most popular Windows C++ development environments including VS, MinGW, Cygwin, and Borland C++. Other platforms that support it include Linux, BeOS, QNX, Mac OSX, and nearly any other Unix platform with X11 libraries.

Allegro can render into a variety of bitmap and hardware-accelerated environments, such as DirectX, XWindows, SVGAlib, FreeBE/AF, CGDirectDisplay, QuickDraw, and others. Allegro does not attempt to provide its own 3D environment or emulation thereof, but OpenGL can be easily integrated using the AllegroGL library, which provides a GLUT-like interface (including extension management).

An Extremely Brief Feature Overview

Before delving directly into APIs, a quick look under the hood is in order:

  • Drawing functions down to the pixel level, including flat shaded, gouraud shaded, texture mapped, and z-buffered polygons and circles, floodfill, bezier splines, patterned fills, sprites, blitting, bitmap scaling and rotation, translucency/lighting, and text output with proportional fonts
  • FLI/FLC animation player (a format with better compression characteristics than MPEG for computer-generated animations)
  • Plays background MIDI music and up to 64 simultaneous sound effects, and can record sample waveforms and MIDI input (Sound platform support includes WaveOut, DirectSound, OSS, ESD, CoreAudio, and QuickTime, just to name a few)
  • Easy access to the mouse, keyboard, joystick, and high-resolution timer interrupts, including a vertical retrace interrupt simulator in the DOS version
  • Routines for reading and writing LZSS compressed files
  • Math functions, including fixed point arithmetic, lookup table trig, and 3D vector/matrix/quaternion manipulation
  • GUI dialog manager and file selector
  • Built-in support for 16-bit and UTF-8 format Unicode characters

Let’s Get This Engine Started!

In Allegro use, as in many other game scenarios, the overall structure consists of pre-game initialization, the game loop, and post-game cleanup. Initialization means both the Allegro startup code and the basics of loading or generating your game level at the starting location. Allegro imposes very little overhead in terms of writing your initialization code (see Figure 1).

If you need a lot of screen real estate, it is polite to first inquire with get_gfx_mode_list() to find the largest mode available:

#include <allegro.h>       // must come AFTER system headers
   set_color_depth(32);    // Defaults to 8-bit color otherwise
   if (set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0) != 0) {
      abort_on_error("Couldn't set a 32 bit color resolution");
   }

The last two parameters of set_gfx_mode() specify the size of the virtual buffer within which your graphics screen lies. This makes easy work of writing a side-scroller game where the terrain is continuously in motion. For example, you might make the virtual buffer, say, 20% wider to give you room to smoothly scroll in new sprites and terrain.

A Complete Allegro Example

This tutorial uses at Kee-Yip Chan’s “SnookerClone” demo, which is based on another demo of the same name by James Lohr. Figure 1 shows the demo’s basic screen shot.

Figure 1. Kee-Yip Chan’s “SnookerClone” Demo

This project shows off a variety of Allegro techniques, including animation, keyboard and mouse input, collision, and gameplay physics (for example, gravity). It utilizes three primary elements: a rotating wheel with eight arms, a big red circle controlled by the arrow keys, and blue circles that drop from the ceiling. The wheel pushes the red ball on contact, and the red ball interacts realistically when colliding with the blue ones. The whole thing is kind of a cross between a pinball machine and one of those executive toys with falling beads suspended in a clear solution.

The following is the code for the demo:

  1 #include <allegro.h>
  2 vector<Point> g_points;    // List of points aka balls. aka
                               // ball centers?
  3 vector<Joint> g_joints;    // List of physical objects,
                               // e.g. wheel and bumpers.
  4 kVec   g_accControl;
  5
  6 int main(void)
  7 {
  8    allegro_init();         // Initialize allegro.
  9    install_keyboard();     // Enable keyboard.
 10    install_mouse();        // Enable mouse.
 11    install_timer();        // Needed for show_mouse();
 12
 13    // Create a 800x600 non-fullscreen window.
 14    set_gfx_mode(GFX_AUTODETECT_WINDOWED, 800, 600, 0, 0);
 15
 16    set_window_title("Kee-Yip Chan's Snooker Clone");
 17    text_mode(-1);    // Text will be drawn on transparent
                         // background.
 18
 19    BITMAP* buffer = create_bitmap(SCREEN_W, SCREEN_H);
       // Create a bitmap for double buffering.
 20
 21     // Initialize data.
 22    create_joints(g_joints);    // register hardcoded screen
                                   // positions for wheel,
 23                                // floor, and bumpers
 24
 25    // Create points aka balls: player ball and three blue
 26    // balls position, velocity, size, and mass.
 27    g_points.push_back(Point(kVec(100, 300),kVec(0, 0),16, 10));
      // Player.
 28    g_points.push_back(Point(kVec(50, 40), kVec(0, 0),12, 5));
       // medium ball.
 29    g_points.push_back(Point(kVec(80, 40), kVec(0, 0) 12, 5));
       // medium ball.
 30    g_points.push_back(Point(kVec(110, 40),kVec(0, 0),6, 1));
       // small ball.
 31
 32    // Main loop, exit when ESC is pressed.
 33    while(!key[KEY_ESC]) {            // Check input.
 34       if(key[KEY_UP])
 35           g_accControl.y = -0.07;    // Jet pack. Accelerate
                                         // upwards
 36       if(key[KEY_LEFT])
 37           g_accControl.x = -0.07;    // Walk left. Accelerate
                                         // to the left.
 38       if(key[KEY_RIGHT])
 39           g_accControl.x = 0.07;     // Walk right. Accelerate
                                         // to the right.
 40
 41       static bool leftMousePressed = false,
                      rightMousePressed = false;
 42       if(mouse_b & 1) { // Left mouse button pressed.
 43           if(!leftMousePressed){
 44              leftMousePressed = true;    // Create a new ball.
 45              g_points.push_back(Point(kVec(mouse_x, mouse_y),
                                    kVec(0, 0), 12, 5));
 46              }
 47           }
 48       if(!(mouse_b & 1))
 49         // Ensures that it doesn't repeat the mouse press;
 50         // otherwise, streams of new balls would gush out.
 51           leftMousePressed = false;
 52       if(mouse_b & 2) {    // Right mouse button pressed.
 53             if(!rightMousePressed){
 54                 rightMousePressed = true;    // Create a new
                                                 // ball.
 55                 g_points.push_back(Point(kVec(mouse_x, mouse_y),
                                             kVec(0, 0), 6, 1));
 56             }
 57         }
 58       if(!(mouse_b & 2))
 59         // Ensures that it doesn't repeat the mouse press;
 60         // otherwise, streams of new balls would gush out.

 61         rightMousePressed = false;
 62
 63       doPhysics();
 64
 65       // Rendering: Erase the buffer so we can use it again;
          // otherwise, old images will linger.
 66       // White color for clarity.
 67       clear_to_color(buffer, makecol(255, 255, 255));
 68       for(unsigned i = 0; i < g_points.size(); i++) {
            // Draw points.
 69         // Draw a solid ball.
 70         circlefill(buffer,    // Draw to buffer.
 71                  g_points[i].position.x,
                     g_points[i].position.y,
                     // Point's position aka ball's center.
 72                  g_points[i].size,    // Radius.
 73                  (i == 0) ? makecol(255, 0, 0) :
                                makecol(0, 0, 255));
                     // Red if player; otherwise, blue.
 74
 75         // Draw an outlined ball.
 76         circle(buffer,    // Draw to buffer.
 77                   g_points[i].position.x,
                      g_points[i].position.y,
            // Point's position aka ball's center.
 78                   g_points[i].size,     // Radius.
 79                   makecol(0, 0, 0));    // Red if player;
 80                                         // otherwise, blue.
 81         }
 82
 83         // Draw joints.
 84         for (unsigned i = 0; i < g_joints.size(); i++)
 85            line(buffer,  // Draw to buffer.
 86                   g_joints[i].p1.x, g_joints[i].p1.y,
                      // Point 1.
 87                   g_joints[i].p2.x, g_joints[i].p2.y,
                      // Point 2.
 88                   makecol(0, 0, 0));    // Black color.
 89               );
 90
 91         // Print instructions.
 92         textout(buffer, font, "Left Mouse Button - new big ball
                                   Right Mouse Button - new small ball",
 93               125, 1, makecol(0, 0, 0));
 94
 95         textout(buffer, font, "Arrow Keys - move red ball",
 96               300, 592, makecol(0, 0, 0));
 97
 98         show_mouse(buffer);    // Draw the mouse cursor.
 99
100         draw_sprite(screen, buffer, 0, 0);
            // Draw the buffer onto the screen.
101       }    // end while
102
103     return 0;
104
105 }END_OF_MAIN();

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read