Commits

jodoherty  committed 6e6c985

Major overhaul of the memory management to use shared_ptr and
the game update loop to eliminate bugs.

  • Participants
  • Parent commits 7c39587

Comments (0)

Files changed (10)

File CMakeLists.txt

 	src/Ship.h
 )
 
-set(DEFINES "-DUSE_SDL")
-
 if (MSVC)
-	set(PLATFORM_C_FLAGS "/W3 /MD /O2 /Gs /DUNICODE /DWIN32 /D_CRT_SECURE_NO_WARNINGS")
-	set(PLATFORM_C_FLAGS_DEBUG "/W3 /MDd /Zi /Od /DUNICODE /DWIN32 /D_CRT_SECURE_NO_WARNINGS")
+	set(PLATFORM_C_FLAGS "/W3 /MD /O2 /EHsc /DUNICODE /DWIN32 /D_CRT_SECURE_NO_WARNINGS")
+	set(PLATFORM_C_FLAGS_DEBUG "/W3 /MDd /Zi /Od /EHsc /DUNICODE /DWIN32 /D_CRT_SECURE_NO_WARNINGS")
+	set(PLATFORM_CXX_FLAGS "${PLATFORM_C_FLAGS}")
+	set(PLATFORM_CXX_FLAGS_DEBUG "${PLATFORM_C_FLAGS_DEBUG}")
+	set(BOOST_ROOT "C:\\boost_1_48_0")
 endif(MSVC)
 
 
-set(CMAKE_C_FLAGS "${PLATFORM_C_FLAGS} ${DEFINES}")
-set(CMAKE_C_FLAGS_RELEASE "${PLATFORM_C_FLAGS} ${DEFINES}")
-set(CMAKE_C_FLAGS_DEBUG "${PLATFORM_C_FLAGS_DEBUG} ${DEFINES}")
+set(CMAKE_C_FLAGS "${PLATFORM_C_FLAGS}")
+set(CMAKE_C_FLAGS_RELEASE "${PLATFORM_C_FLAGS}")
+set(CMAKE_C_FLAGS_DEBUG "${PLATFORM_C_FLAGS_DEBUG}")
+set(CMAKE_CXX_FLAGS "${PLATFORM_CXX_FLAGS}")
+set(CMAKE_CXX_FLAGS_RELEASE "${PLATFORM_CXX_FLAGS}")
+set(CMAKE_CXX_FLAGS_DEBUG "${PLATFORM_CXX_FLAGS_DEBUG}")
 
+set(CMAKE_BUILD_TYPE "Release")
+
+set(Boost_ADDITIONAL_VERSIONS "1.48" "1.48.0" "1.47" "1.47.0")
+
+find_package(Boost REQUIRED)
+include_directories(${Boost_INCLUDE_DIRS})
 
 find_package(OpenGL REQUIRED)
+find_package(GLew REQUIRED)
 find_package(SDL REQUIRED)
 find_package(SDL_mixer REQUIRED)
 
 link_libraries(
 	${OPENGL_LIBRARY}
+	${GLEW_LIBRARY}
 	${SDL_LIBRARY}
 	${SDLMIXER_LIBRARY}
 )
-add_executable(asteroids WIN32 MACOSX_BUNDLE ${SOURCES})
+add_executable(asteroids MACOSX_BUNDLE ${SOURCES})
 

File src/Asteroid.cpp

 }
 
 Asteroid::~Asteroid()
-{}
+{
+    #ifdef DEBUG
+    cout << "Destroyed Asteroid!\n";
+    #endif
+}
 
 bool Asteroid::createChildren(Asteroid *children[]) 
 {

File src/Bullet.h

     Bullet(float x, float y, float dx, float dy) 
           : x(x), y(y), dx(dx), dy(dy)
     {}
+
+    ~Bullet() {
+        #ifdef DEBUG
+        std::cout << "Destroyed Bullet!\n";
+        #endif
+    }
     
     float getSize() {
         return size;

File src/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 <glew.h>
+
 #include "Geometry.h"
 #include "Resources.h"
 

File src/Explosion.h

     float y;
     float points[200];
     Vector2d velocities[100];
-    float color[3];
+    float color[4];
     float psize;
     unsigned long int step;
 
             velocities[i].y = 1.0f * sin(i*kPI/50.0f);
         }
         color[0] = 1.0f;
-        color[1] = 1.0f;
-        color[2] = 1.0f;
+        color[1] = 0.8f;
+        color[2] = 0.4f;
+        color[3] = 1.0f;
         step = 0;
         psize = 3.0f;
     }
         glTranslatef(x, y, 0.0f);
         glVertexPointer(2, GL_FLOAT, 0, points);
         glPushAttrib(GL_CURRENT_BIT);
-        glColor3fv(color);
+        glColor4fv(color);
         glPointSize(psize);
         glDrawArrays(GL_POINTS, 0, 100);
         glPopAttrib();
             velocities[i].x *= 0.94f;
             velocities[i].y *= 0.94f;
         }
