Jump to content

  • Log In with Google      Sign In   
  • Create Account


chiranjivi

Member Since 27 Feb 2010
Offline Last Active Jul 15 2014 05:20 PM
-----

Topics I've Started

Management of game objects

23 March 2014 - 12:08 PM

Hi all,

 

I'm trying to implement a sensible management system for all the objects in a basic platform game. There are various types of objects - projectiles, the player, enemies, powerups, moving platforms, that type of thing.

 

Initially I thought for the sake of simplicity I'd have all objects derive from a base class Entity, and then stick them all in a vector<Entity*>. Then when it's time for them to act or to be drawn to the screen, I can just make a single pass over the vector and call it->update() or it->display(). This saves a bunch of code duplication from having them all in separate vectors for each type and having to iterate over each vector separately to call display functions and so on.

 

Difficulties arise with this method when I need to do something like collision-test all Projectiles against all Enemies - I have to iterate over the vector, testing if each element is a Projectile, and if it is, iterate over the vector again testing to see if each element is an Enemy, and then testing for a collision if so. I have to do this a bunch of times for, say, enemies vs projectiles, player vs projectiles, player vs powerups, enemies vs player, and it turns into a huge tangled mess of code and nested iterations over the vector, and the vast majority of element comparisons don't need to be made as the entities are of the wrong type.

 

I'm looking for an elegant way to simplify this, so that Type A vs Type B checks are as simple as possible, and also so that mass updating and displaying of objects is equally simple.

 

Is there an accepted best practice for this kind of thing? Thanks in advance for any replies.


C++ vector of boost::weak_ptr troubles

03 August 2013 - 07:48 PM

I have a game that has a number of ships in space. The ships exist in the gameworld as boost::shared_ptr<Ship>. These ships can attack one another. The Ship class has a boost::weak_ptr<Ship> called target, which holds a reference to whatever it's currently firing at, and it also has a vector of weak_ptr<Ship> called aggro_vector. The aggro vector records all ships that have attacked this Ship, so that when it kills its current target, it can consult its aggro vector to see which other ships it is currently in combat with, and pick a new target.

 

This is the Ship class, sanitised:

class Ship
{
    public:
    Ship (int x, int y);

    boost::weak_ptr<Ship> target;
    std::vector< boost::weak_ptr<Ship> > aggro_vector;

    void determine_next_target();
    void set_as_target (boost::shared_ptr<Ship> next_target);
}

 

What I'm having trouble with is getting the Ship to correctly look through its aggro_vector and choose a new target.

 

Here is the function that picks the next target from the aggro vector. It iterates through all the weak_ptrs, and if .lock() successfully returns a shared_ptr, it hands this shared_ptr off to the member function that registers the next target. Otherwise the weak_ptr refers to a ship that has since been destroyed and is removed from the aggro vector:

void Ship::determine_next_target()
{
    std::vector< boost::weak_ptr<Ship> >::iterator it = aggro_vector.begin();
    while(it != aggro_vector.end()) {
        if (boost::shared_ptr<Ship> this_ship = (*it).lock()) {
            set_as_target(this_ship);
            ++it;
        } else {
            it = aggro_vector.erase(it);
        }
    }
}

 

When this code is compiled and run, it crashes at the line set_as_target(this_ship). If this line is commented out, the remainder of the code works as it should (although obviously the determine_next_target() function now does nothing other than remove expired weak_ptrs).

 

To be clear, the set_as_target(boost::shared_ptr<Ship>) function works fine and is called from a bunch of other places in the code with no problem. It doesn't appear to be that function, but rather the fact that I'm attempting to call that function in this way.

 

Why am I having problems passing a shared_ptr to an outside function in this fashion? Is there something about iterating over a vector of weak_ptr that I'm missing, or am I just failing to grasp, in the broader sense, some aspect of how these pointers should be used?

 

Thanks in advance for any help.


GLFW/GLUT glutBitmapString - high CPU usage?

01 July 2013 - 02:15 PM

I'm messing around with a simple game using GLFW with freeglut to render text. I noticed that it was using far more CPU than I would have expected, and after commenting out various bits of code I realised it was the (minimal) GUI that was causing the problem.

 

Every frame, the game writes about half a dozen strings to the screen ("SCORE: 3000", "LIVES: 5", that kind of thing). If I disable this overlay, the CPU usage drops to about 2-5%. If I re-enable it, CPU usage skyrockets to about 40-50% and the game visibly slows down.

 

This is the code I'm using to render text:

void draw_string(int x, int y, string output) {
    glRasterPos2i(x, y);
    glutBitmapString(GLUT_BITMAP_HELVETICA_12, (const unsigned char*)output.c_str());
}

