One Hour Game Programming

(1/1)

Richard Marks:
One Hour Game Programming

This is by far the craziest idea that I have had in a while.

The rules are simple.
Write a game in one hour.
Any language, but no pre-made content.

My idea was to make a space invaderish type game.
I succeeded. It sucks major, but hey what the hell do you expect me to create in only 60 minutes??

There are white blocks at the top that are the enemies..they move to the right until they hit the right edge of the screen and then drop down and move to the left, getting faster, moving to the left until they hit the left edge of the screen and then they move to the right and drop down, repeat..

You control a white block at the bottom of the screen with the arrow keys..
I implemented a nice thrust type space flight physics model for the player controls.
You shoot with space. If you hold space, it will repeat shooting but using a timed delay.
If you press the space bar over and over quickly, you can shoot at faster intervals.

If your bullet/line/thingy hits a white enemy block, then the bullet and enemy will disappear, and you will score some points relative to the distance between the enemy and the bottom of the screen.
You get more points the lower the enemy gets to the ground.

When you kill everything the game says you win, and will wait until you press ENTER to restart the game.

Not bad for 60 minutes of work and no plan eh? 8)

Caution..the following source is VERY ugly,messy,unorganized, and poorly written! ;D

Code:

// main.cpp
// Project: One Hour Game Programming - started with Allegro Game Template v6.2
// Author: Richard Marks <ccpsceo@gmail.com>
/*
  ****************************************************************************
  * Copyright (c) 2009, Richard Marks, CCPS Solutions,                       *
  * Undefined Aeon Software.                                                 *
  *                                                                          *
  * Permission is hereby granted, free of charge, to any person obtaining a  *
  * copy of this software and associated documentation files (the            *
  * "Software"), to deal in the Software without restriction, including      *
  * without limitation the rights to use, copy, modify, merge, publish,      *
  * distribute, distribute with modifications, sub-license, and/or sell      *
  * copies of the Software, and to permit persons to whom the Software is    *
  * furnished to do so, subject to the following conditions:                 *
  *                                                                          *
  * The above copyright notice and this permission notice shall be included  *
  * in all copies or substantial portions of the Software.                   *
  *                                                                          *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  *
  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
  *                                                                          *
  * Except as contained in this notice, the name(s) of the above copyright   *
  * holders shall not be used in advertising or otherwise to promote the     *
  * sale, use or other dealings in this Software without prior written       *
  * authorization.                                                           *
  ****************************************************************************
*/

#include <cstdio>
#include <cstdlib>
#include <cstring>

#include <allegro.h>

////////////////////////////////////////////////////////////////////////////////

// we need this for handling timing
static volatile int allegrotimerspeedcounter = 0;
static void my_allegro_timer_speed_controller()
{
allegrotimerspeedcounter++;
}
END_OF_FUNCTION(my_allegro_timer_speed_controller)

// we need this to handle closing the window via the [X] button (you NEED this)
static volatile bool mainthreadisrunning = true;
static void my_allegro_close_button_handler()
{
mainthreadisrunning = false;
}
END_OF_FUNCTION(my_allegro_close_button_handler)

////////////////////////////////////////////////////////////////////////////////

bool setup_game();
void update_game();
void render_game();
void shutdown_game();

////////////////////////////////////////////////////////////////////////////////

// constants for the screen resolution
const int WINDOW_WIDTH = 800;
const int WINDOW_HEIGHT = 600;
const int WINDOW_COLOR_DEPTH = 16;
const bool WINDOW_USE_FULLSCREEN = false;

// the text in the window caption bar
const char* WINDOW_CAPTION = "One Hour Game Programming -- Richard Marks <ccpsceo@gmail.com>";

// if we want to enable the mouse
const bool ENABLE_MOUSE_SUPPORT = true;

// the FPS (frames per second) we should lock to
#define FRAME_LOCK_RATE 30

// bitmap for drawing on
BITMAP* backbuffer = 0;

////////////////////////////////////////////////////////////////////////////////
#include <vector>
#define TYP_NONE 0
#define TYP_BULLET 1
#define TYP_PLAYER 2
#define TYP_ENEMY 3
class Game;
unsigned int objids=0;
class Obj
{
public:
Obj(){id=++objids;}
virtual ~Obj(){}
Obj(Game*objowner)
{
owner=objowner;
id=++objids;
typ=TYP_NONE;
}
Game* owner;
float x,y,xv,yv;
int w,h;
bool alive;
unsigned int id;
unsigned int typ;

virtual void render()
{
const int whitecolor = makecol(255,255,255);
rectfill(backbuffer, (int)x, (int)y, (int)x+w, (int)y+h, whitecolor);
}

virtual void update()
{
x+=xv;
y+=yv;
if ((int)x<0)x=0.0f;
if ((int)x>SCREEN_W-w)x=(float)SCREEN_W-w;
if ((int)y<0)y=0.0f;
if ((int)y>SCREEN_H-h)y=(float)SCREEN_H-h;
}
};

