Jump to content




Recent Status Updates

  • Photo
      16 Sep
    Kadence

    Some spammers sign up to CC and then they leave their account hidden so they think it won't get noticed but with an obvious name like "SaxophoneRetailSingapore" it's hard not to know they are a spam bot. #ModLife

    Show comments (3)
  • Photo
      15 Sep
    Error

    Programming is something that I enjoy and want to make a career out of. But, I usually tend to start things and not finish them. Any advice on how I can finish what I start?

    Show comments (1)
  • Photo
      12 Sep
    FacetiousTurtle33

    Just joined. Really enjoy this sight. Excited to become a great programmer, and helper.

    Show comments (3)
View All Updates

Developed by Kemal Taskin
Photo
- - - - -

Allegro Game Library

php

  • Please log in to reply
12 replies to this topic

#1 Aereshaa

Aereshaa

    CC Devotee

  • Just Joined
  • PipPipPipPipPipPip
  • 638 posts

Posted 02 July 2008 - 10:59 PM

This is a guide to the Allegro Game library, an awesome C library which works on windows, unix, mac OS X, heck, it even works on BeOS and QNX.

Why use the Allegro library and C? Because:
-It is very fast.
-It is under a giftware license.
-...I said so? no? whatever.

So, download allegro here. There will be really helpful information on how to install it inside the package. If you use Dev-C++, there is a devpak. If you use MS Visual Studio.. I dunno. Maybe Xav can figure it out, he uses it.

So once you've got allegro, let's make a simple program using it!
#include the allegro library, allegro.h, and in your main() function, call allegro_init().
Next, if you want to use the mouse or keyboard, call install_keyboard() and/or install_mouse().
Next is graphics. Call set_color_depth(24) (or passing 32, or 16, or 15 or 8), and then call set_gfx_mode(GFX_AUTODETECT_WINDOWED, width, height, 0, 0)
Finally, after the end of your main() function, call END_OF_MAIN().

So, now you should get a blank window which appears for an instant.
To prevent it disappearing until you press the X button, make a global variable called X_button_state, and set it to zero. Make a function called X_button_handler(), inside of which you set X_button_state to one. In main(), call set_close_button_handler(X_button_handler()).

Then, put a loop in the end of your main() function, which doesn't terminate until X_button_state = 1.

Okay, so now I'll tell you about BITMAP structures, blit()ting, and drawing primitives. When you called set_gfx_mode(), you created a BITMAP structure called screen, which is literally the memory mapped pixels of the screen. Writing to the screen, however, is very slow, so it's best to create another BITMAP structure of the same size as your screen, and then, each turn of your main loop, draw to it and then copy the whole thing to the screen.