Am I doing something really stupid here without realising it? I cannot understand why I can render thousands of primitives per frame and OpenGL doesn't even blink, but as soon as I try to render a handful of lines of text my processor begins to buckle under the strain (and it's a 3.4GHz quad, it's not like it's a netbook or whatever).

 

Why is doing something that appears to be fairly simple causing such massive demands of my CPU?

 

Thanks in advance for any responses


SDL - inconsistent timing of sounds...?

26 March 2013 - 11:48 AM

I'm trying to make an application which functions as a metronome, clicking at a rate of 60 BPM. I'm having issues though - if i use Mix_PlayChannel() to play a 'click' sound once every 1000ms, i seem to get something very different than a steady one click per second.

I recorded the sound output in Audacity and compared clicks, and they seem to be spread out by as little as 900ms and sometimes as much as 1100ms for no reason that I can see. I assumed something must have been thrown off somewhere, so in the function that plays the sound I added:

void play_click() {
    std::cout << "click on note " << n << " at " << SDL_GetTicks() << " ticks\n";
    Mix_PlayChannel( -1, metronome, 0 );
}


The output this gives me is this:

click on note 1 at 1116 ticks
click on note 2 at 2116 ticks
click on note 3 at 3116 ticks
click on note 4 at 4116 ticks
click on note 5 at 5116 ticks
click on note 6 at 6116 ticks
click on note 7 at 7116 ticks
click on note 8 at 8116 ticks
click on note 9 at 9116 ticks
click on note 10 at 10116 ticks
click on note 11 at 11116 ticks
click on note 12 at 12116 ticks
click on note 13 at 13116 ticks
click on note 14 at 14116 ticks
click on note 15 at 15116 ticks

So yeah, I'm thoroughly confused. The application reports that it is triggering the sound every time at a precisely 1000ms interval without even a millisecond's variance - but when you actually listen to the sound it outputs, it's all over the place.

Are there inherent timing problems with sound in SDL that I wasn't aware of or have i just done something dumb (I suspect the latter?)

Thank you for any help

Help me understand .cpp vs .h in C++

24 March 2013 - 08:15 AM

Having trouble getting my head around the concept of separating code into .cpp and .h files. I've been coding in C++ for a while now and have never done anything other than just stick all code into header files, which I guess I'm going to have to grow out of eventually.

Here's an example of the problems I'm having. This is the level class for a toy game. From what I have been reading I believe I'm supposed to split it into level.h and level.cpp something like this:

level.h
#ifndef LEVEL_H_INCLUDED
#define LEVEL_H_INCLUDED

class Level {
    public:
    Level();

    int width, height;
    int map_grid[20][20];

    void display_grid();
};

#endif // LEVEL_H_INCLUDED

level.cpp
#include "level.h"

Level::Level() {
    width = height = 20;
    for ( int i = 0; i != width; ++i ) for ( int j = 0; j != height; ++j ) {
        if ( i == 0 || i == width-1 || j == 0 || j == height-1 ) {
            map_grid[j][i] = 1;
        } else {
            map_grid[j][i] = 0;
        }
    }
}

void Level::display_grid() {
    for (int i = 0; i != width; ++i ) for ( int j = 0; j != height; ++j ) {
        if ( map_grid[j][i] == 1 ) draw_sprite( i*64, j*64, block_blue, screen );
    }
}

When I do this, the compiler doesn't like level.cpp, saying 'draw_sprite', 'block_blue' and 'screen' have not been declared. 'draw_sprite' is a function and 'block_blue' and 'screen' are SDL_Surfaces, and they have been declared in an earlier include ("sdl_functions.h"). Attempting to #include sdl_functions.h again at the start of level.cpp prompts the compiler to get angry about me trying to re-declare a load of stuff.

What I don't understand is that if I just mash level.h and level.cpp together into a single header file:

level.h
#ifndef LEVEL_H_INCLUDED
#define LEVEL_H_INCLUDED

class Level {
    public:
    Level();

    int width, height;
    int map_grid[20][20];

    void display_grid();
};

Level::Level() {
    width = height = 20;
    for ( int i = 0; i != width; ++i ) for ( int j = 0; j != height; ++j ) {
        if ( i == 0 || i == width-1 || j == 0 || j == height-1 ) {
            map_grid[j][i] = 1;
        } else {
            map_grid[j][i] = 0;
        }
    }
}

void Level::display_grid() {
    for (int i = 0; i != width; ++i ) for ( int j = 0; j != height; ++j ) {
        if ( map_grid[j][i] == 1 ) draw_sprite( i*64, j*64, block_blue, screen );
    }
}

#endif // LEVEL_H_INCLUDED

...then it works?

Obviously there are huge gaps in my knowledge as to how header and source files are supposed to interact (as well as in many other areas :P), so please go easy on me for asking a very stupid question. Thanks.

PARTNERS