// player bullet
class PBObj : public Obj
{
public:
PBObj(Game* objowner) : Obj(objowner){typ=TYP_BULLET;}
void update();

void render()
{
const int bluecolor = makecol(0,0,255);
const int bluecolor2 = makecol(0,0,64);
line(backbuffer, (int)x-1, (int)y, (int)x-1, (int)y+16, bluecolor2);
line(backbuffer, (int)x, (int)y, (int)x, (int)y+16, bluecolor);
line(backbuffer, (int)x+1, (int)y, (int)x+1, (int)y+16, bluecolor2);
}
};

class EObj : public Obj
{
public:
EObj(Game* objowner) :Obj(objowner)
{
typ=TYP_ENEMY;
}

void update()
{

x+=xv;
y+=yv;
if ((int)x<0 || (int)x>SCREEN_W-w)
{
xv+=0.5f;
xv = -xv;
y += h*2;
x+=xv;
y+=yv;
}

if (y>SCREEN_H-h)
{
alive = false;
}
}
};

class PObj : public Obj
{
public:
PObj(Game* objowner) : Obj(objowner)
{
firingcounter=0;
firingdelay=10;
typ=TYP_PLAYER;
}
void update();
int firingcounter,firingdelay;
};

class Game
{
public:
void addobj(Obj* o)
{
objects_.push_back(o);
}
Game()
{

}
~Game()
{
std::vector<Obj*>::iterator iter;
for (iter = objects_.begin(); iter != objects_.end(); iter++)
{
delete (*iter);
}
}
void init()
{
restart();
}
void restart()
{
score=0;
std::vector<Obj*>::iterator iter;
for (iter = objects_.begin(); iter != objects_.end(); iter++)
{
delete (*iter);
}

Obj* player = new PObj(this);
player->w = 16;
player->h = 16;
player->x = (float)WINDOW_WIDTH/2 - 8;
player->y = (float)WINDOW_HEIGHT - (player->h*2);
player->xv = 0.0f;
player->yv = 0.0f;
player->alive = true;
objects_.push_back(player);
playerid=player->id;
for (int row = 0; row < 4; row++)
{
for (int col = 0; col < 10; col++)
{
Obj* enemy = new EObj(this);
enemy->w = 16;
enemy->h = 16;
enemy->x = (float)(col*28)+col * enemy->w;
enemy->y = (float)(row*8)+row * enemy->h;
enemy->xv = 2.5f;
enemy->yv = 0.0f;
enemy->alive = true;
objects_.push_back(enemy);
}
}
}
void update()
{
if (win)
{
static bool ekey=false;
if (key[KEY_ENTER])
{
if (!ekey){ekey=true;}
}
else
{
if (ekey){ekey=false;win=false;restart();}
}
return;
}
if (1==objects_.size())
{
win=true;
return;
}
std::vector<Obj*>::iterator iter;
for (iter = objects_.begin(); iter != objects_.end(); iter++)
{
if ((*iter)->alive)
{
(*iter)->update();
}
else
{
objects_.erase(iter);
break;
}
}
}

void render()
{
if (win)
{
const char* msg="YOU WIN! PRESS ENTER TO PLAY AGAIN";
textprintf_ex(backbuffer,font,SCREEN_W/2-text_length(font,msg),SCREEN_H/2-text_height(font),makecol(0,255,0),-1,
"%s",msg);
return;
}
std::vector<Obj*>::iterator iter;
for (iter = objects_.begin(); iter != objects_.end(); iter++)
{
if ((*iter)->alive)
{
(*iter)->render();
}
}


textprintf_ex(backbuffer,font,0,0,makecol(255,255,0),-1,"score: %08d", score);

textprintf_ex(backbuffer,font,0,SCREEN_H-32,makecol(255,255,255),-1,"objects: %lu", objects_.size());
}

std::vector<Obj*> objects_;
int score;
bool win;
unsigned int playerid;
};

void PBObj::update()
{
x+=xv;
y+=yv;

if ((int)y<0)
{
alive = false;
}

std::vector<Obj*>::iterator iter;
for (iter = owner->objects_.begin(); iter != owner->objects_.end(); iter++)
{
Obj& other = *(*iter);
if (id!=other.id && other.id!=owner->playerid && other.typ!=TYP_BULLET)
{
if (x >= other.x && x <= other.x+other.w/* && y >= other.y && y <= other.y+other.h*/)
{
alive = false;
other.alive = false;
owner->score+=10*((int)y/(1+other.h));

}
}
}
}

