在处理曲面向量时,如何正确使用SDL_FreeSurface

时间:2021-07-29 02:19:23

I have setup a small shooter game as a tutorial for myself in SDL. I have a struct of a projectile

我在SDL中设置了一个小型射击游戏作为我自己的教程。我有一个抛射物的结构

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

And I put that into a vector.

我把它放到矢量中。

vector<projectile> shot;
projectile one_shot;

And when I press space I create a new projectile and add it to the vector and then they're blitted when they're rendered.

当我按下空格时,我会创建一个新的射弹并将其添加到矢量中,然后在渲染时它们会被渲染。

This works fine, but I'm in seemingly random cases getting a "program has stopped working" error.

这工作正常,但我看似随机的情况下,“程序已停止工作”错误。

So I'm wondering what is the proper way to free the surfaces.

所以我想知道释放表面的正确方法是什么。

  • Do I free them all afterwards?
  • 之后我是否将它们全部释放?
  • Do I free each individual shot when it exits the screen?
  • 退出屏幕时,我是否可以释放每个人的镜头?
  • Or some other choice?
  • 或者其他一些选择?

UPDATE:

更新:

I have found where it crashes when I quit, when I have fired a few shots and they have all exited the screen. I have tried replacing the code that adds the surface to the vector with the "proper way to duplicate" as seen in this example, and it still behaves in the same way.

当我退出时,我已经找到它崩溃的地方,当我开了几枪并且他们都退出了屏幕。我已经尝试用“正确的复制方式”替换将表面添加到向量的代码,如本例所示,它仍然以相同的方式运行。

This is how I free the surface.

这就是我释放表面的方式。

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

Anyone have an idea or some sample code I can look at to figure this out.

任何人都有一个想法或一些示例代码我可以看看来解决这个问题。

3 个解决方案

#1


2  

If several projectiles use the same sprite (as in almost all sprite-based games), it's probably better to use an image cache containing all the images used by your games and do memory management only there. Fill it at start or on demand and flush it when exiting. Then projectiles just need to ask to this cache a pointer to "arrow.png", the cache loads it (if needed) and returns the surface pointer.

如果几个射弹使用相同的精灵(就像几乎所有基于精灵的游戏一样),最好使用包含游戏使用的所有图像的图像缓存,并仅在那里进行内存管理。在开始或按需填充它并在退出时冲洗它。然后抛射物只需要向此缓存询问一个指向“arrow.png”的指针,缓存加载它(如果需要)并返回表面指针。

Such cache can be a simple std::map< string, SDL___Surface* > with just functions like get_surface(string) and flush().

这样的缓存可以是一个简单的std :: map ,只有get_surface(string)和flush()等函数。 ,sdl>

EDIT: an implementation of this idea:

编辑:这个想法的实现:

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");
    ...
}

#2


1  

You should free the surface when you destroy the projectile. When you destroy the projectile is a game design decision; probably when it leaves the screen at the latest, but also of course when (if) it hits a target.

当你摧毁抛射物时,你应该释放表面。当你摧毁弹丸是游戏设计的决定;可能当它最迟离开屏幕时,当然还有(如果)它击中目标时。

#3


0  

Do you use the same surface also elsewhere? Because if so, you cannot free it as long as it is used somewhere else.

你在其他地方也使用相同的表面吗?因为如果是这样的话,只要在其他地方使用它就不能释放它。

In case you don't do that: Make the constructing/loading of your surface and the freeing in the constructor / destructor of projectile. I.e.:

如果你不这样做:在弹丸的构造函数/析构函数中构建/加载曲面和释放。即:

struct projectile {
    SDL_Surface* surface;

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

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

};

#1


2  

If several projectiles use the same sprite (as in almost all sprite-based games), it's probably better to use an image cache containing all the images used by your games and do memory management only there. Fill it at start or on demand and flush it when exiting. Then projectiles just need to ask to this cache a pointer to "arrow.png", the cache loads it (if needed) and returns the surface pointer.

如果几个射弹使用相同的精灵(就像几乎所有基于精灵的游戏一样),最好使用包含游戏使用的所有图像的图像缓存,并仅在那里进行内存管理。在开始或按需填充它并在退出时冲洗它。然后抛射物只需要向此缓存询问一个指向“arrow.png”的指针,缓存加载它(如果需要)并返回表面指针。

Such cache can be a simple std::map< string, SDL___Surface* > with just functions like get_surface(string) and flush().

这样的缓存可以是一个简单的std :: map ,只有get_surface(string)和flush()等函数。 ,sdl>

EDIT: an implementation of this idea:

编辑:这个想法的实现:

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");
    ...
}

#2


1  

You should free the surface when you destroy the projectile. When you destroy the projectile is a game design decision; probably when it leaves the screen at the latest, but also of course when (if) it hits a target.

当你摧毁抛射物时,你应该释放表面。当你摧毁弹丸是游戏设计的决定;可能当它最迟离开屏幕时,当然还有(如果)它击中目标时。

#3


0  

Do you use the same surface also elsewhere? Because if so, you cannot free it as long as it is used somewhere else.

你在其他地方也使用相同的表面吗?因为如果是这样的话,只要在其他地方使用它就不能释放它。

In case you don't do that: Make the constructing/loading of your surface and the freeing in the constructor / destructor of projectile. I.e.:

如果你不这样做:在弹丸的构造函数/析构函数中构建/加载曲面和释放。即:

struct projectile {
    SDL_Surface* surface;

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

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

};