Cross-Platform Game Development for C++ Developers, Part II: The Allegro Platform, Page 2
A Complete Allegro Example (cont'd)
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();
Lines 33-101 comprise the classic game loop model of programming. Play continues until the player hits the ESC key to exit. Simultaneous keyboard input is supported in lines 34-39, because you can hold down both up and left keys to get roughly diagonal motion.
In lines 41-61, the mouse action is captured in global variables mouse_b (for buttons), mouse_x, and mouse_y. If you had been using a scroll mouse, you would have mouse_z available too. A bit of hand-coded de-bouncing logic also ensures that only one ball drops per mouse-down event.
Line 63 calls doPhysics(), whose purpose is to spin the wheel's line segments, update ball positions, detect ball collisions, and alter their direction vectors appropriately. This is a somewhat intense module (350 lines of math code), but it is an elegant implementation that you should study on your own.
The remaining code, lines 65-101, does the rendering and would certainly belong in its own function body in a non-trivial demo. This renders in the classic double-buffer paradigm, whereby the next incremental screen change is calculated and drawn off-screen then swapped in at the last millisecond (line 100). This both insures visual continuity and reduces annoying flicker where objects would appear to be drawn randomly. Within the rendering code, the line() and circlefill() calls are relatively straightforward: circlefill() takes x, y, radius, and fill color as parameters.
The textout_ex() function can do a bit more than
Last, but certainly not least, draw_sprite() on line 100 does a masked copy of the newly rendered bitmap to the screen object you created way back on Line 14. A masked copy means that only the non-transparent colored pixels are copied. In this example, I'm fairly sure it devolves to a "blit" (block copy) transfer.