-        for (int i=0; i<3; i++)
-            color[i] *= 0.90f;
+        color[3] *= 0.90f;
         psize *= 0.98f;
     }
     

File src/Game.cpp

 #include <iostream>
 #include <cstdlib>
 #include <ctime>
-#include <set>
-#include <list>
+#include <vector>
 #include <algorithm>
-#include <functional>
 
-#ifdef USE_SDL
+#include <boost/shared_ptr.hpp>
+#include <boost/pointer_cast.hpp>
+#include <boost/bind.hpp>
+#include <boost/functional.hpp>
+
+#include "Common.h"
+
 #include <SDL.h>
 
 static SDL_Surface *screen = NULL;
-#endif 
-
-#include "Common.h"
 
 #include "Ship.h"
 #include "Bullet.h"
 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: " 
     width = screen->w;
     height = screen->h;
 
-#endif
     // Set up the screen
     reshape(width, height);
 
     audio = GetAudioServiceInstance();
 
     // Initialize sprites and scene data list
-    player = new Ship();
-    sprites.insert(dynamic_cast<Sprite *>(player));
+    boost::shared_ptr<Ship> splayer(new Ship());
+    player = splayer;
+    sprites.push_back(splayer);
 }
 
 Game::~Game()
 {
-    for (set<Sprite*>::iterator it = sprites.begin(); it != sprites.end(); it++)
-        delete *it;
     audio->release();
 }
 
     // Start playing background music
     audio->playTrack(r_bg_music_track);
 
-#ifdef USE_SDL
     // Prepare game loop
     bool quit = false;
     Uint32 ticks = SDL_GetTicks();
             cerr << gluErrorString(error) << endl;
         }
     }
-#endif
 }
 
 void Game::toggleFullScreen()
 {
-#ifdef USE_SDL
     // *todo*
-#endif
 }
 
 void Game::reshape(int w, int h)
 {
     static int step = 3;
 
-    set<Sprite *>::iterator it;
-    set<Sprite *>::iterator it2;
+    vector< boost::shared_ptr<Sprite> >::iterator it;
+    vector< boost::shared_ptr<Sprite> >::iterator it2;
 
-    list<Sprite *>::iterator list_it;
+    vector< boost::shared_ptr<Sprite> >::iterator list_it;
+    vector< boost::shared_ptr<Sprite> > add_list;
 
-    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)));
+        for (int i=0; i<step; i++) {
+            boost::shared_ptr<Sprite> a(new Asteroid(rand()%16+12.0f+step));
+            sprites.push_back(a);
+        }
         step++;
     }
-
-    for (it = sprites.begin(); it != sprites.end(); it++) {
-        (*it)->preUpdateHandler();
-        (*it)->update();
-        (*it)->postUpdateHandler();
+    for_each(sprites.begin(), sprites.end(), 
+            boost::bind(&Sprite::preUpdateHandler,_1));
+    for_each(sprites.begin(), sprites.end(), boost::bind(&Sprite::update,_1));
+    for_each(sprites.begin(), sprites.end(), 
+            boost::bind(&Sprite::postUpdateHandler,_1));
+    sprites.erase(remove_if(sprites.begin(), sprites.end(),
+                    boost::bind(&Sprite::isOutOfBounds, _1)), sprites.end());
+    for (it = sprites.begin(); it != sprites.end();) {
         if ((*it)->isOutOfBounds())
-            destroy_list.push_back(*it);
+            it = sprites.erase(it);
+        else
+            it++;
     }
 
-    for (it = sprites.begin(); it != sprites.end(); it++) {
+    it = sprites.begin();
+    while (it != sprites.end()) {
         it2 = it;
-        for (it2++; it2 != sprites.end(); it2++) {
+        it2++;
+        while (it2 != sprites.end()) {
             if ((*it)->detectCollision(**it2)) {
                 // Use runtime type information to determine the appropriate
                 // course of action for the sprites.
                 // 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);
+                Asteroid *a1 = dynamic_cast<Asteroid *>(it->get());
+                Asteroid *a2 = dynamic_cast<Asteroid *>(it2->get());
 
                 if (a1 && a2) {
                     // Back up the asteroids so they don't overlap
                     }
                     // Now bounce the asteroids off of each other
                     a1->collide(*a2);
+                    #ifdef DEBUG
+                    cout << "a and a" << endl;
+                    #endif
                     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);
+                boost::shared_ptr<Bullet> b1 =
+                    boost::dynamic_pointer_cast<Bullet>(*it);
+                boost::shared_ptr<Bullet> b2 =
+                    boost::dynamic_pointer_cast<Bullet>(*it2);
 
                 if (b1 && b2) {
-                    // Mark the bullets for destruction
-                    destroy_list.push_back(b1);
-                    destroy_list.push_back(b2);
-                    continue;
+                    it = sprites.erase(it);
+                    sprites.erase(it2);
+                    #ifdef DEBUG
+                    cout << "b and b" << endl;
+                    #endif
+                    goto next_iteration;
                 }
 
                 // Now check to see if we have a bullet hitting an asteroid
                 Asteroid *a = NULL;
-                Bullet *b = NULL;
+                boost::shared_ptr<Bullet> b;
                 if (a1)
                     a = a1;
                 else if (a2)
                     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]);
+                        for (int i=0; i<4; i++) {
+                            boost::shared_ptr<Sprite> child(children[i]);
+                            add_list.push_back(child);
+                        }
                         audio->playSample(r_explosion_sample);
                     } else {
                         audio->playSample(r_smallexplosion_sample);
                     }
+                    Point position = a->getLocation();
+                    add_list.push_back(boost::shared_ptr<Sprite>(new
+                                        Explosion(position.x, position.y)));
                     a->disable();
-
-                    // Mark the old objects for destruction
-                    destroy_list.push_back(a);
-                    destroy_list.push_back(b);
-                    continue;
+                    sprites.erase(it2);
+                    it = sprites.erase(it);
+                    #ifdef DEBUG
+                    cout << "a and b" << endl;
+                    #endif
+                    goto next_iteration;
                 }
 
                 // Did something hit the player then?
                     // 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);
                 } 
