I'm attempting to create a replica of space invaders using SDL2 and C++, and I've encountered a very weird problem when attempting to put my alien invaders in a vector and render them in the main loop. This is my code:
//sdlUtilsLib.hpp
class Sprite {
public:
Sprite(SDL_Texture* texture);
Sprite(const Sprite& other);
~Sprite();
Sprite& operator=(const Sprite&) = default;
void setPosition(int x, int y);
void move(int x, int y);
int getPositionX() const;
int getPositionY() const;
void draw(SDL_Renderer* renderer) const;
private:
SDL_Texture* m_texture;
SDL_Rect m_targetArea;
};
class WindowManager {
public:
WindowManager() = delete;
WindowManager(int width, int height);
~WindowManager();
bool update();
Sprite createSprite(const std::string& filename);
void drawSprite(const Sprite& sprite);
SDL_Renderer* m_renderer;
private:
SDL_Window* m_window;
};
And the relevant parts of the definitions:
//sdlUtilsLib.cpp
Sprite::Sprite(SDL_Texture* texture)
: m_texture(texture)
{
m_targetArea.x = 0;
m_targetArea.y = 0;
SDL_QueryTexture(texture, NULL, NULL, &(m_targetArea.w), &(m_targetArea.h));
}
Sprite::Sprite(const Sprite& other)
: m_texture(other.m_texture)
{
m_targetArea.x = other.m_targetArea.x;
m_targetArea.y = other.m_targetArea.y;
m_targetArea.w = other.m_targetArea.w;
m_targetArea.h = other.m_targetArea.h;
}
Sprite::~Sprite() {
SDL_DestroyTexture(m_texture);
}
void Sprite::draw(SDL_Renderer* renderer) const {
SDL_RenderCopy(renderer, m_texture, NULL, &m_targetArea);
}
// WindowManager
WindowManager::WindowManager(int width, int height) {
if(SDL_Init(SDL_INIT_EVERYTHING) < 0) {
SDL_Log("SDL failed the initialization: %s\n", SDL_GetError());
}
//Create window
m_window = SDL_CreateWindow("Space Invaders", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height,
SDL_WINDOW_SHOWN);
if(m_window == NULL) {
SDL_Log("Window could not be created! SDL_Error: %s\n", SDL_GetError());
}
//Create renderer for window
m_renderer = SDL_CreateRenderer(m_window, -1, SDL_RENDERER_ACCELERATED);
if(m_renderer == NULL) {
SDL_Log("Renderer could not be created! SDL Error: %s\n", SDL_GetError());
}
//Initialize renderer color
SDL_SetRenderDrawColor(m_renderer, 0xFF, 0xFF, 0xFF, 0xFF);
}
WindowManager::~WindowManager() {
SDL_DestroyRenderer(m_renderer);
SDL_DestroyWindow(m_window);
SDL_Quit();
}
bool WindowManager::update() {
SDL_PumpEvents();
SDL_RenderPresent(m_renderer);
SDL_RenderClear(m_renderer);
return true;
}
Sprite WindowManager::createSprite(const std::string& filename) {
SDL_Surface* surface = SDL_LoadBMP(filename.data());
if(surface == NULL) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to load image %s! SDL_image Error: %s\n",
filename, SDL_GetError());
return NULL;
}
SDL_Texture* texture = SDL_CreateTextureFromSurface(m_renderer, surface);
SDL_FreeSurface(surface);
if(texture == NULL) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create texture from %s! SDL Error: %s\n",
filename, SDL_GetError());
return NULL;
}
return Sprite(texture);
}
void WindowManager::drawSprite(const Sprite& sprite) {
sprite.draw(m_renderer);
}
And this is the main.cpp file:
int main(int argc, char* argv[]) {
WindowManager windowManager { 800, 640 };
bool isRunning { true };
constexpr std::chrono::duration<int64_t, std::nano> nsPerUpdate { std::chrono::nanoseconds(16666667) };
Clock timer;
Sprite sprite = windowManager.createSprite("/home/jooster/Programming/space_invaders/res/enemy_0.bmp");
Sprite al(sprite);
al.move(15, 15);
//std::array<Sprite, 2> aliens = {Sprite(sprite), al};
std::vector<Sprite> aliens = {Sprite(sprite), al};
while(isRunning) {
const float deltaTime = timer.restartAsSeconds().count();
/*for(Sprite& alien : aliens) {
alien.move(1, 1);
std::cout << "Drawing alien " << alien.getPositionX() << ":" << alien.getPositionY() << '\n';
windowManager.drawSprite(alien);
}*/
for(int i=0; i<2; ++i) {
windowManager.drawSprite(aliens[i]);
}
//Clear and draw the window.
windowManager.update();
if(Input::QUIT) { isRunning = false; }
const auto sleepTime = nsPerUpdate - timer.get();
//std::cout << sleepTime.count() << '\n';
if(sleepTime.count() < 0) {
std::cout << "Too long sleep" << '\n';
continue;
}
std::this_thread::sleep_for(sleepTime);
}
return 0;
}
Either of the two for-loops with calls to WindowManager::drawSprite works for the std::array (or with a C-style array), but if I just switch from the std::array to the std:vector, the rendering stops working, in either loop. Interestingly enough, the calls to Sprite::move and std::cout in the range-based for loop works for the std::vector, and outputs exactly what I would expect, at every iteration, it's just the draw-call that doesn't work.
From what I can see on cppreference.com, operator[] should return a reference or a const reference for both the array and the vector, i.e. they should behave identically in this simple case. What am I missing?
Thanks for any help :)
Aucun commentaire:
Enregistrer un commentaire