Как правильно использовать SDL_FreeSurface при работе с вектором поверхностей - PullRequest
0 голосов
/ 13 ноября 2009

Я настроил небольшую игру-шутер в качестве учебного пособия для себя в SDL. У меня есть структура снаряда

struct projectile
{
    SDL_Surface* surface;
    int x;
    int y;
};

И я поместил это в вектор.

vector<projectile> shot;
projectile one_shot;

И когда я нажимаю пробел, я создаю новый снаряд и добавляю его к вектору, а затем они стираются при рендеринге.

Это работает нормально, но я, кажется, в случайных случаях получаю сообщение об ошибке "Программа перестала работать".

Так что мне интересно, как правильно освободить поверхности.

  • После этого я освобождаю их всех?
  • Освобождаю ли я каждый отдельный снимок, когда он выходит из экрана?
  • Или какой-то другой выбор?

UPDATE:

Я нашел, где происходит сбой при выходе, когда я сделал несколько выстрелов, и все они вышли из экрана. Я попытался заменить код, который добавляет поверхность к вектору, «надлежащим способом дублирования», как , показанный в этом примере , и он все еще ведет себя так же.

Так я освобождаю поверхность.

if(shot.at(i).y < 0 - shot.at(i).surface->h)
{
    SDL_FreeSurface(shot.at(i).surface);
    shot.erase(shot.begin() + i);
}

У любого есть идея или пример кода, на который я могу посмотреть, чтобы понять это.

Ответы [ 3 ]

2 голосов
/ 13 ноября 2009

Если несколько снарядов используют один и тот же спрайт (как почти во всех играх на основе спрайтов), вероятно, лучше использовать кэш изображений, содержащий все изображения, используемые в ваших играх, и управлять памятью только там. Заполните его при запуске или по требованию и промойте при выходе. Тогда снарядам просто нужно запросить у этого кеша указатель на «arrow.png», кеш загружает его (при необходимости) и возвращает указатель поверхности.

Такой кеш может быть простым std :: map с такими функциями, как get_surface (string) и flush ().

РЕДАКТИРОВАТЬ: реализация этой идеи:

class image_cache{
    map<string, SDL_Surface*> cache_;
    public:
    SDL_Surface* get_image(string file){
        map<string, SDL_Surface*>::iterator i = cache_.find(file);
        if(i == cache_.end()) {
            SDL_Surface* surf = SDL_LoadBMP(file.c_str());
            i = cache_.insert(i, make_pair(file, surf));
        }
        return i->second;
    } 
    void flush(){
        map<string, SDL_Surface*>::iterator i = cache_.begin();
        for(;i != cache_.end();++i)
            SDL_FreeSurface(i->second);
        cache_.clear();
    }
    ~image_cache() {flush();}
};

image_cache images;
// you can also use specialized caches instead of a global one
image_cache projectiles_images;

int main()
{
    ...
    SDL_Surface* surf = images.get_image("sprite.png");
    ...
}
1 голос
/ 13 ноября 2009

Вы должны освободить поверхность, когда уничтожаете снаряд. Когда вы уничтожаете снаряд, это решение игрового дизайна; вероятно, когда он покидает экран не позднее, но также, конечно, когда (если) он попадает в цель.

0 голосов
/ 13 ноября 2009

Используете ли вы ту же поверхность и в других местах? Потому что если это так, вы не можете освободить его, если он используется где-то еще.

В случае, если вы этого не сделаете: Создайте / загрузите вашу поверхность и освободите конструктор / деструктор снаряда. I.e.:

struct projectile {
    SDL_Surface* surface;

    projectile() : surface(NULL) {
        surface = LoadImage(...);
    }

    ~projectile() {
        if(surface) {
             SDL_FreeSurface(surface);
             surface = NULL;
        }
    }

};
...