Commits

jodoherty committed d781a57

Reorganized the project files to use CMake instead of handwritten makefiles.

  • Participants
  • Parent commits 1c508c6

Comments (0)

Files changed (42)

 syntax: glob
+build
 *~
-main
 *.o
 *.obj
 .*.swp

Asteroid.cpp

-// Copyright (c) 2011 James O'Doherty
-// All Rights Reserved.
-
-#include "Common.h"
-#include "Asteroid.h"
-#include <algorithm>
-#include <ctime>
-
-using namespace std;
-
-const float Asteroid::kMaxSize = 64.0f;
-const float Asteroid::kMinSize = 4.0f;
-
-static const GLfloat vertices[] = {
-    -1.0f, -0.667f,
-    0.0f, -1.0f,
-    0.667f, -0.667f,
-    0.5f, -0.5f,
-    1.0f, 0.0f,
-    0.667f, 0.667f,
-    0.0f, 1.0f,
-    -0.667f, 0.667f,
-    -0.667f, 0.333f,
-    -1.0f, 0.0f
-};
-
-static const GLuint indices[] = {0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,0};
-static const int indice_count = 20;
-
-void Asteroid::init() 
-{
-    angle = kPI/4;
-    angular_velocity = kPI/64.0f/(rand()%3+1);
-    if (size > kMaxSize)
-        this->size = kMaxSize;
-    if (size < kMinSize)
-        this->size = kMinSize;
-    disabled = false;
-}
-
-Asteroid::Asteroid(float size) : size(size)
-{
-    float a = (rand()%100)/50.0f * kPI;
-    x = 99.0f * cos(a);
-    y = 99.0f * sin(a);
-    init();
-    Vector2d p(-x,-y);
-    p.normalize();
-    velocity = p*0.3f;
-}
-
-Asteroid::Asteroid(float x, float y, float size) 
-                  : x(x), y(y), size(size)
-{
-    init();
-    float heading = kPI*static_cast<float>(rand()%100)/50.0f;
-    float speed = static_cast<float>(rand()%55)/50.0f * (size/(size+0.5f)) *0.3f;
-    velocity.x = speed * cos(heading);
-    velocity.y = speed * sin(heading);
-}
-
-Asteroid::~Asteroid()
-{}
-
-bool Asteroid::createChildren(Asteroid *children[]) 
-{
-    if (disabled || size/2.2f < kMinSize)
-        return false;
-
-    children[0] = new Asteroid(x-size/4.0f, y+size/4.0f, size/2.2f);
-    children[1] = new Asteroid(x-size/4.0f, y-size/4.0f, size/2.2f);
-    children[2] = new Asteroid(x+size/4.0f, y+size/4.0f, size/2.2f);
-    children[3] = new Asteroid(x+size/4.0f, y-size/4.0f, size/2.2f);
-    return true;
-}
-
-void Asteroid::collide(Asteroid &a)
-{
-    float m1 = size*size;
-    float m2 = a.size*a.size;
-    Vector2d normal(a.velocity.x-velocity.x,a.velocity.y-velocity.y);
-    normal.normalize();
-    Vector2d tangent(-normal.y, normal.x);
-    float v1n = normal*velocity;
-    float v1t = tangent*velocity;
-    float v2n = normal*a.velocity;
-    float v2t = tangent*a.velocity;
-    float v1n_ = (v1n*(m1-m2)+2*m2*v2n)/(m1+m2);
-    float v2n_ = (v2n*(m2-m1)+2*m1*v1n)/(m1+m2);
-    velocity = v1n_ * normal + v1t*tangent;
-    a.velocity = v2n_ * normal + v2t * tangent;
-}
-
-void Asteroid::update()
-{
-    angle += angular_velocity;
-    x += velocity.x;
-    y += velocity.y;
-}
-
-void Asteroid::drawAt(float x, float y)
-{
-    glPushMatrix();
-    glTranslatef(x, y, 0.0f);
-    glScalef(size/2.0f, size/2.0f, 1.0f);
-    glRotatef(angle*180/kPI, 0.0f, 0.0f, 1.0f);
-    glEnableClientState(GL_VERTEX_ARRAY);
-    glVertexPointer(2, GL_FLOAT, 0, vertices);
-    glDrawElements(GL_LINES, indice_count, GL_UNSIGNED_INT, indices);
-    glDisableClientState(GL_VERTEX_ARRAY);
-    glPopMatrix();
-}
-

Asteroid.h

-// Copyright (c) 2011 James O'Doherty
-// All Rights Reserved.
-
-#ifndef ASTEROID_H__
-#define ASTEROID_H__
-
-#include "MirroredSprite.h"
-#include "Vector2d.h"
-
-class Asteroid : public MirroredSprite
-{
-    float x;
-    float y;
-    Vector2d velocity;
-    float size;
-    float angle;
-    float angular_velocity;
-    bool disabled;
-
-    void init();
-
-public:
-    Asteroid(float size);
-    Asteroid(float x, float y, float size);
-    ~Asteroid();
-
-    // Child factory function
-    bool createChildren(Asteroid **);
-
-    // Required accessors
-    float getSize() {
-        return size;
-    }
-    Point getLocation() {
-        Point p = {x, y};
-        return p;
-    }
-    void setLocation(Point p) {
-        x = p.x;
-        y = p.y;
-    }
-
-    // Asteroid specific accessors
-    void disable() {
-        disabled = true;
-    }
-
-    void reverse() {
-        x -= 0.1f*velocity.x;
-        y -= 0.1f*velocity.y;
-    }
-
-    // collide handles collisions with other Asteroids
-    void collide(Asteroid &);
-
-    void update();
-    void drawAt(float x, float y);
-
-    static const float kMaxSize;
-    static const float kMinSize;
-
-};
-
-#endif // ASTEROID_H__

AudioService.h

-#ifndef AUDIO_SERVICE_H__
-#define AUDIO_SERVICE_H__
-
-typedef int AudioHandle;
-
-class AudioService
-{
-public:
-    virtual void release() = 0;
-
-    virtual AudioHandle playSample(const char *, int = 0) = 0;
-    virtual void stopSample(AudioHandle) = 0;
-    virtual void playTrack(const char *) = 0;
-};
-
-AudioService *GetAudioServiceInstance();
-
-#endif // AUDIO_SERVICE_H__

Bullet.cpp

-// Bullet.cpp
-// Copyright (c) 2011 James O'Doherty
-// All Rights Reserved.
-
-#include "Common.h"
-#include "Bullet.h"
-
-const float Bullet::size = 1.2f;
-
-void Bullet::update() 
-{
-    x += dx;
-    y += dy;
-}
-
-void Bullet::drawAt(float x, float y)
-{
-    glPushMatrix();
-    glTranslatef(x, y, 0.0f);
-    glRectf(-size/2.0f, -size/2.0f, size/2.0f, size/2.0f);
-    glPopMatrix();
-}
-

Bullet.h

-// Bullet.h
-// Copyright (c) 2011 James O'Doherty
-// All Rights Reserved.
-
-#ifndef BULLET_H__
-#define BULLET_H__
-
-#include "MirroredSprite.h"
-
-class Bullet : public Sprite
-{
-    float x;
-    float y;
-    float dx;
-    float dy;
-    static const float size;
-
-public:
-    Bullet(float x, float y, float dx, float dy) 
-          : x(x), y(y), dx(dx), dy(dy)
-    {}
-    
-    float getSize() {
-        return size;
-    }
-    Point getLocation() {
-        Point p = {x,y};
-        return p;
-    }
-    void setLocation(Point p) {
-        x = p.x;
-        y = p.y;
-    }
-
-    void update();
-    void drawAt(float x, float y);
-
-    friend class Ship;
-};
-
-#endif // BULLET_H__

