游戏开发者笔记--对象池

对象池

对象池也是我们在游戏开发中,可能会经常用到的组件,他能避免你在游戏中经常的创建和销毁对象,提升了游戏的性能,也避免了内存碎片的产生。

主要的应用场景就是有大量的同类型对象需要构造和销毁,此时可以采用对象池,将用不到的对象隐藏起来,等到需要进行使用时,再进行申请。

对象池的主要作用

当涉及到频繁创建和销毁对象的情况时,对象池是一种常用的设计模式,它具有以下优势和用途:

  1. 提高性能:对象的创建和销毁是一项开销较大的操作,特别是在游戏开发等需要高性能的领域。通过使用对象池,可以避免频繁的内存分配和释放,从而提高程序的性能。对象池在初始化阶段创建一定数量的对象,并在需要时重复使用这些对象,减少了频繁的动态内存分配,提高了执行效率。

  2. 减少内存碎片:频繁的内存分配和释放容易导致内存碎片化问题。对象池通过预先分配一块连续的内存空间来存储对象,避免了内存碎片的产生,提高了内存的利用率。

  3. 控制对象的生命周期:对象池可以控制对象的生命周期,确保对象在使用完毕后可以被重复利用。这对于需要反复使用相同类型的对象的场景非常有用,比如游戏中的子弹、敌人、粒子效果等。

  4. 管理对象的数量:通过对象池,可以限制对象的数量,避免出现过多的对象导致内存消耗过大。当对象池中的对象不够用时,可以选择等待其他对象释放或者动态增加对象的数量,以满足需求。

  5. 避免资源竞争:在多线程环境下,对象池可以提供线程安全的机制,避免多个线程同时创建和销毁对象时的资源竞争问题。

总之,对象池是一种有效的管理和复用对象的方法,可以提高程序的性能和资源利用率。它适用于需要频繁创建和销毁对象的场景,并且对于对象的生命周期、内存管理和性能优化有较高的要求。

举一个例子:

在一个射击游戏中,假设有一把枪,他有30发子弹,每当击发一个弹匣,这时我们肯定会把子弹封装成一个类,但是我们击发30发子弹,势必要创建30个子弹对象,这30个子弹击中物体,势必要销毁这30个子弹对象,如果我们子弹的类比较复杂,势必会造成短时间大量对象创建和销毁,这时我们就会造成系统资源的浪费,而且频繁的创建和销毁对象,势必会出现内存泄漏的情况,而且如果我们子弹因为别的问题没有被成功的销毁。可能会使得大量的子弹对象出现在游戏中,会造成游戏的卡顿。

如何实现?
#include <iostream>
#include <vector>
​
class GameObject {
public:
    GameObject(int id) : id(id) {}
​
    void Update() {
        std::cout << "Updating object " << id << std::endl;
    }
​
private:
    int id;
};
​
class ObjectPool {
public:
    ObjectPool(int size) {
        for (int i = 0; i < size; ++i) {
            GameObject* obj = new GameObject(i);
            pool.push_back(obj);
        }
    }
​
    ~ObjectPool() {
        for (GameObject* obj : pool) {
            delete obj;
        }
    }
​
    GameObject* GetObject() {
        if (pool.empty()) {
            std::cout << "No available objects in the pool." << std::endl;
            return nullptr;
        }
​
        GameObject* obj = pool.back();
        pool.pop_back();
        return obj;
    }
​
    void ReleaseObject(GameObject* obj) {
        pool.push_back(obj);
    }
​
private:
    std::vector<GameObject*> pool;
};
​
int main() {
    ObjectPool pool(5);
​
    GameObject* obj1 = pool.GetObject();
    GameObject* obj2 = pool.GetObject();
    GameObject* obj3 = pool.GetObject();
​
    obj1->Update();
    obj2->Update();
    obj3->Update();
​
    pool.ReleaseObject(obj2);
​
    GameObject* obj4 = pool.GetObject();
    GameObject* obj5 = pool.GetObject();
​
    obj4->Update();
    obj5->Update();
​
    delete obj1;
    delete obj3;
    delete obj4;
    delete obj5;
​
    return 0;
}

在这个示例中,我们有一个 GameObject 类来表示游戏对象。ObjectPool 类则是对象池的实现。在 ObjectPool 的构造函数中,我们创建了一定数量的游戏对象,并将它们存储在一个 std::vector 容器中。GetObject 函数从对象池中获取一个可用的对象,并返回它的指针。ReleaseObject 函数用于释放一个对象,并将其放回对象池。

main 函数中,我们展示了如何使用对象池。我们首先创建一个对象池,并从中获取几个对象。然后,我们调用对象的 Update 函数来模拟对游戏对象进行操作。接着,我们释放了一个对象,并再次获取两个新的对象。

请注意,在使用完对象后,我们需要手动调用 delete 来释放内存,因为对象池只负责对象的管理,而不负责对象的销毁。

猜你喜欢

转载自blog.csdn.net/asdasd121312dasd/article/details/132642678