Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411423 Posts in 69363 Topics- by 58416 Members - Latest Member: JamesAGreen

April 18, 2024, 05:00:36 PM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsCommunityTownhallForum IssuesArchived subforums (read only)TutorialsAllegro and C for complete noobs!!
Pages: [1] 2
Print
Author Topic: Allegro and C for complete noobs!!  (Read 15203 times)
Sos
Level 8
***


I make bad games


View Profile WWW
« on: March 11, 2010, 04:50:16 AM »

I notice there is actually no Allegro / C tutorial here so I am going to make one just now. Also I thought i should contribute to the society once instead of constant trolling.

This tutorial is going to be divided into 4 parts:
1. Installing and setting up MinGW
2. Installing allegro on top of it.
3. Installing Code::Blocks
4. Writing a game


At the end of this tutorial you will have a game ready.
So, let us begin!

Installing and setting up MinGW

Download MinGW

MinGW is a GCC compiler port for Windows. Of course you can get Visual C++ 2008 Express, but it's waaay easier to get started with MinGW.

Go to MinGW Download Page



Download the setup file using the Download Now! button.

Run the downloaded file (It's about 200kb web install and will download everything in the process)

Install MinGW

Now a setup window should appear.

From the first screen select Download and Install



Then choose Current version



When it asks for the components to install, I'd prefer you install all of them, select Full install option. But if you don't want this, then you HAVE TO select:
- MinGW Base
- g++
- Obj-C
- Make



Your destination folder MUST BE C:\MinGW

Then agree on the Start Menu location and wait for it to download and install.

Setting up enviroment

Now go to your System properties control panel.
- In Windows XP just right-click My Computer and select properties from the drop-down menu.
- In Windows Vista/7 it's somewhere too, I believe.

Also, sorry that my screenshots are in polish, but the stuff's in the same place regardless of a language, and they can be of some help.

In the Window, navigate to Advanced tab.



Click the Enviroment Variables button below



Now it's time to edit the values. If you do not have admin rights on your system, then edit User variables (box above), but it's safer to edit the System variables (box below).

First, navigate to PATH variable and tap Edit button.



Add C:\MinGW\bin to the end of the string, separating it from other paths with semicoloon ;



Then click New button to create a new variable. Set the variable name to MINGDIR (all caps) and value to C:\MinGW




Apply and accept all the changes. Now you HAVE TO restart your system.



Installing allegro on top of MinGW

After your PC started again, go to Allegro download page

Navigate to below, and download the dx80_mgw.zip package.



When you're done downloading, extract the package to C:\MinGW directory overwriting anything if it wants to. You should also notice that this zip contains two directories lib and include, just as MinGW directory does.

Now download the allegro source code. You want the 4.2.3.1 version. It's under Older stable branch category.



When it downloads, it's time to set up a directory to hold all the projects. You have to make sure it's not hidden somewhere in My Documents or so. Make it directly on the root directory, eg. c:\gamdev

Now extract allegro source to that directory.



And run command prompt
- In windows XP go to start menu and select Run... in the window type cmd and press enter
- In windows vista/7 right click your taskbar, go to properites, start menu tab and click Customize... button. In the checklist hunt down and check the Run... command field. Now you have the access to Run... command from your start menu.

In the command prompt naviagate to allegro folder by typing cd \gamdev\allegro



Then you have to tell allegro that you're going to use MinGW. To do that type fix.bat mingw



After that's done,  type mingw32-make all and go get some coffee Coffee. It's going to take some time (and if you think you've got turbo-ultra-fast-computer and it's going to take a minute or so, then YOU'RE WRONG)



It should indicate it's done by getting back to command prompt and NOT sygnalising error right before that. When this happens, type mingw32-make install, and after a short while you've got allegro installed and ready.

Installing and configuring Code::Blocks

Go to Code::Blocks SF.net Download pageand click Download Now! button to start downloading.



Install Code::Blocks somewhere, there's no catch to it, just install it as you do with usual software.

After installing run it, it should detect GNU GCC compiler automatically. Let this be your default compiler.

Now when the IDE is on and you're done with reading tips of the day, Go to menu Settings / Compiler and Debugger.



Go to Linker settings tab and Click Add  button to add these libraries (ORDER DOES MATTER):
- C:\MinGW\lib\libgdi32.a
- C:\MinGW\lib\libuser32.a
- C:\MinGW\lib\libcomdlg32.a



Then go to Toolchain executables to make sure it looks like on the screenshot.



When you're done, tap OK button and get ready to do some coding.

Or, you can go to Editor opttions in the Settings menu and make the colouring match your own preferences. My workspace looks like this:



OK, now get this all done, while I'm writing the follow-up containing actual game coding.
« Last Edit: March 11, 2010, 06:12:33 AM by Sos » Logged

Sos
Level 8
***


I make bad games


View Profile WWW
« Reply #1 on: March 11, 2010, 06:00:49 AM »

OK, now it'stime to do some badass C coding, no more pictures, just pure code Smiley

If you are familiar with Game Maker Language, this is going to be easy as hell.

Run your Code::Blocks, click 'New File" icon and save it as something.c before you write anything inside. If you don't save it, it will not highlight the syntax.

Basic basics

I will write the tutoriial like documented code, so you can copypaste code boxes one by one.

First thing we need are includes, we just include some predefined functions soo we can use them later on.

Code:
#include <stdio.h>
#include <allegro.h>

Right after includes, there are defines

Code:
#define WIDTH 320
#define HEIGHT 240

This means, we define WIDTH as 320 and HEIGHT as 240, these are like constants, but it works a bit different.
Compiler will replace every occurence of WIDTH and HEIGHT with the actual values before compiling, so if you have a variable named MyButtWIDTH, it will change it to MyButt320 and probably give an error somewhere in the process.

Next thing in the C file are global variables declarations, so here we go

Code:
BITMAP *buffer,*player_bmp;
volatile int tim;
int player_x,player_y;

It goes like this
type name,name2,*pointer1,*pointer2;
So buffer and player_bmp point to bitmaps (you don't need to care what pointers are for now)
player_x and player_y are integer values.
tim is a volatile variable, it will be used between our game process and a timer, and it should not be touched otherwise.

Types you need to worry about are:

General ones:


int - signed integer
float - floating point real value
char - one byte,either -128..127 or any ASCII value in single quotes, like 'a', 'z'
if you want unsigned values, add unsigned keyword before, like

unsigned int
unsigned char - that'd be 0..255, pretty helpful for colour values

Allegro ones:
BITMAP - as you can expect, a bitmap it is
SAMPLE - sound
fixed - fixed point number - 16 bit integer value + 16 bit fraction

The capitalised ones are structs, and you should always declare them with asterisk before.

Types that doesn't exist in C:
string - you just use array of chars.
boolean - you just use int, 0 is false, non-0 is true

OK, now we need some functions to get started, I prepared three of them.

Code:
void draw()
{

}

This function will draw anything you want.

Code:
void timer_proc()
{

}

This is a timed function, it will execute at regular intervals

Code:
void load_stuffs()
{

}

This function will load everything we need.

We are going to populate the functions later on. First, let's finish writing the framework.

The next function is a timer function, it will increase the timer variable for us. It should not be doing anything else, since it can be  hazardous.

Code:
void timer()
{
tim++;
}
END_OF_FUNCTION(timer);

It ends with this END_OF_FUNCTION thingie to tell allegro to take good care of this function.

Now it's tthe main part, so the entry point of our application, let's go.

Code:
int main(int argc, char *argv[])
{
    allegro_init();  // Initialise allegro lib
    install_keyboard();  // install keyboard functionality
    install_timer(); // install timer functionality
    install_mouse(); // install mouse driver
    install_sound(DIGI_AUTODETECT, MIDI_NONE, argv[0]); // install sound driver
    set_color_depth(32); // set colour depth to 32-bit
    set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0); // open 640x480 window
   

This initialisation sequence is self-explanatory I believe. Do not worry about this argc and argv thingies, you don't need them now, but remember to keep them there.
You should also notice that main function has int before instead of void, this means it can return a value, we'll get to that later, now let's proceed.

Code:
    srand(time(NULL));

This seeds the randomiser with current time.

Code:
    buffer = create_bitmap(WIDTH, HEIGHT);

This will create a new buffer bitmap, with dimension specified above in the #define section (320x240)

Code:
    load_stuffs();

This calls the load_stuffs function. We will populate that later on.

Code:
    install_int_ex(timer, BPS_TO_TIMER(60));
    LOCK_FUNCTION(timer);
    LOCK_VARIABLE(tim);

This here installs timer interrupt, this means that timer function will be called 60 timer per second. LOCK_ stuff is for safety here.

Code:
    while(!key[KEY_ESC])  // this all will repeat until esc is pressed
    {
      clear_to_color(buffer, makecol(255, 255, 255)); // clears screen

      while (tim > 0)  // this here will happen only limited time a second
      {                // it will also make up for lost cycles
      timer_proc();
      tim--;
    }

      draw();
      stretch_blit(buffer,screen,0,0,WIDTH,HEIGHT,0,0,SCREEN_W,SCREEN_H);
        // this last function copies our buffer to the screen
    }

This is our main loop, it will go on until someone taps esc button. As for stretch_blit, the allegro manual says:

Quote
void stretch_blit(BITMAP *source, BITMAP *dest, int source_x, source_y, source_width, source_height, int dest_x, dest_y, dest_width, dest_height);

So it will just stretch the buffer bitmap to the whole screen.

Now it's time for closing functions.
Code:
    remove_timer();
    remove_sound();
    allegro_exit();
    return 0;
}
END_OF_MAIN();

This will exit allegro and terminate the program.

When you're done copypasting this into your .c file, tap F9 to compile and run it.
A box should appear below containing compiler output. After it's done the compiled program will run automatically and you should see an empty white window
This is what you should see in the compiler output:
Code:
Compiling: C:\msys\1.0\src\sandra\something.c
Linking console executable: C:\msys\1.0\src\sandra\something.exe
Process terminated with status 0 (0 minutes, 0 seconds)
0 errors, 0 warnings
 
Checking for existence: C:\msys\1.0\src\sandra\something.exe
Executing: C:\Program Files\CodeBlocks/cb_console_runner.exe "C:\msys\1.0\src\sandra\something.exe" (in C:\msys\1.0\src\sandra)
Process terminated with status 0 (0 minutes, 6 seconds)

You can close / open the box using F2 button.
« Last Edit: March 11, 2010, 10:29:20 AM by Sos » Logged

Sos
Level 8
***


I make bad games


View Profile WWW
« Reply #2 on: March 11, 2010, 10:28:39 AM »

Basic gameplay

OK, now we will populate our empty fuctions we declared before. They are already called in the proper places so we just need to type stuff inside them.

First, make an image, and save it as BMP in the same folder that your .c file is. Magic pink is for transparent in allegro. Let it be player.bmp



Now let's modify our loading function to load this bitmap and set up initial position.

Code:
void load_stuffs()
{
  player_bmp = load_bmp("player.bmp",NULL); // load player bitmap
  player_x=160; // set initial position
  player_y=120;
}

Ok,now the bitmap is loaded, but it won't display (you can compile and check if you want to)
We have to modify the drawing function too.

Code:
void draw()
{
  // draw player bitmap at its position
  draw_sprite(buffer,player_bmp,player_x,player_y);
}

When you compile now, you should see the bitmap near the centre of the screen.  Why not IN the center? because the hot-spot for bitpams is upper-left corner, but since we can determine the size of the bitmap, it will be an easy thing to fix.
So let's change the draw_sprite lien to this:
Code:
draw_sprite(buffer,player_bmp,player_x-(player_bmp->w/2),player_y-(player_bmp->h/2));

player_bmp->w and player_bmp->h gets members of the struct callled  w and h. You can do that with any bitmap.

Basically we are subtracting half the width from the position do it will display at the right spot regardless of the  bitmaps size.

But, this is still not a  game, so let us modify the timer_proc function and add some interaction.

Code:
void timer_proc()
{
  if (key[KEY_UP]) player_y--;
  if (key[KEY_DOWN]) player_y++;
  if (key[KEY_LEFT]) player_x--;
  if (key[KEY_RIGHT]) player_x++;
}

This 4 lines will either increase (++) or decrease (--) player x and y position variables when keys are pressed.

Now compile and see how it works.
You should have noticed, that your player can go out of the screen easily, let us fix this.
Code:
void timer_proc()
{
  if (key[KEY_UP] && player_y>0)        player_y--;
  if (key[KEY_DOWN] && player_y<HEIGHT) player_y++;
  if (key[KEY_LEFT] && player_x>0)      player_x--;
  if (key[KEY_RIGHT] && player_x<WIDTH) player_x++;
}

This means, 'if up is pressed and player y position is bigger than 0, decrease plaer y position', and so on accordingly to the key.

Now we will add add animation to the player character. To do that, we need another bitmap variable, and a frame indicator variable, that will tell the program which frame to display, let's do this. First draw the second frame and save it as player2.bmp. Make sure it's the same size that the first one.



Now locate this line (near the beginning)
Code:
BITMAP *buffer,*player_bmp;
and change that to:
Code:
BITMAP *buffer,*player_bmp[2];

Now you have an array of 2 bitmaps, they can be accessed via player_bmp[0] and player_bmp[1]. We need to reword some part of the code to get that working properly. if you try to compile now, it will compile, but crash, so do not do this until we're done with this.

Now we need player_frame variable to tell the program, which frame to access, let's add it to int variables line

Code:
int player_x,player_y,player_frame;

We also need to modify the loading function to load two bitmaps instead of one

Code:
void load_stuffs()
{
  player_bmp[0] = load_bmp("player.bmp",NULL); // load player bitmap
  player_bmp[1] = load_bmp("player2.bmp",NULL); // bitmap second frame
  player_x=160; // set initial position
  player_y=120;
  player_frame=0; // set current frame to 0
}

Also, we need to tweak the display function to draw the proper frame of the character.

Code:
void draw()
{
  // draw player bitmap at its position
   draw_sprite(buffer,player_bmp[player_frame],player_x-(player_bmp[player_frame]->w/2),player_y-(player_bmp[player_frame]->h/2));

}



player_bmp[player_frame] will access frame 0 of the bitmap if player_frame==0 or frame 1 if player_frame==1
Also you should notice, that when accessing width and height of the bitmap, we also need to pass the frame number.

you can compile now and see that it's still not animating.

We need to modify the timer_proc function to change the player_frame value for us, so:
Code:
void timer_proc()
{
  if (key[KEY_UP] && player_y>0)        player_y--;
  if (key[KEY_DOWN] && player_y<HEIGHT) player_y++;
  if (key[KEY_LEFT] && player_x>0)      player_x--;
  if (key[KEY_RIGHT] && player_x<WIDTH) player_x++;
  player_frame^=1; //change the frame
}

player_frame^=1 means the same as player_frame=player_frame^1, ^ is exclusive-or, or flip for short,it will flip between 1 and 0.
If you compile now, you can see that your player got a serious seizure, let's run a biopsy! Uhhh.. I mean let's fix this Tongue

To do this you need some understanding of bits. When you increase a number by one, its first bit flips 0->1, when it flips 1->0, it also flips the second bit, so the second bitip flipping 2 times slower than the first one. the 3rd bit flips 4 times slower, 4th 8 times slower etc.
So, what we will do is:

Add another variable:
Code:
int player_x,player_y,player_frame,player_frame_counter;
and change the timer code:
Code:
void timer_proc()
{
  if (key[KEY_UP] && player_y>0)        player_y--;
  if (key[KEY_DOWN] && player_y<HEIGHT) player_y++;
  if (key[KEY_LEFT] && player_x>0)      player_x--;
  if (key[KEY_RIGHT] && player_x<WIDTH) player_x++;
  player_frame_counter++;
  player_frame=1 & (player_frame_counter>>4); //change the frame
}
This last line will shift (>>) the player frame counter right, so e.g here the 4th bit will become the first bit, and it ill AND (&) the value with one, so only first bit will be able to have either 1 or 0 values, and all other values will be 0. Let me picture that for you

Code:
player_frame_counter = 56;
56       - 00111000
56>>1    - 00011100
56>>2    - 00001110
56>>3    - 00000111
56>>4    - 00000011
1&(56>>4)- 00000001

Now we have an animated player Smiley but we want it to animate ONLY when walking. Nothing easier. let's do it like this:

Code:
void timer_proc()
{
  if (key[KEY_UP] && player_y>0)        {player_y--;player_frame_counter++;}
  if (key[KEY_DOWN] && player_y<HEIGHT) {player_y++;player_frame_counter++;}
  if (key[KEY_LEFT] && player_x>0)      {player_x--;player_frame_counter++;}
  if (key[KEY_RIGHT] && player_x<WIDTH) {player_x++;player_frame_counter++;}
  player_frame=1 & (player_frame_counter>>4); //change the frame
}
As you should have noticed, we put the player_frame_counter++; into the key press condition, so it will be called only when keys are pressed.
Logged

Sos
Level 8
***


I make bad games


View Profile WWW
« Reply #3 on: March 11, 2010, 10:28:51 AM »

Enemies and AI

Now let's add an enemy, but firs we need a game design. I already have an idea for that.

Quote
You are a psycho killer and want to kill badly!

So we actually need to ad victim, not an enemy. Let's draw one
Frame 0:

Frame 1:


Now let's add variables for the victim.
Code:
BITMAP *buffer,*player_bmp[2],*victim_bmp[2];
volatile int tim;
int player_x,player_y,player_frame,player_frame_counter;
int victim_x,victim_y,victim_frame,victim_frame_counter;

And modify loading function to load it.
Code:
void load_stuffs()
{
  player_bmp[0] = load_bmp("player.bmp",NULL); // load player bitmap
  player_bmp[1] = load_bmp("player2.bmp",NULL); // bitmap second frame
  player_x=80; // set initial position
  player_y=60;
  player_frame=0; // set current frame to 0
  player_frame_counter=0;
 
  victim_bmp[0] = load_bmp("victim.bmp",NULL); // load victim bitmap
  victim_bmp[1] = load_bmp("victim2.bmp",NULL); // bitmap second frame
  victim_x=240; // set initial position
  victim_y=180;
  victim_frame=0; // set current frame to 0
  victim_frame_counter=0;
}

As you can see we modified the initial positions, so that they do not overlap.
Now let it display the victim as well as the player

Code:
void draw()
{
  // draw player bitmap at its position
  draw_sprite(buffer,victim_bmp[victim_frame],victim_x-(victim_bmp[victim_frame]->w/2),victim_y-(victim_bmp[victim_frame]->h/2));
  draw_sprite(buffer,player_bmp[player_frame],player_x-(player_bmp[player_frame]->w/2),player_y-(player_bmp[player_frame]->h/2));
}



You should notice that the victim is drawn BEFORE the player, so that when they overlap, player will cover the victim.

Now let's add AI to this victim. We will need additional variables for that, add them where the global variables are.

Code:
int victim_xv,victim_yv,victim_step_counter;
xv and yv is a vector, the direction that our character will move. step counter will count after how many cycles to regenerate the vector. You should also set the step counter to 0 in the loading function

Code:
victim_step_counter=0;

Now let's head to timer_proc and add the AI

Code:
void timer_proc()
{
  if (key[KEY_UP] && player_y>0)        {player_y--;player_frame_counter++;}
  if (key[KEY_DOWN] && player_y<HEIGHT) {player_y++;player_frame_counter++;}
  if (key[KEY_LEFT] && player_x>0)      {player_x--;player_frame_counter++;}
  if (key[KEY_RIGHT] && player_x<WIDTH) {player_x++;player_frame_counter++;}
  player_frame=1 & (player_frame_counter>>4); //change the frame

  victim_frame_counter++;
  victim_frame=1 & (victim_frame_counter>>3); //change the frame
  if (victim_step_counter)
  {
    victim_x+=victim_xv;
    victim_y+=victim_yv;
    victim_step_counter--;
  } else {
    victim_xv=3-(rand()%7);
    victim_yv=3-(rand()%7);
    victim_step_counter=20+(rand()%20);
  }
}

The frame flipper for the victim is just a copy off player's one, but it will flip all the time.
Now the if-part. if (victim_step_counter) means the same as if (victim_step_counter!=0) (not equal 0). So if it's not equal 0, it will add vectors to the position values and decrease the counter. When the couunter reaches 0, it will randomize the values. rand()%7 will return a random value from 0 to 6.

You can compile now and see that our victim can get away from being killed waaay too easy, because he can go past screen boundaries. Let's change that.

But instead of blocking it's way out of the screen, we will flip the vector values, so that he will bounce off the screen boundaries.

Code:
void timer_proc()
{
  if (key[KEY_UP] && player_y>0)        {player_y--;player_frame_counter++;}
  if (key[KEY_DOWN] && player_y<HEIGHT) {player_y++;player_frame_counter++;}
  if (key[KEY_LEFT] && player_x>0)      {player_x--;player_frame_counter++;}
  if (key[KEY_RIGHT] && player_x<WIDTH) {player_x++;player_frame_counter++;}
  player_frame=1 & (player_frame_counter>>4); //change the frame

  victim_frame_counter++;
  victim_frame=1 & (victim_frame_counter>>3); //change the frame
  if (victim_step_counter)
  {
    victim_x+=victim_xv;
    victim_y+=victim_yv;
    if (victim_x<0 || victim_x>WIDTH) {victim_xv*=-1;victim_step_counter+=10;} //this line
    if (victim_y<0 || victim_y>HEIGHT) {victim_yv*=-1;victim_step_counter+=10;} //this line
    victim_step_counter--;
  } else {
    victim_xv=3-(rand()%7);
    victim_yv=3-(rand()%7);
    victim_step_counter=20+(rand()%20);
  }
}

We added two lines. They read as follows 'if victim is out the screen,make him go the opposite direction and inscrease step counter by 10'.
Why increase the step counter? because when we flip the direction he's going, he's is still out of the screen, but 'about' to go the opposite way. Now when this happens when counter reaches 0, he might get stuck in screen boundaries, so apart from setting his direction back to the screen, we have to make sure he actually goes there.

Ok, so now we have to be able to actually murder him. We will need a new function for that

Code:
int distance(int x1,int y1,int x2,int y2,int dist)
{
 int xx,yy,d;
 xx=x2-x1; // x distance
 yy=y2-y1; // y distance
 d=xx*xx+yy*yy;
 if (d>(dist*dist)) return 0; else return 1;
}

Add this just before the first function, so that this is the first function. The function takes two points and a distance and calculate whether the point distance is closer or further than the given distance.

Now let's check it this work. We want the victim to bleed when caught. Let's make bleeding function then.

Code:
void bleed(BITMAP *bmp,int howmuch)
{
  int c,x,y;
  // it will make howmuch blood spots on the bmp bitmap
  for (c=0;c<howmuch;c++)
  {
    x=rand()%bmp->w; // randomize point on bitmap
    y=rand()%bmp->h;
    // if pixel at x,y is not magic pink it will put a randomnly red dot there
    if (getpixel(bmp,x,y)!=makecol(255,0,255)) putpixel(bmp,x,y,makecol(128+(rand()%127),0,0));
  }
}
Put this function right after distance function.
It uses the for loop to make an amount of spots at random places on the bmp bitmap. It also checks not to draw on the transparent parts of the bitmap.

Now let's call it from timer_proc.
Add this at the end of the timer_proc function
Code:
  if (distance(player_x,player_y,victim_x,victim_y,32))
  {
    bleed(victim_bmp[0],20);
    bleed(victim_bmp[1],20);
  }

When you compile you'll see that it actually works, and victim bleeds when near the killer.

Ok, now let's add some eye-candy. We desperadetly need background, let's steal one.



Let's make a variable for it.

Code:
BITMAP *buffer,*player_bmp[2],*victim_bmp[2],*bg;

And load it into the variable (in the loading function)
Code:
bg = load_bmp("street.bmp",NULL);

Now let's display it as well.
Add this to the beggining of draw function or it will cover everything.
Code:
stretch_blit(bg,buffer,0,0,bg->w,bg->h,0,0,WIDTH,HEIGHT);

You can compile now and see that it works pretty well. BUT WAIT! Why the character  is not bleeding onto the street? let's make some mess here.
We'll make a function that draws random red circles on the bg bitmap.

Code:
void mess(BITMAP *bmp,int x,int y)
{
  circlefill(bmp,x+(rand()%64),y+(rand()%64),4+(rand()%4),makecol(128+(rand()%127),0,0));
}
This will draw some circles nearby x and y on the  bmp bitmap. Now let's this happen when we are near the victim, so change this is your timer_proc
Code:
  if (distance(player_x,player_y,victim_x,victim_y,32))
  {
    bleed(victim_bmp[0],20);
    bleed(victim_bmp[1],20);
  }
To this:
Code:
  if (distance(player_x,player_y,victim_x,victim_y,32))
  {
    bleed(victim_bmp[0],20);
    bleed(victim_bmp[1],20);
    mess(bg,victim_x-(victim_bmp[0]->w/2),victim_y-(victim_bmp[0]->h/2));
  }
You can see that we're subtracting half of bitmap width from the position, this is because we also add  this half of width when drawing it.

Now let's check that out! You should see it's working, but the circles look weird on the bg, let's change it to ellipses!

Code:
void mess(BITMAP *bmp,int x,int y)
{
  int r;
  r= 4+(rand()%4);
  ellipsefill(bmp,x+(rand()%64),y+(rand()%64),r,r/2,makecol(128+(rand()%127),0,0));
}
You should notice that we precalculate the ellipse radius, this is because we want vertical radius to be half of the horizontal radius, instead of two random values.

That would conclude the tutorial.



PS. To change killer to rapist, you should writte your mess and bleed functions like this:

Code:
void bleed(BITMAP *bmp,int howmuch)
{
  int c,x,y,col;
  // it will make howmuch blood spots on the bmp bitmap
  for (c=0;c<howmuch;c++)
  {
    col=192+(rand()%63);
    x=rand()%bmp->w; // randomize point on bitmap
    y=rand()%bmp->h;
    // if pixel at x,y is not magic pink it will put a randomnly red dot there
    if (getpixel(bmp,x,y)!=makecol(255,0,255)) putpixel(bmp,x,y,makecol(col,col,col));
  }
}

void mess(BITMAP *bmp,int x,int y)
{
  int r,col;
  r= 4+(rand()%4);
  col=192+(rand()%63);
  ellipsefill(bmp,x+(rand()%64),y+(rand()%64),r,r/2,makecol(col,col,col));
}

MAK SOME ALLEGRO GAMS, NAO!!!
Logged

J. Kyle Pittman
Level 6
*


PostCount++;


View Profile WWW
« Reply #4 on: March 11, 2010, 12:04:03 PM »

Quote
This means, we define WIDTH as 320 and HEIGHT as 240, these are like constants, but it works a bit different.
Compiler will replace every occurence of WIDTH and HEIGHT with the actual values before compiling, so if you have a variable named MyButtWIDTH, it will change it to MyButt320 and probably give an error somewhere in the process.
Not sure about other compilers, but MSVC won't do this.  In fact, if you want that behavior, you have to jump through some hoops involvings multiple #defines and use of the ## concatenation operator.  For instance:

Code:
#define WIDTH 320

#define ConcatTokens(x,y) x##y
#define ConcatTokensWrapper(x,y) ConcatTokens(x,y)

int main()
{
    int MyButt320;

    MyButtWIDTH = 1;                        // Wrong.  "error C2065: 'MyButtWIDTH' : undeclared identifier"
    ConcatTokens(MyButt,WIDTH) = 1;         // Wrong.  "error C2065: 'MyButtWIDTH' : undeclared identifier"
    ConcatTokensWrapper(MyButt,WIDTH) = 1;  // Correct.

    return 0;
}
Logged

Sos
Level 8
***


I make bad games


View Profile WWW
« Reply #5 on: March 11, 2010, 12:48:05 PM »

Not sure about other compilers, but MSVC won't do this.  In fact, if you want that behavior, you have to jump through some hoops involvings multiple #defines and use of the ## concatenation operator.  For instance:

It's about GCC. VC stinks. Also, I don't get why someone would like that behaviour.
Logged

Draknek
Level 6
*


"Alan Hazelden" for short


View Profile WWW
« Reply #6 on: March 11, 2010, 03:16:42 PM »

No standard-confirming compiler will convert MyButtWIDTH into MyButt320. Macros are only matched if the entire identifier is matched.
Logged

Sos
Level 8
***


I make bad games


View Profile WWW
« Reply #7 on: March 15, 2010, 03:45:11 PM »

WHERE ARE YOUR ALLEGRO GAMS!!!!!!!!!!!!!!!!?Huh?Huh?Huh?Huh?Huh?
Logged

oahda
Level 10
*****



View Profile
« Reply #8 on: March 20, 2010, 04:14:06 AM »

Man... why... why Windows? Why... why encourage Windows as the main OS for programming C..?
Man... why..?

Man...

Code:
sudo apt-get install g++ codeblocks

At least it's C. Very nice.
I haven't really worked with Allegro myself, but I once watched a timelapse of a guy quickly making a game with it, on YouTube.
Logged

gnat
Level 1
*



View Profile WWW
« Reply #9 on: March 20, 2010, 12:47:57 PM »

Wow, Sos spends a load of time making a fairly complete tutorial and all of the responses are criticism (at least most of this is constructive) and stabs at his methods due to personal preference.

So typical of the programming community.

Good work Sos.
Logged

LAN Party List - The definitive LAN party list. Also Game Jams, etc.
GitHub
Lee
Level 1
*


View Profile
« Reply #10 on: March 20, 2010, 04:57:55 PM »

nice tutorial, would have liked it if it were around when I was trying to build and install allegro, infuriating when it doesn't work. good job
Logged
Skofo
Level 10
*****



View Profile
« Reply #11 on: March 20, 2010, 05:04:17 PM »

Buh. WTF

Code:
C:\gamedev\allegro>mingw32-make all
mingw32-make msg lib
mingw32-make[1]: Entering directory `C:/gamedev/allegro'
sh: C:\Program: No such file or directory
mingw32-make[1]: *** [msg] Error 127
mingw32-make[1]: Leaving directory `C:/gamedev/allegro'
mingw32-make: *** [all] Error 2

Plaes halp. Sad I made sure that MinGW is in C:\, and tried setting the environment variables you gave me both in system and in user, but I still get that same accursed error. I'm using 64-bit Windows 7.
Logged

If you wish to make a video game from scratch, you must first invent the universe.
Ajene
Guest
« Reply #12 on: March 20, 2010, 05:42:56 PM »

Very nice, though I prefer to use the Dev-C++ IDE with allegro.
Logged
Sos
Level 8
***


I make bad games


View Profile WWW
« Reply #13 on: March 21, 2010, 07:16:39 AM »

Man... why... why Windows? Why... why encourage Windows as the main OS for programming C..?
Man... why..?

Man...

1. Linux gaming barely exists
2. Allegro sucks on Linux
3. You want someone to actually play your gams, no?

Wow, Sos spends a load of time making a fairly complete tutorial and all of the responses are criticism (at least most of this is constructive) and stabs at his methods due to personal preference.

So typical of the programming community.

Good work Sos.

Thanks Smiley

nice tutorial, would have liked it if it were around when I was trying to build and install allegro, infuriating when it doesn't work. good job

Have you noticed 'docs' directory bundled with allegro source?

Buh. WTF

Code:
C:\gamedev\allegro>mingw32-make all
mingw32-make msg lib
mingw32-make[1]: Entering directory `C:/gamedev/allegro'
sh: C:\Program: No such file or directory
mingw32-make[1]: *** [msg] Error 127
mingw32-make[1]: Leaving directory `C:/gamedev/allegro'
mingw32-make: *** [all] Error 2

Plaes halp. Sad I made sure that MinGW is in C:\, and tried setting the environment variables you gave me both in system and in user, but I still get that same accursed error. I'm using 64-bit Windows 7.

Why did you install MinGW to 'program files'?
Logged

Falmil
Level 6
*


View Profile
« Reply #14 on: March 21, 2010, 09:57:52 AM »

File and directory names with spaces are not your friend.
Logged
Skofo
Level 10
*****



View Profile
« Reply #15 on: March 21, 2010, 12:33:56 PM »

Why did you install MinGW to 'program files'?

Why did you not read what I wrote?

Quote from: Skofo
I made sure that MinGW is in C:\
Logged

If you wish to make a video game from scratch, you must first invent the universe.
Falmil
Level 6
*


View Profile
« Reply #16 on: March 21, 2010, 12:49:37 PM »

It should be C:\MinGW, not C:\Program Files\MinGW.
Logged
Skofo
Level 10
*****



View Profile
« Reply #17 on: March 21, 2010, 01:37:19 PM »

Facepalm

It is not in Program Files.
Logged

If you wish to make a video game from scratch, you must first invent the universe.
Falmil
Level 6
*


View Profile
« Reply #18 on: March 21, 2010, 02:24:21 PM »

Well, its trying to access Program Files for some reason, except the path isn't in quotes, so it chopped off the path after the space in 'Program Files'. It would be easier to figure out the problem if it was clear what it was trying to access. That's my guess anyway. I hate compiling from source and I didn't follow the tutorial so I have no idea what really went wrong.
Logged
salade
Level 4
****



View Profile
« Reply #19 on: March 21, 2010, 05:02:36 PM »

Facepalm

My best guess is that something in the makefile is trying to acess the Program Files directory, despite your best intentions. Why this is happening only to you is a mystery...

Anyway, allegro's windows distribution method is just flawed and not worth your trouble. Just use Devpacks. There's supposed to be a Code::Blocks pluggin for them.

Logged
Pages: [1] 2
Print
Jump to:  

Theme orange-lt created by panic