Common.h

-#ifndef COMMON_H__
-#define COMMON_H__
-
-#ifdef WIN32
-#include <windows.h>
-#endif
-
-#ifdef __APPLE__
-    #include <OpenGL/glu.h>
-    #include <OpenGL/glext.h>
-#else
-    #include <GL/gl.h>
-    #include <GL/glu.h>
-#endif
-#include <cstdlib>
-#include <cmath>
-
-#include "Geometry.h"
-#include "Resources.h"
-
-#endif // COMMON_H__

Explosion.h

-#ifndef EXPLOSION_H__
-#define EXPLOSION_H__
-
-#include "Sprite.h"
-#include "Vector2d.h"
-#include "Common.h"
-#include <cmath>
-
-class Explosion : public Sprite
-{
-    float x;
-    float y;
-    float points[200];
-    Vector2d velocities[100];
-    float color[3];
-    float psize;
-    unsigned long int step;
-
-public:
-    Explosion(float x, float y) : x(x), y(y) {
-        for (int i=0; i<200; i++)
-            points[i] = 0.0;
-        for (int i=0; i<100; i++) {
-            velocities[i].x = 1.0f * cos(i*kPI/50.0f);
-            velocities[i].y = 1.0f * sin(i*kPI/50.0f);
-        }
-        color[0] = 1.0f;
-        color[1] = 1.0f;
-        color[2] = 1.0f;
-        step = 0;
-        psize = 3.0f;
-    }
-    ~Explosion() {
-    }
-
-    Point getLocation() {
-        Point p = {x,y};
-        return p;
-    }
-
-    float getSize() {
-        return 10.0f;
-    }
-
-    bool isPhysical() {
-        return false;
-    }
-
-    void drawAt(float x, float y) {
-        glPushMatrix();
-        // Enable vertex arrays
-        glEnableClientState(GL_VERTEX_ARRAY);
-
-        glTranslatef(x, y, 0.0f);
-        glVertexPointer(2, GL_FLOAT, 0, points);
-        glPushAttrib(GL_CURRENT_BIT);
-        glColor3fv(color);
-        glPointSize(psize);
-        glDrawArrays(GL_POINTS, 0, 100);
-        glPopAttrib();
-
-        // Disable vertex arrays
-        glDisableClientState(GL_VERTEX_ARRAY);
-        glPopMatrix();
-    }
-
-    void update() {
-        for (int i=0; i<100; i++) {
-            points[2*i] += velocities[i].x; 
-            points[2*i + 1]  += velocities[i].y;
-            velocities[i].x *= 0.94f;
-            velocities[i].y *= 0.94f;
-        }
-        for (int i=0; i<3; i++)
-            color[i] *= 0.90f;
-        psize *= 0.98f;
-    }
-    
-    bool isFinished() {
-        if (psize < 1.0f)
-            return true;
-        return false;
-    }
-
-};
-
-#endif // EXPLOSION_H__

Game.cpp