void PObj::update()
{
if (key[KEY_UP])
{
yv -= 1.0f;
}
else if (key[KEY_DOWN])
{
yv += 1.0f;
}
else
{
if (yv >0){yv-=0.2f;}else{yv+=0.2f;}
}

if (key[KEY_LEFT])
{
xv -= 1.0f;
}
else if (key[KEY_RIGHT])
{
xv += 1.0f;
}
#if 1
else

{
if (xv > 0)
{
xv -= 0.2f;
}
else
{
xv += 0.2f;
}
}
#endif
static bool spaceisdown=false;
if (key[KEY_SPACE])
{
if (!spaceisdown){spaceisdown=true;}
if (++firingcounter>=firingdelay)
{
// shoot
Obj* bullet = new PBObj(owner);
bullet->yv= -20.0f;
bullet->xv=0.0f;
bullet->x = (float)x+w/2;
bullet->y = y-2.0f;
bullet->alive = true;
owner->addobj(bullet);
firingcounter=0;
}
}
else
{
if (spaceisdown)
{
spaceisdown=false;
// shoot
Obj* bullet = new PBObj(owner);
bullet->yv= -20.0f;
bullet->xv=0.0f;
bullet->x = (float)x+w/2;
bullet->y = y-2.0f;
bullet->alive = true;
owner->addobj(bullet);
}
}
if ((int)xv< -8)xv=-8.0f;
if ((int)xv>8)xv=8.0f;
if ((int)yv< -8)yv=-8.0f;
if ((int)yv>8)yv=8.0f;
Obj::update();
}


Game game;
////////////////////////////////////////////////////////////////////////////////

int main(int argc, char* argv[])
{
// init allegro and add keyboard and optional mouse support
allegro_init();
install_timer();
install_keyboard();
if (ENABLE_MOUSE_SUPPORT)
{
install_mouse();
}

// set the video mode
set_color_depth(WINDOW_COLOR_DEPTH);
set_gfx_mode(
(WINDOW_USE_FULLSCREEN) ?
GFX_AUTODETECT_FULLSCREEN :
GFX_AUTODETECT_WINDOWED,
WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0);
// set the window caption text
set_window_title(WINDOW_CAPTION);

// create the back buffer bitmap
backbuffer = create_bitmap(SCREEN_W, SCREEN_H);

// seed the random number generator
srand(time(0));

// lock the static functions and variables we need for handling timing and closing the window via the [X] button
LOCK_FUNCTION(my_allegro_close_button_handler);
LOCK_FUNCTION(my_allegro_timer_speed_controller);
LOCK_VARIABLE(allegrotimerspeedcounter);

// set the callback function for the close-button to our global handler function
set_close_button_callback(my_allegro_close_button_handler);

// set our FPS lock timing global function
install_int_ex(my_allegro_timer_speed_controller, BPS_TO_TIMER(FRAME_LOCK_RATE));

// setup the game
if (!setup_game())
{
fprintf(stderr, "The game initialization has failed. Cannot continue!\n");
exit(1);
}

// main loop
bool gameover = false;
while(!gameover)
{
// if our global is ever false
if (!mainthreadisrunning)
{
gameover = true;
}

// we only draw when the FPS should be locked
if (allegrotimerspeedcounter > 0)
{
// we only update during our FPS lock time
while (allegrotimerspeedcounter > 0)
{
// ensure the keyboard data is current
if (keyboard_needs_poll())
{
poll_keyboard();
}

// ensure the mosue data is current
if (ENABLE_MOUSE_SUPPORT)
{
if (mouse_needs_poll())
{
poll_mouse();
}
}

// update
update_game();

// decrement the global timing var so that we can leave the update loop!
allegrotimerspeedcounter--;
}

// start rendering the scene
render_game();

if (ENABLE_MOUSE_SUPPORT)
{
show_mouse(backbuffer);
}

// make it all visible
blit(backbuffer, screen, 0, 0, 0, 0, backbuffer->w, backbuffer->h);
}
else
{
// a little rest to keep CPU usage down ^-^
rest(1);
}
}

// shutdown the game
shutdown_game();

// clean up the back buffer
if (backbuffer)
{
if (ENABLE_MOUSE_SUPPORT)
{
show_mouse(0);
}
destroy_bitmap(backbuffer);
}

return 0;
}
END_OF_MAIN();

////////////////////////////////////////////////////////////////////////////////

bool setup_game()
{
// load game resources and stuff here
// return false if something failed to load or init


game.init();

// return true to let the main() function know that we're good to go
return true;
}

////////////////////////////////////////////////////////////////////////////////

void update_game()
{
// TODO: *** update stuff here
game.update();

// pressing ESC will end the main loop
if (key[KEY_ESC])
{
mainthreadisrunning = false;
}
}

////////////////////////////////////////////////////////////////////////////////

void render_game()
{
clear_bitmap(backbuffer);

// TODO: *** draw stuff here
game.render();
}

////////////////////////////////////////////////////////////////////////////////

void shutdown_game()
{
// unallocate anything you allocated for your game here
}



If you'd like to, you are free to try your own insane write-a-game-in-an-hour session, and post your results here.
 :D

Navigation

[0] Message Index