To do this, outside your main loop, put:
BITMAP * buffer = create_bitmap([I]width[/I],[I]height[/I]);
(Of course, you're free to call it whatever you want.)
Now, inside your loop, at the beginning, clear your buffer to black:
clear_to_color(buffer, 0);
(later, I'll show you how to make other colors)
And at the end, copy it to your screen, using the blit() function, which is for copying large areas of pixels:
blit(buffer,screen,0,0,0,0,[I]width[/I],[I]height[/I]);

So, how do you write to the buffer? Well, let's start with colors. In Allegro, colors are simply int values, which can be generated from rgb colors by calling the makecol() function, as follows:
int red = makecol(255,0,0);
int green = makecol(0,255,0);
int blue = makecol(0,0,255);
For more pretty colors, check out this chart.

Now, let's use a few colors, to draw stuff! There are quite a few primitive drawing functions, so I'll just list them, and their arguments. Test them out, they look cool when moving!
line(buffer,[I]x1[/I],[I]y1[/I],[I]x2[/I],[I]y2[/I],[I]color[/I]); //line
triangle(buffer,[I]x1[/I],[I]y1[/I],[I]x2[/I],[I]y2[/I],[I]x3[/I],[I]y3[/I],[I]color[/I]); //filled triangle
rect(buffer,[I]x1[/I],[I]y1[/I],[I]x2[/I],[I]y2[/I],[I]color[/I]); //rectangle outline
rectfill(buffer,[I]x1[/I],[I]y1[/I],[I]x2[/I],[I]y2[/I],[I]color[/I]); // filled rectangle
circle(buffer,[I]x[/I],[I]y[/I],[I]r[/I],[I]color[/I]); // circle outline
circlefill(buffer,[I]x[/I],[I]y[/I],[I]r[/I],[I]color[/I]); // filled circle
ellipse(buffer,[I]x[/I],[I]y[/I],[I]rx[/I],[I]ry[/I],[I]color[/I]); // ellipse/oval outline
ellipsefill(buffer,[I]x[/I],[I]y[/I],[I]rx[/I],[I]ry[/I],[I]color[/I]); // filled ellipse/oval
... that seems enough for now. see ya later!

Edited by Aereshaa, 03 July 2008 - 09:45 AM.

  • 3

#2 gaylo565

gaylo565

    CC Addict

  • Advanced Member
  • PipPipPipPipPip
  • 258 posts

Posted 03 July 2008 - 08:40 AM

I like it:) I've never used Allegro before but I think I might try and add it to my centipede game that I am working on once I get the game working. I'm sure it will take recoding of most of my project but I have never done large amounts of work with a graphics library before and would love to give it a try.
  • 0

#3 John

John

    CC Mentor

  • Moderator
  • 4,450 posts
  • Location:New York, NY

Posted 05 July 2008 - 04:40 PM

Does Allegro support three dimensional graphics? Everything you mentioned seems to be two dimensional.
  • 0

#4 Aereshaa

Aereshaa

    CC Devotee

  • Just Joined
  • PipPipPipPipPipPip
  • 638 posts

Posted 05 July 2008 - 08:54 PM

It does if you are willing to look up the formulae! For example, I made a 3d Pong game a few weeks ago. Basically, I used Allegro with math.h and checked the formulae on wikipedia. Also there are 3d math routines, although I haven't used them at all...

Okay, so next thing is input. Allegro uses two main sources of input: the keyboard array and the mouse variables. The keyboard array is key[] which is indexed by a kabillion macros: here's how it works:
key[KEY_A]
key[KEY_ESC]
key[KEY_SHIFT]
key[KEY_F1]
key[KEY_CTRL]
...aand so on. A complete list is here.

For mouse, use the variables mouse_x mouse_y, and use the bit-mapped variable mouse_b. mouse_b & 1 is left button, mouse_b & 2 is right, mouse_b & 4 is middle. any other buttons on your mouse can probably be found at later bits.

Okay, next is text. To draw text on the screen, you need a font. Fonts can be loaded to allegro from GRX format .fnt files, 8x8 or 8x16 BIOS format fonts, or from specially prepared bitmaps. Allegro also contains a global font variable, containing a simple font.
To load a font, use the load_font() function, like so.
FONT * myfont = load_font("myfont.fnt",NULL,NULL);
The two NULL arguments are a palette, which doesn't exist, and a loader script file, which is not needed.

So, to use a font, use the textprintf_ex() function.
textprintf(buffer,font,[I]x[/I],[I]y[/I],[I]color[/I],[I]bgcolor[/I],[I]"format string"[/I], ...)
The color or bgcolor arguments may be -1, in which case they are transparent.
There are also textprintf_centre_ex(), and textprintf_right_ex(), variants which treat the coordinates given differently.

Edited by Aereshaa, 05 July 2008 - 09:27 PM.

  • 2

#5 Aereshaa

Aereshaa

    CC Devotee

  • Just Joined
  • PipPipPipPipPipPip
  • 638 posts

Posted 07 July 2008 - 10:54 AM

Okay, so, you've got a game, say a clone of space invaders, and you have the game logic all worked out, but wait! You can only draw triangles and squares and lines and circles!
What you need is sprites. Sprites are essentially bitmaps loaded out of a file. Allegro can load sprites from .bmp, .lbm, .tga, and .pcx image files, using the load_bitmap() function, whats syntax is:
BITMAP * sprite = load_bitmap("[I]whatever.bmp[/I]",NULL);
The NULL is a palette, which is only used for 256-color modes.
But remember that all bitmaps must be destroyed using destroy_bitmap() before the end of the program.
To use a sprite, you will need the draw_sprite() function, similar to the blit() function, except that the color FF00FF (bright violet) is treated as transparent. It is used like this:
draw_sprite(buffer,[I]sprite[/I],[I]x[/I],[I]y[/I]);
There are plenty of extra featured versions, such as stretch_sprite()
, which takes a width and height to stretch the sprite to, and rotate_sprite() which takes as an extra argument an angle in fixed point, which you can convert from radians using radtofix_r():
rotate_sprite(buffer,[I]sprite[/I],[I]x[/I],[I]y[/I],radtofix_r(PI / 3.0)); //rotates 60 degrees

Edited by Aereshaa, 07 July 2008 - 11:05 AM.

  • 0

#6 Aereshaa

Aereshaa

    CC Devotee

  • Just Joined
  • PipPipPipPipPipPip
  • 638 posts

Posted 09 July 2008 - 04:02 PM

Okay, that's pretty much the basic stuff, for extra features and lists of functions see here.
Now, I'll just share some examples:
Aereshaa's Pong Reloaded. Undefine reloaded for classic pong.
#include "stdio.h"
#include "unistd.h"
#include "time.h"
#include "allegro.h"
#include "stdlib.h"
#include "math.h"
#define scrH 128
#define scrW 256
#define color int
#define triple long double
#define reloaded
typedef struct MASS_ {
 int xpos;
 int ypos;
 double xspd;
 double yspd;
} MASS;
#define mass MASS *


int main(int argc, char** argv){
 allegro_init();//setup of graphics & stuff.
 install_keyboard();
 install_mouse();
 set_color_depth(24);
 set_gfx_mode(GFX_AUTODETECT_WINDOWED, scrW * 2 , scrH * 2 ,0,0);
 BITMAP *buffer = create_bitmap(scrW, scrH);//will speed things up.
 MASS P1 = {64,64,0.0,0.0};
 MASS P2 = {192,64,0.0,0.0};
 MASS BL = {128,64,-2.0,0.0};
 char P1_size = 8;
 char P2_size = 8;
#ifdef reloaded
 long P1_timeanom_pow = 0;
 long P2_timeanom_pow = 0;
 long P1_gravanom_pow = 0;
 long P2_gravanom_pow = 0;
 long P1_gravanom_dur = 0;
 long P2_gravanom_dur = 0;
 int gravdir = 0;
 long P1_reflanom_pow = 0;
 long P2_reflanom_pow = 0;
#endif
 int P1_score = 0;
 int P2_score = 0;
 int winner = 0;
 color white = makecol24(255,255,255);
 color grey = makecol24(127,127,127);
 color green = makecol24(0,255,0);
 color red = makecol24(255,0,0);
 color blue = makecol24(0,0,255);
 color cyan = makecol24(0,255,255);
 int show = 0;
 while(!key[KEY_G] && !key[KEY_ESC]){
  START:
  clear(buffer);
  textprintf_centre_ex(buffer,font,scrW / 2,24,blue,-1,"AERESHAA\'S");
  textprintf_centre_ex(buffer,font,scrW / 2 + 1,24,cyan,-1,"AERESHAA\'S");
#ifdef reloaded
  textprintf_centre_ex(buffer,font,scrW / 2,36,white,-1,"\"PONG RELOADED\"");
#else
  textprintf_centre_ex(buffer,font,scrW / 2,36,white,-1,"\"PONG\"");
#endif
  if(time(0) % 2)textprintf_centre_ex(buffer,font,scrW / 2 + 1,48,grey,-1,"press G to continue");
  if(!(time(0) % 2) && show != 1)textprintf_centre_ex(buffer,font,scrW / 2 + 1,56,grey,-1,"press H to show controls");
  if(key[KEY_H])show = 1;
  if(show == 1){
   textprintf_centre_ex(buffer,font,scrW / 2 + 1,68,grey,-1,"P1: W = up, S = down");
#ifdef reloaded
   textprintf_centre_ex(buffer,font,scrW / 2 + 1,76,grey,-1,"anomalies: Z,X,C");
#endif
   textprintf_centre_ex(buffer,font,scrW / 2 + 1,86,grey,-1,"P2: ^ = up, v = down");
#ifdef reloaded
   textprintf_centre_ex(buffer,font,scrW / 2 + 1,94,grey,-1,"anomalies: I,O,P");
#endif
  }
  stretch_blit(buffer,screen,0,0,scrW,scrH,0,0,scrW*2,scrH*2);
 }
 while(!key[KEY_ESC]){
  /*               /TIMING PHASE/                    * /
   *   Timing is very important, so it will be
   *   handled by using the nanosleep() function.
   */
  usleep(25000);
#ifdef reloaded
  P1_timeanom_pow++;
  P2_timeanom_pow++;
  P1_reflanom_pow++;
  P2_reflanom_pow++;
  P1_gravanom_pow++;
  P2_gravanom_pow++;
  if(P2_gravanom_dur){P2_gravanom_dur--;gravdir = 2;}
  else if(P1_gravanom_dur){P1_gravanom_dur--;gravdir = 1;}
  else if((P1_gravanom_dur) && (P2_gravanom_dur)){P2_gravanom_dur--;P1_gravanom_dur--;gravdir = 0;}
  else{gravdir = 0;}
#endif
  /*                /CONTROL PHASE/                  * /
   *    Control phase begins here. Both players will
   *    have access to easy controls for warps, time
   *    anomalies, gravity introduction, etc.
   */
  if(key[KEY_S])P1.yspd += 0.5;
  if(key[KEY_W])P1.yspd -= 0.5;
  if(key[KEY_DOWN])P2.yspd += 0.5;
  if(key[KEY_UP])P2.yspd -= 0.5;
  if(key[KEY_Y]){ //reset
  P1_score = 0;
  P2_score = 0;
  P1 = (MASS) {64,64,0.0,0.0};
  P2 = (MASS) {192,64,0.0,0.0};
  BL = (MASS) {128,64,-2.0,0.0};
  winner = 0;
#ifdef reloaded
  P1_timeanom_pow = 0;
  P2_timeanom_pow = 0;
  P1_gravanom_pow = 0;
  P2_gravanom_pow = 0;
  P1_gravanom_dur = 0;
  P2_gravanom_dur = 0;
  gravdir = 0;
  P1_reflanom_pow = 0;
  P2_reflanom_pow = 0;
#endif
  goto START;
  }
#ifdef reloaded
  if(key[KEY_Z] && P1_timeanom_pow > 200){
   P1.yspd = 0 - P1.yspd;
   P2.yspd = 0 - P2.yspd;
   BL.yspd = 0 - BL.yspd;
   BL.xspd = 0 - BL.xspd;
   P1_timeanom_pow = 0;
  }
  if(key[KEY_I] && P2_timeanom_pow > 200){
   P1.yspd = 0 - P1.yspd;
   P2.yspd = 0 - P2.yspd;
   BL.yspd = 0 - BL.yspd;
   BL.xspd = 0 - BL.xspd;
   P2_timeanom_pow = 0;
  }
  if(key[KEY_X] && P1_gravanom_pow > 400){
   P1_gravanom_dur = 50;
   P1_gravanom_pow = 0;
  }
  if(key[KEY_O] && P2_gravanom_pow > 400){
   P2_gravanom_dur = 50;
   P2_gravanom_pow = 0;
  }
  if(key[KEY_P] && P2_reflanom_pow > 200){
   BL.yspd = 0 - BL.yspd;
   BL.xspd = 0 - BL.xspd;
   BL.ypos = (128 - BL.ypos);
   BL.xpos = (256 - BL.xpos);
   P2_reflanom_pow = 0;
  }
  if(key[KEY_C] && P1_reflanom_pow > 200){
   BL.yspd = 0 - BL.yspd;
   BL.xspd = 0 - BL.xspd;
   BL.ypos = (128 - BL.ypos);
   BL.xpos = (256 - BL.xpos);
   P1_reflanom_pow = 0;
  }
#endif
  /*                 /PHYSICS PHASE/                 * /
   *   This game is very physics-intensive, so I will
   *   use the simplest algorithms I know. Time is the
   *   most complicated part.
   */
   /*Player One*/
  P1.ypos += (int) P1.yspd;
  if(P1.ypos > scrH){//bounce off walls
   P1.yspd = 0.0 - P1.yspd;
   P1.ypos = scrH;}
  if(P1.ypos < 0){//bounce off walls
   P1.yspd = 0.0 + -P1.yspd;
   P1.ypos = 0;}
  P1.yspd += (P1.yspd > 0.0)?(-0.2):
                           (P1.yspd < 0.0)?(0.2):(0.0);
   /*Player Two*/
  P2.ypos += (int) P2.yspd; color grey = makecol24(127,127,127);
  if(P2.ypos > scrH){//bounce off walls
   P2.yspd = 0.0 - P2.yspd;
   P2.ypos = scrH;}
  if(P2.ypos < 0){//bounce off walls
   P2.yspd = 0.0 + -P2.yspd;
   P2.ypos = 0;}
  P2.yspd += (P2.yspd > 0.0)?(-0.2):
                           (P2.yspd < 0.0)?(0.2):(0.0);
   /*Ball*/
  BL.ypos += (int) BL.yspd;
  BL.xpos += (int) BL.xspd;
  if(BL.ypos > scrH){ //bounce off walls
   BL.yspd = 0.0 - BL.yspd;
   BL.ypos = scrH;}
  if(BL.ypos < 0){ //bounce off walls
   BL.yspd = 0.0 + -BL.yspd;
   BL.ypos = 0;}
  if(BL.xpos < P1.xpos + 2 && BL.xpos > P1.xpos - 5
                           && BL.ypos > P1.ypos - (P1_size + 2)
                           && BL.ypos < P1.ypos + (P1_size + 2)){
   BL.xspd = 0.0 + -BL.xspd; // bounce off paddle 1.
   BL.xpos = P1.xpos + 2;
   BL.yspd += P1.yspd;}

  if(BL.xpos > P2.xpos - 2 && BL.xpos < P2.xpos + 5
                           && BL.ypos > P2.ypos - (P2_size + 2)
                           && BL.ypos < P2.ypos + (P2_size + 2)){
   BL.xspd = 0.0 + -BL.xspd; // bounce off paddle 2.
   BL.xpos = P2.xpos - 2;
   BL.yspd += P2.yspd;}
  if(BL.xpos > scrW){//score for P1
   BL.xspd = -2.0;
   BL.yspd = 0.0;
   P1_score++;
   BL.ypos = 64;
   BL.xpos = scrW / 2;}
  if(BL.xpos < 0){//score for P2
   BL.xspd = 2.0;
   BL.yspd = 0.0;  if(winner)textprintf_centre_ex(buffer,font,scrW / 2,0,red,-1,"!P%d Wins!",winner);
   P2_score++;
   BL.xpos = scrW / 2;
   BL.ypos = 64;}
#ifdef reloaded
   BL.xspd += (gravdir == 1)?(0.1):(gravdir == 2)?(-0.1):(0.0);
#endif
  /*                   /GAME PHASE/                   */
  if(P1_score == 15){
   winner = 1;}
  if(P2_score == 15){
   winner = 2;}
  /*                  /DRAWING PHASE/                 * /
   *   Drawing phase begins here. All game objects
   *   must be drawn, unless mitigating circumstances
   *   arise. I will use primitives wherever possible.
   */
  clear(buffer);
  textprintf_ex(buffer,font,0,0,grey,-1,"%d",P1_score);
#ifdef reloaded
  if(P1_timeanom_pow > 200)textprintf_ex(buffer,font,0,8,grey,-1,"time anomaly");
  if(P1_reflanom_pow > 200)textprintf_ex(buffer,font,0,24,grey,-1,"reflect anomaly");
  if(P1_gravanom_pow > 300)textprintf_ex(buffer,font,0,16,grey,-1,"gravity anomaly");
  if(P1_gravanom_dur)textprintf_ex(buffer,font,0,16,green,-1,"gravity anomaly");
#endif
  textprintf_right_ex(buffer,font,scrW,0,grey,-1,"%d",P2_score);
#ifdef reloaded
  if(P2_timeanom_pow > 200)textprintf_right_ex(buffer,font,scrW,8,grey,-1,"time anomaly");
  if(P2_reflanom_pow > 200)textprintf_right_ex(buffer,font,scrW,24,grey,-1,"reflect anomaly");
  if(P2_gravanom_pow > 300)textprintf_right_ex(buffer,font,scrW,16,grey,-1,"gravity anomaly");
  if(P2_gravanom_dur)textprintf_right_ex(buffer,font,scrW,16,green,-1,"gravity anomaly");
#endif
  textprintf_centre_ex(buffer,font,scrW / 2, 64, grey, -1, "%.3f", BL.yspd / BL.xspd);
  line(buffer,P1.xpos, P1.ypos + P1_size, P1.xpos, P1.ypos - P1_size, white);
  line(buffer,P2.xpos, P2.ypos + P2_size, P2.xpos, P2.ypos - P2_size, white);
  circle(buffer, BL.xpos, BL.ypos, 2, white);
  if(winner)textprintf_centre_ex(buffer,font,scrW / 2,0,red,-1,"!P%d Wins!",winner);
  stretch_blit(buffer,screen,0,0,scrW,scrH,0,0,scrW*2,scrH*2);
 }
 destroy_bitmap(buffer);
}END_OF_MAIN();


...Will add more.
  • 0

#7 hellochar

hellochar

    CC Newcomer

  • Just Joined
  • PipPip
  • 10 posts

Posted 13 July 2008 - 02:17 PM

I'm having a problem with set_close_button_handler(X_button_handler());. Code::Blocks gives me a compiler error stating "invalid use of void expression". Before that it gives me a warning - "warning: implicit declaration of function 'set close button handler'". I'm thinking the compiler isn't finding the function set_close_button_handler, but that doesn't make sense because I've imported allegro.h and all other functions work.

I'm using Allegro 4.2.1, Code::Blocks for my IDE, and the GNU GCC compiler (I installed MinGW for it).
  • 0

#8 Aereshaa

Aereshaa

    CC Devotee

  • Just Joined
  • PipPipPipPipPipPip
  • 638 posts

Posted 13 July 2008 - 05:53 PM

Oops, I gave the wrong name. It's set_close_button_callback(). Sorry about that.

Here is an example using fullscreen, and a loaded image, a matrix "digital rain" effect. (Attached.) Change the .txt extension to tga.

Attached Files


Edited by Aereshaa, 13 July 2008 - 06:25 PM.

  • 0

#9 shruti

shruti

    CC Newcomer

  • Just Joined
  • PipPip
  • 16 posts

Posted 27 July 2008 - 08:02 AM

I like it very much.i hope i'll enjoy the package.thank you very much for the information.
  • 0

#10 USMAN

USMAN

    CC Lurker

  • Just Joined
  • Pip
  • 2 posts

Posted 28 February 2009 - 11:06 AM

Very nice tut .. thanks for the effort m8 :)
  • 0

#11 rockeykiller

rockeykiller

    CC Lurker

  • Just Joined
  • Pip
  • 3 posts

Posted 02 March 2009 - 07:34 PM

i have been looking for the tut like this one thanks for your efforts mate :)
  • 0

#12 Aereshaa

Aereshaa

    CC Devotee

  • Just Joined
  • PipPipPipPipPipPip
  • 638 posts

Posted 29 September 2009 - 04:11 AM

Thank you. I just wanted to remind anyone read ing here of the difference between the 'blit'-family functions and the 'draw_sprite' functions. They are:
blit(src, dest, whatever else);
versus
draw_sprite(buffer, sprite, whatever else);
In other words, the order of the arguments is reversed. This sometimes screws people up, so I'm posting it here.
  • 0
Watches: Nanoha, Haruhi, AzuDai. Listens to: E-Type, Dj Melodie, Nightcore.
"When people are wrong they need to be corrected. And then when they can't accept it, an argument ensues." - MeTh0Dz





Also tagged with one or more of these keywords: php