-// Game.cpp
-// Copyright (c) 2011 James O'Doherty
-// All Rights Reserved.
-
-#include <iostream>
-#include <cstdlib>
-#include <ctime>
-#include <set>
-#include <list>
-#include <algorithm>
-#include <functional>
-
-#ifdef USE_SDL
-#include <SDL.h>
-
-static SDL_Surface *screen = NULL;
-#endif 
-
-#include "Common.h"
-
-#include "Ship.h"
-#include "Bullet.h"
-#include "Asteroid.h"
-#include "Game.h"
-
-using namespace std;
-
-Game::Game()
-{
-    int width, height;
-#ifdef USE_SDL
-    // Initialize SDL subsystems
-    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) < 0) {
-        cerr << "Error, couldn't initialize SDL: " 
-             << SDL_GetError() << endl;
-        exit(EXIT_FAILURE);
-    }
-    atexit(SDL_Quit);
-
-    // Initialize SDL screen
-    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
-    screen = SDL_SetVideoMode(800, 600, 0, 
-                              SDL_OPENGL | SDL_HWSURFACE | SDL_RESIZABLE);
-
-    if (!screen) {
-        cerr << "Error, video initialization failed: " 
-             << SDL_GetError() << endl;
-        exit(EXIT_FAILURE);
-    }
-
-    width = screen->w;
-    height = screen->h;
-
-#endif
-    // Set up the screen
-    reshape(width, height);
-
-    // Set up our audio service
-    audio = GetAudioServiceInstance();
-
-    // Initialize sprites and scene data list
-    player = new Ship();
-    sprites.insert(dynamic_cast<Sprite *>(player));
-}
-
-Game::~Game()
-{
-    for (set<Sprite*>::iterator it = sprites.begin(); it != sprites.end(); it++)
-        delete *it;
-    audio->release();
-}
-
-void Game::run()
-{
-    srand(static_cast<unsigned int>(time(NULL)));
-
-    // Start playing background music
-    audio->playTrack(r_bg_music_track);
-
-#ifdef USE_SDL
-    // Prepare game loop
-    bool quit = false;
-    Uint32 ticks = SDL_GetTicks();
-    const Uint32 delta = 20;
-
-    // Run game loop
-    while (!quit) {
-        quit = poll();
-        // Update game physics if the correct time delta has passed
-        while (SDL_GetTicks() > ticks + delta) {
-            update();
-            ticks += delta;
-        }
-        // Render screen and sprites
-        draw();
-        // Detect and report OpenGL error conditions
-        while (GLenum error = glGetError() != GL_NO_ERROR) {
-            cerr << gluErrorString(error) << endl;
-        }
-    }
-#endif
-}
-
-void Game::toggleFullScreen()
-{
-#ifdef USE_SDL
-    // *todo*
-#endif
-}
-
-void Game::reshape(int w, int h)
-{
-    if (h == 0)
-        h = 1;
-    GLfloat aspectRatio = (GLfloat)w/(GLfloat)h;
-
-    // Set up the OpenGL project screen
-    glMatrixMode(GL_PROJECTION);
-    glLoadIdentity();
-
-    // Fill the entire window
-    glViewport(0,0,w,h);
-    // Center the projection on 0,0 and ensure an x,y
-    // range of at least 100 in all 4 directions is visible.
-    if (w <= h) {
-        left = 0;
-        bottom = (h-w)/2;
-        width = w;
-        height = w;
-        glOrtho(-100.0,100.0,-100.0/aspectRatio,100.0/aspectRatio,0,1);
-    } else {
-        bottom = 0;
-        left = (w-h)/2;
-        width = h;
-        height = h;
-        glOrtho(-100.0*aspectRatio,100.0*aspectRatio,-100.0, 100,0,1);
-    }
-
-    glMatrixMode(GL_MODELVIEW);
-    glDisable(GL_DEPTH_TEST);
-    glLoadIdentity();
-
-    glClearColor(0.0f,0.0f,0.0f,0.0f);
-    glClear(GL_COLOR_BUFFER_BIT);
-}
-
-void Game::update()
-{
-    static int step = 3;
-
-    set<Sprite *>::iterator it;
-    set<Sprite *>::iterator it2;
-
-    list<Sprite *>::iterator list_it;
-
-    list<Sprite *> destroy_list;
-    list<Sprite *> add_list;
-    if (sprites.size() < 2) {
-        for (int i=0; i<step; i++)
-            add_list.push_back(dynamic_cast<Sprite *>(new Asteroid(rand()%16+12.0f+step)));
-        step++;
-    }
-
-    for (it = sprites.begin(); it != sprites.end(); it++) {
-        (*it)->preUpdateHandler();
-        (*it)->update();
-        (*it)->postUpdateHandler();
-        if ((*it)->isOutOfBounds())
-            destroy_list.push_back(*it);
-    }
-
-    for (it = sprites.begin(); it != sprites.end(); it++) {
-        it2 = it;
-        for (it2++; it2 != sprites.end(); it2++) {
-            if ((*it)->detectCollision(**it2)) {
-                // Use runtime type information to determine the appropriate
-                // course of action for the sprites.
-
-                // A more flexible method would be to create a SpriteManager
-                // class that all sprites have a delegate to and require
-                // Sprite class descendents implement a collision event
-                // handler. Then every class would have everything it
-                // needs to handle events.
-
-                // I haven't gotten around to doing that yet.
-               
-                // Do we have an asteroid hitting an asteroid?
-                Asteroid *a1 = dynamic_cast<Asteroid *>(*it);
-                Asteroid *a2 = dynamic_cast<Asteroid *>(*it2);
-
-                if (a1 && a2) {
-                    // Back up the asteroids so they don't overlap
-                    while ((*it)->detectCollision(**it2)) {
-                        a1->reverse();
-                        a2->reverse();
-                    }
-                    // Now bounce the asteroids off of each other
-                    a1->collide(*a2);
-                    continue;
-                } 
-
-                // Now check to see if we have a bullet hitting a bullet
-                Bullet *b1 = dynamic_cast<Bullet *>(*it);
-                Bullet *b2 = dynamic_cast<Bullet *>(*it2);
-
-                if (b1 && b2) {
-                    // Mark the bullets for destruction
-                    destroy_list.push_back(b1);
-                    destroy_list.push_back(b2);
-                    continue;
-                }
-
-                // Now check to see if we have a bullet hitting an asteroid
-                Asteroid *a = NULL;
-                Bullet *b = NULL;
-                if (a1)
-                    a = a1;
-                else if (a2)
-                    a = a2;
-                if (b1)
-                    b = b1;
-                else if (b2)
-                    b = b2;
-                if (a && b) {
-                    // Spawn baby asteroids if the asteroid is 
-                    // big enough and hasn't been disabled
-                    Asteroid *children[4];
-                    if (a->createChildren(children)) {
-                        // Children created successfully
-                        add_list.push_back(children[0]);
-                        add_list.push_back(children[1]);
-                        add_list.push_back(children[2]);
-                        add_list.push_back(children[3]);
-                        audio->playSample(r_explosion_sample);
-                    } else {
-                        audio->playSample(r_smallexplosion_sample);
-                    }
-                    a->disable();
-
-                    // Mark the old objects for destruction
-                    destroy_list.push_back(a);
-                    destroy_list.push_back(b);
-                    continue;
-                }
-
-                // Did something hit the player then?
-                if ((*it == player || *it2 == player) && player->isAlive()) {
-                    // Just kill the player. 
-                    audio->playSample(r_explosion_sample);
-                    player->kill();
-                    // If it was a bullet, destroy the bullet too.
-                    if (b)
-                        destroy_list.push_back(b);
-                } 
-                
-            }
-        }
-    }
-
-    // Now remove and delete all the sprites that were marked for destruction.
-    for (list_it=destroy_list.begin(); list_it != destroy_list.end(); 
-         list_it++) 
-    {
-        sprites.erase(*list_it);
-        delete *list_it;
-    }
-    // Prune any bad objects
-    for (list_it = add_list.begin(); list_it != add_list.end(); list_it++) {
-        for (it = sprites.begin(); it != sprites.end(); it++) {
-            if ((*list_it)->detectCollision(**it)) {
-                delete *list_it;
-                add_list.erase(list_it++);
-                break;
-            }
-        }
-    } 
-    for (list_it = add_list.begin(); list_it != add_list.end(); list_it++) {
-        skip:
-        list<Sprite *>::iterator list_it2 = list_it;
-        for (list_it2++; list_it2 != add_list.end(); list_it2++) {
-            if ((*list_it)->detectCollision(**list_it2)) {
-                delete *list_it;
-                add_list.erase(list_it++);
-                goto skip;
-            }
-        }
-    }
-
-    // Now add all the objects we created in this update step
-    for (list_it = add_list.begin(); list_it != add_list.end(); list_it++) {
-        sprites.insert(*list_it);
-    }
-}
-
-void Game::draw()
-{
-    glClear(GL_COLOR_BUFFER_BIT);
-    glColor3f(1.0f, 1.0f, 1.0f);
-    
-    glEnable(GL_SCISSOR_TEST);
-    glScissor(left, bottom, width, height);
-
-    // Draw sprites and game objects
-    for (set<Sprite*>::iterator it = sprites.begin(); it != sprites.end(); 
-         it++) 
-    {
-        #ifdef DEBUG
-        // Draw bounding circles used in collision detection
-        glPushMatrix();
-        Circle c = {(*it)->getLocation(), (*it)->getSize()/2.0};
-        glTranslatef(c.center.x, c.center.y, 0.0f);
-        for (int i=0; i<360; i++) {
-            glRotatef(1.0f, 0.0f, 0.0f, 1.0f);
-            glBegin(GL_POINTS);
-                glVertex2f(c.radius, 0.0f);
-            glEnd();
-        }
-        glPopMatrix();
-        #endif
-        (*it)->draw();
-    }
-    glDisable(GL_SCISSOR_TEST);
-
-    glPushAttrib(GL_CURRENT_BIT);
-    // Draw border of field area
-    glColor3f(1.0f, 1.0f, 1.0f);
-    glLineWidth(2.0f);
-    glBegin(GL_LINES);
-        glVertex2i(-100, -100);
-        glVertex2i(100, -100);
-        glVertex2i(100, -100);
-        glVertex2i(100, 100);
-        glVertex2i(100, 100);
-        glVertex2i(-100, 100);
-        glVertex2i(-100, 100);
-        glVertex2i(-100, -100);
-    glEnd();
-    glPopAttrib();
-#ifdef USE_SDL
-    SDL_GL_SwapBuffers();
-#endif
-}
-
-bool Game::poll()
-{
-    bool quit = false;
-    static AudioHandle thrustSample = -1;
-
-#ifdef USE_SDL
-    // Poll Events
-    SDL_Event event;
-    while (SDL_PollEvent(&event)) {
-        switch (event.type) {
-            case SDL_KEYDOWN:
-                switch (event.key.keysym.sym) {
-                    case SDLK_UP:
-                    case SDLK_w:
-                        player->setAccelerate();
-                        if (player->isAlive())
-                            thrustSample = audio->playSample(r_thrust_sample, -1);
-                        break;
-                    case SDLK_LEFT:
-                    case SDLK_a:
-                        player->setLeft();
-                        break;
-                    case SDLK_RIGHT:
-                    case SDLK_d:
-                        player->setRight();
-                        break;
-                    case SDLK_ESCAPE:
-                        quit = true;
-                        break;
-                    default:
-                        break;
-                }
-                break;
-            case SDL_KEYUP:
-                switch (event.key.keysym.sym) {
-                    case SDLK_UP:
-                    case SDLK_w:
-                        player->clearAccelerate();
-                        if (thrustSample != -1)
-                            audio->stopSample(thrustSample);
-                        thrustSample = -1;
-                        break;
-                    case SDLK_LEFT:
-                    case SDLK_a:
-                        player->clearLeft();
-                        break;
-                    case SDLK_RIGHT:
-                    case SDLK_d:
-                        player->clearRight();
-                        break;
-                    case SDLK_SPACE:
-                        if (player->isAlive()) {
-                            sprites.insert(player->fire());
-                            audio->playSample(r_fire_sample);
-                        }
-                        else
-                            player->revive();
-                        break;
-                    case SDLK_F11:
-                        toggleFullScreen();
-                        break;
-                    default:
-                        break;
-                }
-                break;
-            case SDL_VIDEORESIZE:
-                screen = SDL_SetVideoMode(event.resize.w,
-                                          event.resize.h,
-                                          0,
-                                          screen->flags);
-                reshape(event.resize.w, event.resize.h);
-                break;
-            case SDL_QUIT:
-                quit = true;
-                break;
-            default:
-                break;
-        }
-    }
-#endif
-    return quit;
-}
-

