使用SDL无法绘制多个精灵对象?技术问题求助
问题根源
你的代码核心问题在于**GameObject类使用了默认的拷贝构造函数和赋值运算符**,导致对象拷贝时执行浅拷贝:多个GameObject实例会共享同一个SDL_Texture*指针。当你把TestObj1、TestObj2推入vector时,vector中存储的是原对象的浅拷贝,这些拷贝对象和原对象共用同一块纹理内存。
虽然在循环执行期间原对象还未销毁,但这种设计存在两个致命问题:
- 程序结束时,原对象和
vector中的拷贝对象都会调用析构函数销毁同一个纹理,触发双重释放(可能导致崩溃); - 若
vector发生扩容(比如后续添加更多对象),旧的拷贝对象会被销毁,连带销毁纹理,导致剩余对象的纹理指针失效。
这就是你只能看到最后一个对象的原因——前面的对象纹理已经被提前销毁,无法正常渲染。
修复方案
推荐使用智能指针存储对象的方案,彻底避免拷贝问题,同时保证资源安全管理:
步骤1:修改GameObject类,禁用拷贝语义
在类中显式禁用拷贝构造和赋值运算符,避免意外的浅拷贝:
#include <iostream> #include <cmath> #include <cstdlib> #include <ctime> #include <vector> #include <memory> // 新增:包含智能指针头文件 #include <SDL.h> #include <SDL_image.h> using namespace std; class GameObject { private: SDL_Texture* texture; // 精灵纹理 SDL_Rect rect; // 位置与尺寸 SDL_Renderer* renderer;// 渲染器指针 public: GameObject(SDL_Renderer* renderer, const char* filepath, int x, int y) : texture(nullptr), renderer(renderer) { rect.x = x; rect.y = y; // 新增错误检查 SDL_Surface* surface = IMG_Load(filepath); if (!surface) { cout << "加载图片失败: " << IMG_GetError() << endl; return; } texture = SDL_CreateTextureFromSurface(renderer, surface); if (!texture) { cout << "创建纹理失败: " << SDL_GetError() << endl; } SDL_FreeSurface(surface); if (texture) { SDL_QueryTexture(texture, nullptr, nullptr, &rect.w, &rect.h); } } ~GameObject() { if (texture) { SDL_DestroyTexture(texture); } } // 禁用拷贝构造和赋值运算符 GameObject(const GameObject&) = delete; GameObject& operator=(const GameObject&) = delete; // 允许移动构造(可选,不影响当前场景) GameObject(GameObject&&) = default; GameObject& operator=(GameObject&&) = default; void draw() { if (texture) { SDL_RenderCopy(renderer, texture, nullptr, &rect); } } };
步骤2:修改main函数,使用智能指针容器
把vector<GameObject>改为vector<unique_ptr<GameObject>>,直接存储对象的唯一指针,避免拷贝:
int main(int, char**) { const short FPS = 60; const int frameDelay = 1000 / FPS; Uint32 frameStart; int frameTime; SDL_Init(SDL_INIT_EVERYTHING); SDL_Window* window = SDL_CreateWindow("title", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 960, SDL_WINDOW_SHOWN); SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, 0); // 修改为智能指针容器 vector<unique_ptr<GameObject>> gameObjects; // 直接在容器中创建对象,避免拷贝 gameObjects.push_back(make_unique<GameObject>(renderer, "assets//test.png", 10, 20)); gameObjects.push_back(make_unique<GameObject>(renderer, "assets//test.png", 80, 20)); bool quit = false; while (!quit) { frameStart = SDL_GetTicks(); SDL_Event ev; while (SDL_PollEvent(&ev)) { switch (ev.type) { case SDL_QUIT: quit = true; break; } } SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); SDL_RenderClear(renderer); // 遍历智能指针容器,调用draw方法 for (auto& gameObject : gameObjects) { gameObject->draw(); } SDL_RenderPresent(renderer); frameTime = SDL_GetTicks() - frameStart; if (frameDelay > frameTime) { SDL_Delay(frameDelay - frameTime); } } return 0; }
额外说明
如果坚持要使用值语义存储对象(不推荐,会重复加载纹理浪费资源),可以实现深拷贝构造函数:在拷贝时重新加载纹理文件,保证每个对象持有独立的纹理。但这种方式会增加内存开销和加载时间,不如智能指针方案高效。
内容的提问来源于stack exchange,提问作者Michael Scott
相关产品推荐
相关产品推荐

