Code:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <process.h>
#include <SDL/SDL.h>
#define MAX_SPACE_IMAGES 3
#define SCREEN_WIDTH 920
#define SCREEN_HEIGHT 518
#define FRAMES_PER_SECOND 70
#define SPACE_UPDATE_FRAME 20
#define MAX_LASER_QUEUE 1
#define MAX_ENEMIES 15
#define TRUE 1
#define FALSE 0
typedef struct enemy_fighter
{
SDL_Surface * image;
int x;
int y;
unsigned is_dead:1;
unsigned move_right:1;
unsigned move_left:1;
unsigned move_down:1;
} enemy_fighter;
typedef struct laser
{
SDL_Rect shape;
int node_id;
int speed;
struct laser * next;
} laser;
void SDL_errorexit( const char * error_message )
{
char buffer[BUFSIZ];
sprintf(buffer, "%s : %s", error_message, SDL_GetError());
fprintf(stderr, "%s", buffer);
exit(1);
}
void init_SDL( )
{
if ( SDL_Init( SDL_INIT_EVERYTHING ) < 0 )
SDL_errorexit("SDL_Init");
return;
}
laser * create_list_node( )
{
laser * temp = NULL;
if ( !(temp = malloc(sizeof(*temp))) )
{
perror("Malloc");
exit(1);
}
return temp;
}
laser * append_list( laser * lasers, int id, int speed, int x, int y, int w, int h )
{
laser * temp = NULL;
if ( !lasers )
{
lasers = create_list_node( );
lasers->node_id = id;
lasers->speed = speed;
lasers->shape.h = h;
lasers->shape.x = x;
lasers->shape.y = y;
lasers->shape.w = w;
lasers->next = NULL;
} else
{
for ( temp = lasers; temp->next; temp = temp->next );
temp->next = create_list_node();
temp->next->node_id = id;
temp->next->speed = speed;
temp->next->shape.h = h;
temp->next->shape.x = x;
temp->next->shape.y = y;
temp->next->shape.w = w;
temp->next->next = NULL;
}
return lasers;
}
laser * remove_first_node( laser * lasers )
{
laser * temp = lasers;
lasers = lasers->next;
free(temp);
return lasers;
}
void release_list( laser * lasers )
{
laser * temp = NULL;
while ( lasers )
{
temp = lasers;
lasers = lasers->next;
free(temp);
}
return;
}
SDL_Surface * load_image_opt( char * image_path, int is_transparent )
{
SDL_Surface * image = NULL;
SDL_Surface * temp_image = SDL_LoadBMP(image_path);
if ( !temp_image )
SDL_errorexit("SDL_LoadBMP");
if ( is_transparent )
SDL_SetColorKey( temp_image, SDL_SRCCOLORKEY, SDL_MapRGB(temp_image->format, 255, 255, 255) );
image = SDL_DisplayFormat( temp_image );
SDL_FreeSurface( temp_image );
return image;
}
SDL_Surface * set_video_mode( const char * window_title )
{
SDL_Surface * console = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, 24, SDL_SWSURFACE | SDL_DOUBLEBUF );
SDL_WM_SetCaption( window_title, "N/A" );
if (!console)
SDL_errorexit("SDL_SetVideoMode");
return console;
}
void game_intro( SDL_Surface ** space, SDL_Surface * title, SDL_Surface * console )
{
SDL_Rect title_rect;
int offset = 0;
int iteration;
title_rect.x = (console->w - title->w) / 2;
title_rect.y = (console->h - title->h) / 2;
title_rect.h = title->h;
title_rect.w = title->w;
for ( iteration = 0; iteration < 9; iteration++ )
{
offset = (offset > MAX_SPACE_IMAGES - 1 ? 0 : offset + 1);
SDL_FillRect(console, 0, SDL_MapRGB(console->format, 0, 0, 0)); /* Clear the screen */
SDL_BlitSurface(space[offset], 0, console, NULL );
SDL_BlitSurface(title, 0, console, &title_rect);
SDL_Flip(console); /* Update the screen */
SDL_Delay(250); /* Delay the loop */
}
return;
}
void handle_events( int * quit, int * laser_request, int * x )
{
SDL_Event event;
/* While-loop was from SDL documentation : http://www.libsdl.org/release/SDL-1.2.15/docs/html/guideinputkeyboard.html */
while( SDL_PollEvent( &event ) )
{
switch( event.type )
{
case SDL_QUIT :
*quit = 1;
break;
/* Keydown event */
case SDL_KEYDOWN :
switch( event.key.keysym.sym )
{
case SDLK_LEFT :
*x = -5;
break;
case SDLK_RIGHT :
*x = 5;
break;
case SDLK_SPACE :
*laser_request = 1;
break;
case SDLK_ESCAPE :
*quit = 1;
break;
default : break;
}
break;
/* End keydown event */
/* Keyup event */
case SDL_KEYUP:
switch( event.key.keysym.sym )
{
case SDLK_LEFT :
if( *x < 0 )
*x = 0;
break;
case SDLK_RIGHT :
if( *x > 0 )
*x = 0;
break;
case SDLK_SPACE :
if ( *laser_request > 0 )
*laser_request = 0;
break;
default : break;
}
/* End keyup event */
break;
default : break;
}
}
return;
}
inline void move_fighter( SDL_Surface * console, SDL_Rect * fighter, int * x )
{
if ( fighter->x >= console->w - 75 )
{
*x = 0;
fighter->x = console->w - 76;
}
fighter->x += *x;
return;
}
inline void update_space_array_offset( int * offset, int * frame )
{
if ( *frame == SPACE_UPDATE_FRAME )
*offset = (*offset > MAX_SPACE_IMAGES - 1 ? 0 : *offset + 1);
return;
}
inline void reset_frame( int * frame )
{
*frame = *frame == SPACE_UPDATE_FRAME ? 0 : *frame + 1;
return;
}
inline void wait( unsigned time_start, unsigned time_end )
{
if ( (time_end - time_start) < (1000 / FRAMES_PER_SECOND) )
SDL_Delay( (( 1000 / FRAMES_PER_SECOND ) - ( time_end - time_start )) );
return;
}
void game_start( SDL_Surface ** space, SDL_Surface * space_fighter, SDL_Surface * console )
{
unsigned time_start = 0;
unsigned time_end = 0;
SDL_Rect fighter;
int frame = 0;
int offset = 0;
int quit = 0;
int x = 0;
int laser_request = 0;
int laser_queue = 0;
int amount_of_lasers = 0;
fighter.x = (console->w - space_fighter->w ) / 2; /* Set the fighter in the middle of the game */
fighter.y = console->h - 100; /* Set it 100 pixels minus the screen size */
fighter.h = 75;
fighter.w = 75;
laser * lasers = NULL;
laser * temp = NULL;
srand(time(NULL)); /* Randomize our node identifiers, may be needed in the future */
while ( !quit )
{
time_start = SDL_GetTicks(); /* Start the timer here to cap our frame rate later. */
update_space_array_offset( &offset, &frame ); /* Update the background image array if needed */
handle_events( &quit, &laser_request, &x ); /* Handle all the events and store the results in the parameters */
move_fighter( console, &fighter, &x ); /* Handle moving the fighter according to the result of the event handler */
/* Limit the lasers to a preset constant, can be any number,
/ but obviously super high amounts will do nothing. */
if ( amount_of_lasers < MAX_LASER_QUEUE )
laser_queue += laser_request;
for ( ; laser_queue; --laser_queue, ++amount_of_lasers )
{
lasers = append_list( lasers, rand(), 1, ((fighter.x + fighter.w / 2) - 2), fighter.y, 2, 16 ); /* Create a linked list to store all the valid requests */
spawnl(P_NOWAIT, "sound.exe", "sound.exe", "laser.txt", NULL); /* This was simpler than trying to multithread to play it at the same time. */
}
if ( lasers )
{
for ( temp = lasers; temp; temp = temp->next )
{
if ( temp->shape.y > 0 )
{
temp->shape.y -= 20;
}
else
{
lasers = remove_first_node(lasers); /* Needs to be updated to have the ability to remove nodes in the middle of the list */
--amount_of_lasers; /* Decrease this, so it always represents the exact amount of lasers in existence */
}
}
}
/* Drawing starts here */
SDL_FillRect(console, 0, SDL_MapRGB(console->format, 0, 0, 0)); /* Clear the screen */
SDL_BlitSurface(space[offset], 0, console, NULL );
SDL_BlitSurface(space_fighter, 0, console, &fighter);
for ( temp = lasers; temp; temp = temp->next )
SDL_FillRect(console, &temp->shape, SDL_MapRGB(console->format, 0, 255, 0)); /* Update each laser */
SDL_Flip(console); /* Update the screen */
/* End drawing */
time_end = SDL_GetTicks();
wait( time_start, time_end ); /* Wait until our FPS limit has been reached if executing faster than the limit */
reset_frame( &frame );
}
if ( lasers ) /* There shouldn't be any lasers left, but we need to make sure */
release_list(lasers);
return;
}
int main( int argc, char * argv[] )
{
/* Variable declarations */
/*
enemy_fighter enemies[MAX_ENEMIES] = {{NULL}};
*/
SDL_Surface * space[MAX_SPACE_IMAGES] = {NULL};
SDL_Surface * title = NULL;
SDL_Surface * space_fighter = NULL;
SDL_Surface * console = NULL;
int offset;
/* Initializing SDL... */
init_SDL();
if (atexit(SDL_Quit) )
{
perror("atexit");
exit(1);
}
/* Screen configurations */
console = set_video_mode( "Space Fighter" );
/* Image loading */
/*
for ( offset = 0; offset < MAX_ENEMIES; offset++ )
{
enemies[offset].image = load_image_opt( "enemy_fighter.bmp", 1 );
enemies[offset].is_dead = FALSE;
enemies[offset].move_down = FALSE;
enemies[offset].move_left = TRUE;
enemies[offset].move_right = FALSE;
enemies[offset].x = 0;
enemies[offset].y = 0;
}
*/
space[0] = load_image_opt( "space_dark.bmp", 0 );
space[1] = load_image_opt( "space_lighter.bmp", 0 );
space[2] = load_image_opt( "space_light.bmp", 0 );
title = load_image_opt( "space_fighter_intro.bmp", 1 );
space_fighter = load_image_opt( "space_fighter.bmp", 1 );
/* Start the game introduction */
game_intro( space, title, console );
SDL_FreeSurface(title); /* We no longer need the introduction title */
/* Start the game */
game_start( space, space_fighter, console );
/* Free allocated memory */
for (offset = 0; offset < MAX_SPACE_IMAGES - 1; offset++ )
SDL_FreeSurface(space[offset]);
/*
for ( offset = 0; offset < MAX_ENEMIES; offset++ )
SDL_FreeSurface(enemies[offset].image);
*/
SDL_FreeSurface(space_fighter);
return 0;
}
Here's exhibit A, the game screen after the title screen with no "empty space" :