Game.h

-// Game.h
-// Copyright (c) 2011 James O'Doherty
-// All Rights Reserved.
-
-#ifndef GAME_H__
-#define GAME_H__
-
-#ifdef USE_SDL
-#include <SDL.h>
-#endif
-
-#include "AudioService.h"
-#include "Sprite.h"
-#include "Ship.h"
-#include <set>
-
-class Game
-{
-    std::set<Sprite*> sprites;
-    Ship *player;
-    int left;
-    int bottom;
-    int width;
-    int height;
-    AudioService *audio;
-
-public:
-    Game();
-    ~Game();
-
-    void run();
-
-    bool poll();
-    void update();
-    void draw();
-
-private:
-    // Handle screen resize event
-    void reshape(int w, int h);
-    // Handle fullscreen toggle event
-    void toggleFullScreen();
-    // Convert local coordinates to screen coordinates
-    Point localToScreen(Point);
-};
-
-
-inline Point Game::localToScreen(Point p)
-{
-    p.x = (p.x+100)/2*width+left;
-    p.y = (p.y+100)/2*height+bottom;
-    return p;
-}
-
-#endif // GAME_H__
-

Geometry.h

-// Geometry.h
-// Copyright (c) 2011 James O'Doherty
-// All Rights Reserved
-
-#ifndef GEOMETRY_H__
-#define GEOMETRY_H__
-
-const float kPI = 3.1415927f;
-
-struct Point
-{
-    float x;
-    float y;
-};
-
-struct Circle
-{
-    Point center;
-    float radius;
-};
-
-struct Rect
-{
-    float left;
-    float top;
-    float right;
-    float bottom;
-};
-
-
-// Utility functions for geometry and collision detection
-
-inline bool isOverlapping(Rect &r1, Rect &r2) {
-    return (r1.left < r2.right &&
-            r1.right > r2.left &&
-            r1.bottom < r2.top && 
-            r1.top > r2.bottom);
-}
-
-inline bool isOverlapping(Circle &p, Circle &q) {
-    if ((p.radius+q.radius)*(p.radius+q.radius) > 
-        (p.center.x - q.center.x)*(p.center.x - q.center.x) +
-        (p.center.y - q.center.y)*(p.center.y - q.center.y))
-        return true;
-    return false;
-}
-
-
-
-#endif // GEOMETRY_H__

Makefile

-CC = g++
-CFLAGS = `pkg-config sdl --cflags` -Wall -DUSE_SDL
-LDFLAGS = -o main
-LIBS = `pkg-config sdl --libs` -lGL -lGLU -lSDL_mixer
-
-include Makefile.common

Makefile.common

-
-SOURCES = main.cpp Game.cpp SDLAudioService.cpp Asteroid.cpp Bullet.cpp Ship.cpp
-HEADERS = Asteroid.h AudioService.h Bullet.h Common.h Game.h Geometry.h MirroredSprite.h Resources.h SDLAudioService.h Ship.h Sprite.h Vector2d.h
-
-all: ${SOURCES} ${HEADERS}
-	${CC} ${CFLAGS} ${SOURCES} ${LDFLAGS} ${LIBS}
-

Makefile.win32

-
-CC = cl
-
-DEFINES = /DUSE_SDL /DWIN32 /DNDEBUG /D_WINDOWS /DUNICODE /D_UNICODE
-CFLAGS = /nologo /W3 /O2 /Oi /GL ${DEFINES} /EHsc /MD
-LDFLAGS = /link /OUT:bin\main.exe /INCREMENTAL:NO /NOLOGO /SUBSYSTEM:WINDOWS
-LIBS = kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib opengl32.lib glu32.lib SDL.lib SDLmain.lib SDL_mixer.lib
-
-include Makefile.common
-

MirroredSprite.h

-#ifndef MIRRORED_SPRITE_H__
-#define MIRRORED_SPRITE_H__
-
-
-#include "Sprite.h"
-
-// MirroredSprite is an abstract class that implements default member
-// functions that automatically mirror the sprite whenever it reaches
-// the edge of the playing field.
-class MirroredSprite : public Sprite
-{
-public:
-    // Additional required accessors
-    virtual void setLocation(Point) = 0;
-
-    // Implementation for subclasses to inherit
-    void draw() {
-        float size = getSize();
-        Point location = getLocation();
-        float &x = location.x;
-        float &y = location.y;
-        // Draw the sprite at the actual location
-        drawAt(x, y);
-
-        // Now determine if mirrored images at the opposite sides
-        // of the screen are needed
-        bool horizontal = true;
-        bool vertical = true;
-        float mx = x;
-        float my = y;
-        if (x+size > 100.0f) 
-            mx = -200.0f + x;
-        else if (x-size < -100.0f)
-            mx = 200.0f + x;
-        else
-            horizontal = false;
-        if (y+size > 100.0f )
-            my = -200.0f + y;
-        else if (y-size < -100.0f)
-            my = 200.0f + y;
-        else
-            vertical = false;
-        if (horizontal && vertical) 
-            drawAt(mx, my);
-        if (horizontal) 
-            drawAt(mx, y);
-        if (vertical)
-            drawAt(x, my);
-    }
-
-    // Ensure collision detection accounts for the fact that
-    // our object might be mirrored at 3 different points of
-    // the screen.
-    bool detectCollision(Sprite &s) {
-        if (!isPhysical() || !s.isPhysical())
-            return false;
-
-        Circle p = {getLocation(), getSize()/2.0f};
-        Circle q = {s.getLocation(), s.getSize()/2.0f};
-
-        if (isOverlapping(p, q))
-            return true;
-
-        // Now determine if mirrored copies of the object on the other side
-        // of the screen are needed and if they collide with our target
-        float &size = p.radius;
-        float x = p.center.x;
-        float y = p.center.y;
-
-        bool horizontal = true;
-        bool vertical = true;
-        float mx = x;
-        float my = y;
-        if (x+size > 100.0f) 
-            mx = -200.0f + x;
-        else if (x-size < -100.0f)
-            mx = 200.0f + x;
-        else
-            horizontal = false;
-        if (y+size > 100.0f )
-            my = -200.0f + y;
-        else if (y-size < -100.0f)
-            my = 200.0f + y;
-        else
-            vertical = false;
-        if (horizontal && vertical) {
-            p.center.x = mx;
-            p.center.y = my;
-            if (isOverlapping(p, q))
-                return true;
-        }
-        if (horizontal) {
-            p.center.x = mx;
-            p.center.y = y;
-            if (isOverlapping(p, q))
-                return true;
-        }
-        if (vertical) {
-            p.center.x = x;
-            p.center.y = my;
-            if (isOverlapping(p, q))
-                return true;
-        }
-        return false;
-    }
-    // Force mirrored sprites to wrap around the screen
-    void postUpdateHandler() {
-        Point p = getLocation();
-        if (p.x > 100.0f)
-            p.x += -200.0f;
-        else if (p.x < -100.0f)
-            p.x += 200.0f;
-        if (p.y > 100.0f)
-            p.y += -200.0f;
-        else if (p.y < -100.0f)
-            p.y += 200.0f;
-        setLocation(p);
-    }
-
-    bool isOutOfBounds() {
-        return false;
-    }
-};
-
-#endif // MIRRORED_SPRITE_H__

