SDL2 - 从 1.2 迁移到 2.0 后显示 *.bmp 文件时出现问题,程序已构建但运行时出现空白屏幕

问题描述 投票:0回答:1

我一直在关注克里斯托弗·赫伯茨洞穴故事的重建 (他的 GitHub 页面:https://github.com/chebert/cavestory-screencast, 和播放列表 https://www.youtube.com/watch?v=IufkC1IRY2Q&list=PL006xsVEsbKjSKBmLu1clo85yLrwjY67X&index=1&pp=iAQB), 为了在更实际的环境中学习 C++,以及如何为每个函数使用更多的类/标头方法编写简单的游戏,而不是将所有内容写在一个庞大的“main.cpp”文件中。

一切都很顺利,但是这一切都是在 SDL 1.2 中完成的,而不是 2.0 中。现在,在最新版本中从头开始一个新项目后,我尝试在屏幕上显示单个位图文件,可以通过按 Esc 键关闭该文件。它构建得很好,代码如下:

游戏.cpp:

...
void Game::eventLoop(){
    Graphics graphics;
    SDL_Event event;

    sprite_.reset(new Sprite("sprites/tilesets/dirt_tile.bmp", 0, 0, 128, 128));

    bool running = true;
    while(running){

        const int start_time_ms = SDL_GetTicks();
        while (SDL_PollEvent(&event) ){
            switch (event.type){
            case SDL_KEYDOWN:
                if (event.key.keysym.scancode == SDL_SCANCODE_ESCAPE)
                    running = false;
                break;
            default:
                break;
            }
        }

        update();
        draw(graphics);

        const int ms_per_frame = 1000 / kFPS;
        const int elapsed_time_ms = SDL_GetTicks() - start_time_ms;

        if(elapsed_time_ms < ms_per_frame){
            SDL_Delay(ms_per_frame - elapsed_time_ms);
        }
    }
}

...

void Game::draw(Graphics& graphics){

    sprite_->draw(graphics, 400, 300);
    graphics.flip();
}

图形.h:

struct SDL_Surface;
struct SDL_Rect;


struct Graphics{
    typedef SDL_Texture* SurfaceID;

    Graphics();
    ~Graphics();

    void blitSurface(SurfaceID source, SDL_Rect* source_rectangle, SDL_Rect* destination_rectangle);
    void flip();

    private:
        SDL_Window* window_;
        SDL_Renderer* renderer_;
};

#endif // GRAPHICS_H

图形.cpp:

...
Graphics::Graphics(){

    window_ =   SDL_CreateWindow("Swordguy",
                                 SDL_WINDOWPOS_UNDEFINED,
                                 SDL_WINDOWPOS_UNDEFINED,
                                 kScreenWidth, kScreenHeight, 0);
    renderer_ = SDL_CreateRenderer(window_, -1, 0);

}


Graphics::~Graphics(){

    SDL_DestroyWindow(window_);
    SDL_DestroyRenderer(renderer_);

}


void Graphics::blitSurface(SurfaceID source, SDL_Rect* source_rectangle, SDL_Rect* destination_rectangle){

    SDL_RenderCopy(renderer_, source, source_rectangle, destination_rectangle);
}


void Graphics::flip(){

    SDL_RenderPresent(renderer_);
}

sprite.h:

struct Graphics;

struct Sprite{

    Sprite(const std::string& file_path,
           int source_x, int source_y,
           int width, int height);

    // ~Sprite();

    void draw(Graphics& graphics, int x, int y);

    private:
        SDL_Rect source_rect_;
        SDL_Texture* sprite_sheet_;
};

#endif // SPRITE_H

精灵.cpp:

Sprite::Sprite(const std::string& file_path,
               int source_x, int source_y,
               int width, int height){

    SDL_Surface* sprite_sheet_ = SDL_LoadBMP(file_path.c_str() );
    source_rect_.x = source_x;
    source_rect_.y = source_y;
    source_rect_.w = width;
    source_rect_.h = height;

}


/*
Sprite::~Sprite(){

    SDL_FreeSurface(sprite_sheet_);
}
*/


void Sprite::draw(Graphics& graphics, int x, int y){

    SDL_Rect destination_rectangle;
    destination_rectangle.x = x;
    destination_rectangle.y = y;
    graphics.blitSurface(sprite_sheet_, &source_rect_, &destination_rectangle);

}

之后,程序以某种方式构建并运行,但屏幕完全空白。

在此处输入问题之前我所做的事情:

  • https://wiki.libsdl.org/SDL2/MigrationGuide检查了SDL2/迁移指南,并在graphics.cpp中添加了单独的窗口和渲染器函数,以及析构函数中的橡皮擦,

  • 在第 9 行的 sprite.cpp 中添加了 SDL_Surface*,因为没有它,SDL_Surface.h 不会将其转换为 SDL_Texture*,

  • 在第 18 行关闭了 sprite.cpp 中释放表面的析构函数,只是为了检查程序,因为它无法将 SDL_Texture* 转换为 SDL_Surface*,

  • 检查 *.bmp 文件是否正常,它是从 Lazy Foo 的代码中正确加载的:https://lazyfoo.net/tutorials/SDL/02_getting_an_image_on_the_screen/index.php。文件本身也是一个适当的 24 位 *.bmp 文件,

感觉解决方案真的很简单,但我只是不知道该怎么办了。有什么帮助或提示吗?

c++ bitmap game-development sdl-2
1个回答
-2
投票

问题似乎在于从 SDL 1.2 迁移到 SDL 2.0,特别是在处理 SDL 2.0 中的渲染和纹理系统时。让我们分解一下问题,看看如何解决:

  1. SDL_Texture 与 SDL_Surface: 在 SDL2 中,渲染到屏幕涉及使用 SDL 渲染器的

    SDL_Texture
    ,而不是 SDL 1.2 中使用的 SDL_Surface。您的代码尝试将
    SDL_Surface
    用作
    SDL_Texture
    ,这是行不通的。

  2. 加载BMP作为纹理: 在 Sprite 类中,您将 BMP 加载到 SDL_Surface 中,但没有将此表面转换为 SDL2 用于渲染的 SDL_Texture。

让我们尝试解决这些问题:

  1. 将 SDL_Surface 转换为 SDL_Texture:

    修改

    Sprite
    中的
    sprite.cpp
    构造函数,将加载的BMP表面转换为SDL_Texture:

    Sprite::Sprite(const std::string& file_path,
                   int source_x, int source_y,
                   int width, int height) {
    
        SDL_Surface* loadedSurface = SDL_LoadBMP(file_path.c_str());
        if (loadedSurface == nullptr) {
            // Handle error
            return;
        }
    
        // Convert the surface to a texture
        sprite_sheet_ = SDL_CreateTextureFromSurface(graphics.renderer_, loadedSurface);
    
        // Free the loaded surface now that we have a texture
        SDL_FreeSurface(loadedSurface);
    
        source_rect_.x = source_x;
        source_rect_.y = source_y;
        source_rect_.w = width;
        source_rect_.h = height;
    }
    

    请注意,Graphics 类应该提供一个方法或直接访问渲染器,例如,

    graphics.renderer_
    ,用于此转换。

  2. 清除渲染器:

    在使用渲染器绘制到屏幕之前,最好先清除渲染器:

    void Graphics::flip(){
        SDL_RenderClear(renderer_);   // Clear the renderer
        SDL_RenderPresent(renderer_);
    }
    
  3. 检查BMP路径和错误处理

    确保 BMP 文件的路径正确并且相对于可执行文件或工作目录存在。此外,您可以使用 SDL_GetError() 打印和检查与 SDL 函数相关的任何错误:

    SDL_Surface* loadedSurface = SDL_LoadBMP(file_path.c_str());
    if (loadedSurface == nullptr) {
        std::cerr << "Unable to load BMP: " << SDL_GetError() << std::endl;
        return;
    }
    

进行这些更改后,重新编译并运行您的代码。 BMP 应正确显示在屏幕上。请记住,在 SDL 2.0 中,使用

SDL_Texture
和渲染 API 提供硬件加速,与 SDL 1.2 中基于表面的方法相比,这将更加高效。

© www.soinside.com 2019 - 2024. All rights reserved.