-                
+            }
+            it2++;
+        } 
+        {
+            boost::shared_ptr<Explosion> e =
+                                boost::dynamic_pointer_cast<Explosion>(*it);
+            if (e && e->isFinished()) {
+                it = sprites.erase(it);
+                goto next_iteration;
             }
         }
+        it++;
+        next_iteration:;
     }
 
-    // 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++) {
+    // Prune new objects added on top of existing ones.
+    list_it = add_list.begin();
+    while (list_it != add_list.end()) {
+        bool erase = false;
+        for (it=sprites.begin(); it != sprites.end(); it++) {
             if ((*list_it)->detectCollision(**it)) {
-                delete *list_it;
-                add_list.erase(list_it++);
+                erase = true;
                 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;
-            }
-        }
+        if (erase)
+            list_it = add_list.erase(list_it);
+        else
+            list_it++;
     }
-
     // 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);
-    }
+        sprites.push_back(*list_it);
+    } 
 }
 
 void Game::draw()
     glColor3f(1.0f, 1.0f, 1.0f);
     
     glEnable(GL_SCISSOR_TEST);
+    glEnable(GL_BLEND);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
     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();
-    }
+    for_each(sprites.begin(), sprites.end(), boost::bind(&Sprite::draw,_1));
+    glDisable(GL_BLEND);
     glDisable(GL_SCISSOR_TEST);
 
     glPushAttrib(GL_CURRENT_BIT);
         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)) {
                         break;
                     case SDLK_SPACE:
                         if (player->isAlive()) {
-                            sprites.insert(player->fire());
+                            sprites.push_back(boost::shared_ptr<Sprite>(player->fire()));
                             audio->playSample(r_fire_sample);
                         }
                         else
                 break;
         }
     }
-#endif
     return quit;
 }
 
 #include "AudioService.h"
 #include "Sprite.h"
 #include "Ship.h"
-#include <set>
+#include <vector>
+#include <boost/smart_ptr.hpp>
 
 class Game
 {
-    std::set<Sprite*> sprites;
-    Ship *player;
+    std::vector< boost::shared_ptr<Sprite> > sprites;
+    boost::shared_ptr<Ship> player;
     int left;
     int bottom;
     int width;

File src/Ship.cpp

 // Copyright (c) 2011 James O'Doherty
 // All Rights Reserved
 
+#include <boost/pointer_cast.hpp>
+
 #include "Common.h"
 #include "Ship.h"
 #include "Bullet.h"
 
 Ship::~Ship() 
 {
+    #ifdef DEBUG
+    std::cout << "Destroyed Ship!\n";
+    #endif
 }
 
 void Ship::update()
     glPopMatrix();
 }
 
-Sprite *Ship::fire()
+Bullet *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);
+    return bullet;
 }
 
 #include "MirroredSprite.h"
 #include "Explosion.h"
+#include "Bullet.h"
 
 class Ship : public MirroredSprite
 {
     void drawAt(float x, float y);
     void update();
 
-    Sprite *fire();
+    Bullet *fire();
 
 private:
     void clearState() {

File src/Sprite.h

 #ifndef SPRITE_H__
 #define SPRITE_H__
 
+#include <iostream>
 #include "Geometry.h" 
 
 // Sprite is an abstract class describing an interface for an object that 
 class Sprite
 {
 public:
+    virtual ~Sprite() { 
+        #ifdef DEBUG
+        std::cout << "Destroyed Sprite!\n"; 
+        #endif
+    };
     // Required accessors
     virtual float getSize() = 0;
     virtual Point getLocation() = 0;