Resources.h

-#ifndef RESOURCES_H__
-#define RESOURCES_H__
-
-#define r_explosion_sample  "res/explosion.wav"
-#define r_smallexplosion_sample "res/smallexplosion.wav"
-#define r_fire_sample "res/fire.wav"
-#define r_bg_music_track  "res/bg.mp3"
-#define r_thrust_sample "res/thrust.wav"
-
-#endif // RESOURCES_H__

SDLAudioService.cpp

-#include <iostream>
-#include "SDLAudioService.h"
-
-using namespace std;
-
-typedef map<const char*, Mix_Music *>::iterator TrackIterator;
-typedef map<const char*, Mix_Chunk *>::iterator SampleIterator;
-
-SDLAudioService *SDLAudioService::instance = NULL;
-unsigned int SDLAudioService::refcount = 0;
-
-SDLAudioService::SDLAudioService()
-{
-    if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024) == -1) {
-        cerr << "Couldn't initialize audio service." << endl;
-        cerr << "Mix_OpenAudio: " << Mix_GetError() << endl;
-    }
-    Mix_AllocateChannels(32); 
-} 
-
-SDLAudioService::~SDLAudioService()
-{
-    for (TrackIterator it = tracks.begin(); it != tracks.end(); it++) 
-        Mix_FreeMusic(it->second);
-    for (SampleIterator it = samples.begin(); it != samples.end(); it++)
-        Mix_FreeChunk(it->second);
-    Mix_CloseAudio();
-} 
-
-AudioService *GetAudioServiceInstance()
-{
-    return SDLAudioService::getInstance();
-}
-
-SDLAudioService *SDLAudioService::getInstance()
-{
-    if (!instance) 
-        instance = new SDLAudioService();
-    refcount++;
-    return instance;
-}
-
-void SDLAudioService::release()
-{
-    if (refcount <= 0 && instance) {
-        delete instance;
-        instance = NULL;
-        refcount = 0;
-    } else {
-        refcount--;
-    }
-}
-
-void SDLAudioService::loadTrack(const char *filename)
-{
-    if (tracks.find(filename) == tracks.end()) {
-        tracks[filename] = Mix_LoadMUS(filename);
-        if (tracks[filename] == NULL) {
-            // Loading failed, print an error and erase the track
-            cerr << "Mix_LoadMUS(\"" << filename << "\"): "
-                 << Mix_GetError() << endl;
-            tracks.erase(filename);
-        }
-    }
-}
-
-void SDLAudioService::loadSample(const char *filename)
-{
-    if (samples.find(filename) == samples.end()) {
-        samples[filename] = Mix_LoadWAV(filename);
-        if (samples[filename] == NULL) {
-            cerr << "Mix_LoadWAV(\"" << filename << "\"): "
-                 << Mix_GetError() << endl;
-            samples.erase(filename);
-        }
-    }
-}
-
-AudioHandle SDLAudioService::playSample(const char *filename, int loops)
-{
-    loadSample(filename);
-    return Mix_PlayChannel(-1, samples[filename], loops);
-}
-
-void SDLAudioService::stopSample(AudioHandle handle)
-{
-    Mix_HaltChannel(handle);
-}
-
-void SDLAudioService::playTrack(const char *filename)
-{
-    loadTrack(filename);
-    Mix_PlayMusic(tracks[filename], -1);
-}
-
-

SDLAudioService.h

-#ifndef SDL_AUDIO_SERVICE_H__
-#define SDL_AUDIO_SERVICE_H__
-
-#include "AudioService.h"
-#include <SDL.h>
-#include <SDL_mixer.h>
-#include <map>
-
-class SDLAudioService : public AudioService
-{
-    // SDLAudioService implements the Singleton pattern, so only
-    // one instance is allowed at any one time.
-    static SDLAudioService *instance;
-    // Reference counting is used to handle resource management.
-    static unsigned int refcount;
-    // Samples are cached by name using STL maps in this implementation
-    std::map<const char *, Mix_Music *> tracks;
-    std::map<const char *, Mix_Chunk *> samples;
-
-    // Private constructor and destructor
-    SDLAudioService();
-    ~SDLAudioService();
-
-    void loadSample(const char *);
-    void loadTrack(const char *);
-
-public:
-    void release();
-
-    AudioHandle playSample(const char *, int = 0);
-    void stopSample(AudioHandle);
-    void playTrack(const char *);
-
-    static SDLAudioService *getInstance();
-};
-
-#endif // SDL_AUDIO_SERVICE_H__

Ship.cpp

-// Ship.cpp
-// Copyright (c) 2011 James O'Doherty
-// All Rights Reserved
-
-#include "Common.h"
-#include "Ship.h"
-#include "Bullet.h"
-#include "Explosion.h"
-
-using namespace std;
-
-static const float size = 10.0f;
-
-// Internal constants
-const float Ship::thrust = 0.02f;
-const float Ship::drag = 0.99f;
-const int Ship::framecount = 3;
-const float Ship::size = 0.5f*::size; 
-
-static float vertices[] = {
-    // ship body
-    -size/2.0f+size/8.0f, -size/4.0f, 0.0f,
-    size/2.0f+size/8.0f, 0.0f, 0.0f,
-    -size/2.0f+size/8.0f, size/4.0f, 0.0f,
-    // short tail
-    -size/1.5f+size/8.0f, -size/5.0f, 0.0f,
-    -size/2.0f+size/8.0f, 0.0f, 0.0f,
-    -size/1.5f+size/8.0f, size/5.0f, 0.0f,
-    // long tail
-    -size+size/8.0f, -size/5.0f, 0.0f,
-    -size/2.0f+size/8.0f, 0.0f, 0.0f,
-    -size+size/8.0f, size/5.0f, 0.0f,
-};
-
-static GLuint frames[][6] = {{0, 1, 2, 0, 0, 0},
-                             {0, 1, 2, 3, 4, 5},
-                             {0, 1, 2, 6, 7, 8}};
-
-Ship::Ship(float startx, float starty) 
-{
-    x = startx;
-    y = starty;
-    direction = kPI/2;
-    clearState();
-    blink = true;
-    visible = true;
-    step = 0;
-}
-
-Ship::~Ship() 
-{
-}
-
-void Ship::update()
-{
-    static float drift = 1.0f;
-    const int framedelta = 4;
-    if (alive) {
-        if (left)
-            direction += kPI/96.0f*drift;
-        if (right)
-            direction -= kPI/96.0f*drift;
-
-        // Reset the turning speed if the user let goes of the keys
-        if (!left && !right)
-            drift = 1.0f;
-        // Speed up turning as the user holds down the left or right key
-        else if (drift < 2.0f)
-            drift += 0.04f;
-        if (accelerate) {
-            dx += thrust * std::cos(direction);
-            dy += thrust * std::sin(direction);
-            if (step % framedelta == 0) 
-                frame = (frame + 1) % framecount;
-        }
-        // Update dx and dy
-        x += dx;
-        y += dy;
-        dx *= drag;
-        dy *= drag;
-    } else {
-        explosion->update();
-    }
-    if (step % 5 == 0) {
-        if (step < 120 && blink) {
-            if (!visible)
-                visible = true;
-            else 
-                visible = false;
-        } else {
-            visible = true;
-            blink = false;
-        }
-    }
-    step++;
-
-}
-
-void Ship::drawAt(float x, float y)
-{
-    if (!alive) {
-        explosion->draw();
-        return;
-    }
-    if (!visible)
-        return;
-
-    glPushMatrix();
-    // Move to ship coordinates
-    glTranslatef(x, y, 0.0f);
-    glRotatef(direction*180/kPI, 0.0f, 0.0f, 1.0f);
-
-    // Enable vertex arrays
-    glEnableClientState(GL_VERTEX_ARRAY);
-
-    // Load vertex pointer
-    glVertexPointer(3, GL_FLOAT, 0, ::vertices);
-
-    // Draw current frame
-    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, ::frames[frame]);
-
-    // Disable vertex arrays
-    glDisableClientState(GL_VERTEX_ARRAY);
-    glPopMatrix();
-}
-
-Sprite *Ship::fire()
-{
-    float dx = this->dx + 1.8f * cos(this->direction);
-    float dy = this->dy + 1.8f * sin(this->direction);
-    Bullet *bullet = new Bullet(this->x + size*cos(this->direction),
-                                this->y + size*sin(this->direction),
-                                dx, dy);
-    return dynamic_cast<Sprite *>(bullet);
-}

Ship.h

-// Ship.h
-// Copyright (c) 2011 James O'Doherty
-// All Rights Reserved.
-
-#ifndef SHIP_H__
-#define SHIP_H__
-
-#include "MirroredSprite.h"
-#include "Explosion.h"
-
-class Ship : public MirroredSprite
-{
-    float x;
-    float y;
-    float direction;
-    float dx;
-    float dy;
-    bool left;
-    bool right;
-    bool accelerate;
-    int frame;
-    unsigned int step;
-    bool alive;
-    bool blink;
-    bool visible;
-    Explosion *explosion;
-    static const int framecount;
-    static const float thrust;
-    static const float drag;
-    static const float size;
-
-public:
-    Ship(float = 0.0, float = 0.0);
-    ~Ship();
-
-    // Required accessors
-    float getSize() {
-        return size;
-    }
-    Point getLocation() {
-        Point p = {x,y};
-        return p;
-    }
-    void setLocation(Point p) {
-        x = p.x;
-        y = p.y;
-    }
-
-    // Optional overrides
-    bool isPhysical() {
-        return !blink;
-    }
-    bool isVisible() {
-        return visible;
-    }
-
-    // Other accessors
-    bool isAlive() {
-        return alive;
-    }
-    bool isReady() {
-        return explosion->isFinished();
-    }
-    void revive() {
-        if (isReady()) {
-            dx = 0;
-            dy = 0;
-            alive = true;
-            step = 0;
-            blink = true;
-            delete explosion;
-        }
-    }
-    void kill() {
-        alive = false;
-        frame = 0;
-        explosion = new Explosion(x,y);
-    }
-
-    // Used for player controls
-    void setLeft() {
-        left = true;
-    }
-    void clearLeft() {
-        left = false;
-    }
-    void setRight() {
-        right = true;
-    }
-    void clearRight() {
-        right = false;
-    }
-    void setAccelerate() {
-        accelerate = true;
-    }
-    void clearAccelerate() {
-        frame = 0;
-        accelerate = false;
-    }
-
-    void drawAt(float x, float y);
-    void update();
-
-    Sprite *fire();
-
-private:
-    void clearState() {
-        left = false;
-        right = false;
-        accelerate = false;
-        dx = 0.0;
-        dy = 0.0;
-        frame = 0;
-        alive = true;
-    }
-};
-
-#endif // SHIP_H__

Sprite.h

-// Sprite.h
-// Copyright (c) 2011 James O'Doherty
-// All Rights Reserved
-
-#ifndef SPRITE_H__
-#define SPRITE_H__
-
-#include "Geometry.h" 
-
-// Sprite is an abstract class describing an interface for an object that 
-// maintains a modeled state and can render itself onto the OpenGL screen.
-class Sprite
-{
-public:
-    // Required accessors
-    virtual float getSize() = 0;
-    virtual Point getLocation() = 0;
-
-    // Required game loop calls
-    virtual void update() = 0;
-    virtual void drawAt(float, float) = 0;
-
-    // Default drawing routine
-    virtual void draw() {
-        Point p = getLocation();
-        drawAt(p.x, p.y);
-    }
-
-    // Optional hooks for adding handlers that get
-    // called before and after update() respectively
-    virtual void preUpdateHandler() {}
-    virtual void postUpdateHandler() {}
-
-    // Optional collision detection use override
-    virtual bool isPhysical() {
-        return true;
-    }
-    virtual bool isVisible() {
-        return true;
-    }
-
-    // Default collision detection routine
-    virtual bool detectCollision(Sprite &s) {
-        if (!isPhysical() || !s.isPhysical())
-            return false;
-
-        Circle p = {getLocation(), getSize()/2.0f};
-        Circle q = {s.getLocation(), s.getSize()/2.0f};
-
-        if (isOverlapping(p, q))
-            return true;
-        return false;
-    }
-
-    virtual bool isOutOfBounds() {
-        Point p = getLocation();
-        return (p.x < -110.0f ||
-                p.y < -110.0f ||
-                p.x > 110.0f ||
-                p.y > 110.0f);
-    }
-
-};
-
-
-#endif // SPRITE_H__

Vector2d.h

-#ifndef VECTOR_2D_H__
-#define VECTOR_2D_H__
-
-#include <cmath>
-
-class Vector2d {
-public:
-    float x;
-    float y;
-
-    Vector2d() : x(0.0f), y(0.0f)
-    {}
-
-    Vector2d(float x, float y) : x(x), y(y)
-    {}
-
-    float getMagnitude();
-    void normalize();
-    void reverse();
-
-    Vector2d& operator+= (Vector2d);
-    Vector2d& operator-= (Vector2d);
-    Vector2d& operator*= (float);
-    Vector2d& operator/= (float);
-
-    Vector2d operator- ();
-};
-
-inline float Vector2d::getMagnitude() {
-    return (float) std::sqrt(x*x+y*y);
-}
-
-inline void Vector2d::normalize() {
-    const float tol = 0.0001f;
-    float m = getMagnitude();
-    if (m <= tol) m = 1;
-    x /= m;
-    y /= m;
-
-    if (std::fabs(x) < tol) x = 0.0f;
-    if (std::fabs(y) < tol) y = 0.0f;
-}
-
-inline void Vector2d::reverse() 
-{
-    x = -x;
-    y = -y;
-}
-
-inline Vector2d& Vector2d::operator += (Vector2d u)
-{
-    x += u.x;
-    y += u.y;
-    return *this;
-}
-
-inline Vector2d& Vector2d::operator-= (Vector2d u)
-{
-    x -= u.x;
-    y -= u.y;
-    return *this;
-}
-
-inline Vector2d& Vector2d::operator*= (float s)
-{
-    x *= s;
-    y *= s;
-    return *this;
-}
-
-inline Vector2d& Vector2d::operator/= (float s)
-{
-    x /= s;
-    y /= s;
-    return *this;
-}
-
-inline Vector2d Vector2d::operator- () 
-{
-    return Vector2d(-x, -y);
-}
-
-
-inline Vector2d operator+ (Vector2d u, Vector2d v)
-{
-    return Vector2d(u.x + v.x, u.y+v.y);
-}
-
-inline Vector2d operator- (Vector2d u, Vector2d v)
-{
-    return Vector2d(u.x - v.x, u.y-v.y);
-}
-
-inline float operator* (Vector2d u, Vector2d v)
-{
-    return (u.x*v.x + u.y*v.y);
-}
-
-inline Vector2d operator*(float s, Vector2d u)
-{
-    Vector2d p(u.x*s, u.y*s);
-    return p;
-}
-
-inline Vector2d operator*(Vector2d u, float s)
-{
-    Vector2d p(u.x*s, u.y*s);
-    return p;
-}
-
-inline Vector2d operator/ (Vector2d u, float s)
-{
-    Vector2d p(u.x/s, u.y/s);
-    return p;
-}
-
-
-#endif // VECTOR_2D_H__

main.cpp

-// main.cpp - Game initialization and main loop
-// Copyright (c) 2011 James O'Doherty
-// All Rights Reserved
-
-#include <SDL.h>
-#include "Game.h"
-
-using namespace std;
-
-int main(int argc, char *argv[])
-{
-    Game game;
-    game.run();
-    return 0;
-}
+// Copyright (c) 2011 James O'Doherty
+// All Rights Reserved.
+
+#include "Common.h"
+#include "Asteroid.h"
+#include <algorithm>
+#include <ctime>
+
+using namespace std;
+
+const float Asteroid::kMaxSize = 64.0f;
+const float Asteroid::kMinSize = 4.0f;
+
+static const GLfloat vertices[] = {
+    -1.0f, -0.667f,
+    0.0f, -1.0f,
+    0.667f, -0.667f,
+    0.5f, -0.5f,
+    1.0f, 0.0f,
+    0.667f, 0.667f,
+    0.0f, 1.0f,
+    -0.667f, 0.667f,
+    -0.667f, 0.333f,
+    -1.0f, 0.0f
+};
+
+static const GLuint indices[] = {0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,0};
+static const int indice_count = 20;
+
+void Asteroid::init() 
+{
+    angle = kPI/4;
+    angular_velocity = kPI/64.0f/(rand()%3+1);
+    if (size > kMaxSize)
+        this->size = kMaxSize;
+    if (size < kMinSize)
+        this->size = kMinSize;
+    disabled = false;
+}
+
+Asteroid::Asteroid(float size) : size(size)
+{
+    float a = (rand()%100)/50.0f * kPI;
+    x = 99.0f * cos(a);
+    y = 99.0f * sin(a);
+    init();
+    Vector2d p(-x,-y);
+    p.normalize();
+    velocity = p*0.3f;
+}
+
+Asteroid::Asteroid(float x, float y, float size) 
+                  : x(x), y(y), size(size)
+{
+    init();
+    float heading = kPI*static_cast<float>(rand()%100)/50.0f;
+    float speed = static_cast<float>(rand()%55)/50.0f * (size/(size+0.5f)) *0.3f;
+    velocity.x = speed * cos(heading);
+    velocity.y = speed * sin(heading);
+}
+
+Asteroid::~Asteroid()
+{}
+
+bool Asteroid::createChildren(Asteroid *children[]) 
+{
+    if (disabled || size/2.2f < kMinSize)
+        return false;
+
+    children[0] = new Asteroid(x-size/4.0f, y+size/4.0f, size/2.2f);
+    children[1] = new Asteroid(x-size/4.0f, y-size/4.0f, size/2.2f);
+    children[2] = new Asteroid(x+size/4.0f, y+size/4.0f, size/2.2f);
+    children[3] = new Asteroid(x+size/4.0f, y-size/4.0f, size/2.2f);
+    return true;
+}
+
+void Asteroid::collide(Asteroid &a)
+{
+    float m1 = size*size;
+    float m2 = a.size*a.size;
+    Vector2d normal(a.velocity.x-velocity.x,a.velocity.y-velocity.y);
+    normal.normalize();
+    Vector2d tangent(-normal.y, normal.x);
+    float v1n = normal*velocity;
+    float v1t = tangent*velocity;
+    float v2n = normal*a.velocity;
+    float v2t = tangent*a.velocity;
+    float v1n_ = (v1n*(m1-m2)+2*m2*v2n)/(m1+m2);
+    float v2n_ = (v2n*(m2-m1)+2*m1*v1n)/(m1+m2);
+    velocity = v1n_ * normal + v1t*tangent;
+    a.velocity = v2n_ * normal + v2t * tangent;
+}
+
+void Asteroid::update()
+{
+    angle += angular_velocity;
+    x += velocity.x;
+    y += velocity.y;
+}
+
+void Asteroid::drawAt(float x, float y)
+{
+    glPushMatrix();
+    glTranslatef(x, y, 0.0f);
+    glScalef(size/2.0f, size/2.0f, 1.0f);
+    glRotatef(angle*180/kPI, 0.0f, 0.0f, 1.0f);
+    glEnableClientState(GL_VERTEX_ARRAY);
+    glVertexPointer(2, GL_FLOAT, 0, vertices);
+    glDrawElements(GL_LINES, indice_count, GL_UNSIGNED_INT, indices);
+    glDisableClientState(GL_VERTEX_ARRAY);
+    glPopMatrix();
+}
+
+// Copyright (c) 2011 James O'Doherty
+// All Rights Reserved.
+
+#ifndef ASTEROID_H__
+#define ASTEROID_H__
+
+#include "MirroredSprite.h"
+#include "Vector2d.h"
+
+class Asteroid : public MirroredSprite
+{
+    float x;
+    float y;
+    Vector2d velocity;
+    float size;
+    float angle;
+    float angular_velocity;
+    bool disabled;
+
+    void init();
+
+public:
+    Asteroid(float size);
+    Asteroid(float x, float y, float size);
+    ~Asteroid();
+
+    // Child factory function
+    bool createChildren(Asteroid **);
+
+    // Required accessors
+    float getSize() {
+        return size;
+    }
+    Point getLocation() {
+        Point p = {x, y};
+        return p;
+    }
+    void setLocation(Point p) {
+        x = p.x;
+        y = p.y;
+    }
+
+    // Asteroid specific accessors
+    void disable() {
+        disabled = true;
+    }
+
+    void reverse() {
+        x -= 0.1f*velocity.x;
+        y -= 0.1f*velocity.y;
+    }
+
+    // collide handles collisions with other Asteroids
+    void collide(Asteroid &);
+
+    void update();
+    void drawAt(float x, float y);
+
+    static const float kMaxSize;
+    static const float kMinSize;
+
+};
+
+#endif // ASTEROID_H__

src/AudioService.h

+#ifndef AUDIO_SERVICE_H__
+#define AUDIO_SERVICE_H__
+
+typedef int AudioHandle;
+
+class AudioService
+{
+public:
+    virtual void release() = 0;
+
+    virtual AudioHandle playSample(const char *, int = 0) = 0;
+    virtual void stopSample(AudioHandle) = 0;
+    virtual void playTrack(const char *) = 0;
+};
+
+AudioService *GetAudioServiceInstance();
+
+#endif // AUDIO_SERVICE_H__
+// Bullet.cpp
+// Copyright (c) 2011 James O'Doherty
+// All Rights Reserved.
+
+#include "Common.h"
+#include "Bullet.h"
+
+const float Bullet::size = 1.2f;
+
+void Bullet::update() 
+{
+    x += dx;
+    y += dy;
+}
+
+void Bullet::drawAt(float x, float y)
+{
+    glPushMatrix();
+    glTranslatef(x, y, 0.0f);
+    glRectf(-size/2.0f, -size/2.0f, size/2.0f, size/2.0f);
+    glPopMatrix();
+}
+
+// Bullet.h
+// Copyright (c) 2011 James O'Doherty
+// All Rights Reserved.
+
+#ifndef BULLET_H__
+#define BULLET_H__
+
+#include "MirroredSprite.h"
+
+class Bullet : public Sprite
+{
+    float x;
+    float y;
+    float dx;
+    float dy;
+    static const float size;
+
+public:
+    Bullet(float x, float y, float dx, float dy) 
+          : x(x), y(y), dx(dx), dy(dy)
+    {}
+    
+    float getSize() {
+        return size;
+    }
+    Point getLocation() {
+        Point p = {x,y};
+        return p;
+    }
+    void setLocation(Point p) {
+        x = p.x;
+        y = p.y;
+    }
+
+    void update();
+    void drawAt(float x, float y);
+
+    friend class Ship;
+};
+
+#endif // BULLET_H__
+#ifndef COMMON_H__
+#define COMMON_H__
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#ifdef __APPLE__
+    #include <OpenGL/glu.h>
+    #include <OpenGL/glext.h>
+#else
+    #include <GL/gl.h>
+    #include <GL/glu.h>
+#endif
+#include <cstdlib>
+#include <cmath>
+
+#include "Geometry.h"
+#include "Resources.h"
+
+#endif // COMMON_H__
+#ifndef EXPLOSION_H__
+#define EXPLOSION_H__
+
+#include "Sprite.h"
+#include "Vector2d.h"
+#include "Common.h"
+#include <cmath>
+
+class Explosion : public Sprite
+{
+    float x;
+    float y;
+    float points[200];
+    Vector2d velocities[100];
+    float color[3];
+    float psize;
+    unsigned long int step;
+
+public:
+    Explosion(float x, float y) : x(x), y(y) {
+        for (int i=0; i<200; i++)
+            points[i] = 0.0;
+        for (int i=0; i<100; i++) {
+            velocities[i].x = 1.0f * cos(i*kPI/50.0f);
+            velocities[i].y = 1.0f * sin(i*kPI/50.0f);
+        }
+        color[0] = 1.0f;
+        color[1] = 1.0f;
+        color[2] = 1.0f;
+        step = 0;
+        psize = 3.0f;
+    }
+    ~Explosion() {
+    }
+
+    Point getLocation() {
+        Point p = {x,y};
+        return p;
+    }
+
+    float getSize() {
+        return 10.0f;
+    }
+
+    bool isPhysical() {
+        return false;
+    }
+
+    void drawAt(float x, float y) {
+        glPushMatrix();
+        // Enable vertex arrays
+        glEnableClientState(GL_VERTEX_ARRAY);
+
+        glTranslatef(x, y, 0.0f);
+        glVertexPointer(2, GL_FLOAT, 0, points);
+        glPushAttrib(GL_CURRENT_BIT);
+        glColor3fv(color);
+        glPointSize(psize);
+        glDrawArrays(GL_POINTS, 0, 100);
+        glPopAttrib();
+
+        // Disable vertex arrays
+        glDisableClientState(GL_VERTEX_ARRAY);
+        glPopMatrix();
+    }
+
+    void update() {
+        for (int i=0; i<100; i++) {
+            points[2*i] += velocities[i].x; 
+            points[2*i + 1]  += velocities[i].y;
+            velocities[i].x *= 0.94f;
+            velocities[i].y *= 0.94f;
+        }
+        for (int i=0; i<3; i++)
+            color[i] *= 0.90f;
+        psize *= 0.98f;
+    }
+    
+    bool isFinished() {
+        if (psize < 1.0f)
+            return true;
+        return false;
+    }
+
+};
+
+#endif // EXPLOSION_H__
+// Game.cpp
+// Copyright (c) 2011 James O'Doherty
+// All Rights Reserved.
+
+#include <iostream>
+#include <cstdlib>
+#include <ctime>
+#include <set>
+#include <list>
+#include <algorithm>
+#include <functional>
+
+#ifdef USE_SDL
+#include <SDL.h>
+
+static SDL_Surface *screen = NULL;
+#endif 
+
+#include "Common.h"
+
+#include "Ship.h"
+#include "Bullet.h"
+#include "Asteroid.h"
+#include "Game.h"
+
+using namespace std;
+
+Game::Game()
+{
+    int width, height;
+#ifdef USE_SDL
+    // Initialize SDL subsystems
+    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) < 0) {
+        cerr << "Error, couldn't initialize SDL: " 
+             << SDL_GetError() << endl;
+        exit(EXIT_FAILURE);
+    }
+    atexit(SDL_Quit);
+
+    // Initialize SDL screen
+    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+    screen = SDL_SetVideoMode(800, 600, 0, 
+                              SDL_OPENGL | SDL_HWSURFACE | SDL_RESIZABLE);
+
+    if (!screen) {
+        cerr << "Error, video initialization failed: " 
+             << SDL_GetError() << endl;
+        exit(EXIT_FAILURE);
+    }
+
+    width = screen->w;
+    height = screen->h;
+
+#endif
+    // Set up the screen
+    reshape(width, height);
+
+    // Set up our audio service
+    audio = GetAudioServiceInstance();
+
+    // Initialize sprites and scene data list
+    player = new Ship();
+    sprites.insert(dynamic_cast<Sprite *>(player));
+}
+
+Game::~Game()
+{
+    for (set<Sprite*>::iterator it = sprites.begin(); it != sprites.end(); it++)
+        delete *it;
+    audio->release();
+}
+
+void Game::run()
+{
+    srand(static_cast<unsigned int>(time(NULL)));
+
+    // Start playing background music
+    audio->playTrack(r_bg_music_track);
+
+#ifdef USE_SDL
+    // Prepare game loop
+    bool quit = false;
+    Uint32 ticks = SDL_GetTicks();
+    const Uint32 delta = 20;
+
+    // Run game loop
+    while (!quit) {
+        quit = poll();
+        // Update game physics if the correct time delta has passed
+        while (SDL_GetTicks() > ticks + delta) {
+            update();
+            ticks += delta;
+        }
+        // Render screen and sprites
+        draw();
+        // Detect and report OpenGL error conditions
+        while (GLenum error = glGetError() != GL_NO_ERROR) {
+            cerr << gluErrorString(error) << endl;
+        }
+    }
+#endif
+}
+
+void Game::toggleFullScreen()
+{
+#ifdef USE_SDL
+    // *todo*
+#endif
+}
+
+void Game::reshape(int w, int h)
+{
+    if (h == 0)
+        h = 1;
+    GLfloat aspectRatio = (GLfloat)w/(GLfloat)h;
+
+    // Set up the OpenGL project screen
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+
+    // Fill the entire window
+    glViewport(0,0,w,h);
+    // Center the projection on 0,0 and ensure an x,y
+    // range of at least 100 in all 4 directions is visible.
+    if (w <= h) {
+        left = 0;
+        bottom = (h-w)/2;
+        width = w;
+        height = w;
+        glOrtho(-100.0,100.0,-100.0/aspectRatio,100.0/aspectRatio,0,1);
+    } else {
+        bottom = 0;
+        left = (w-h)/2;
+        width = h;
+        height = h;
+        glOrtho(-100.0*aspectRatio,100.0*aspectRatio,-100.0, 100,0,1);
+    }
+
+    glMatrixMode(GL_MODELVIEW);
+    glDisable(GL_DEPTH_TEST);
+    glLoadIdentity();
+
+    glClearColor(0.0f,0.0f,0.0f,0.0f);
+    glClear(GL_COLOR_BUFFER_BIT);
+}
+
+void Game::update()
+{
+    static int step = 3;
+
+    set<Sprite *>::iterator it;
+    set<Sprite *>::iterator it2;
+