SDL_Texture不会在第二个实例中绘制

时间:2018-04-17 18:40:41

标签: c++ sdl-2

的main.cpp

#include "SDL.h"
#include <cstdio>
#include <iostream>
#include "Game.h"

//Constants
bool isFullscreen = false;
const int SCREEN_WIDTH  = 640;
const int SCREEN_HEIGHT = 480;
const char *GAME_NAME = "Alex's RPG Game | Version 2";

//Game
Game *game = nullptr; //Game is null --> nullpointer


int main(int argc, char* argv[]) {
    //Ignore the arguments

    std::cout << "Starting game" << std::endl;

    game = new Game();

    game->init(GAME_NAME, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_RESIZABLE);

    while (game->isGameRunning()){
        game->handleEvents();
        game->update();
        game->render();
    }

    game->destroy();

    return 0;
}

game.cpp:

Game::Game() {
    isRunning = false;
    screen = new SplashScreen(getGame());
}

Game::~Game() {
    //Empty deconstructor
}

void Game::init(const char *title, int xPos, int yPos, int width, int height, Uint32 flag) {

    if (SDL_Init(SDL_INIT_EVERYTHING) == 0) {

        std::cout << "Subsystems are running..." << std::endl;

        window = SDL_CreateWindow(title, xPos, yPos, width, height, flag);

        if (window) {
            std::cout << "Window created" << std::endl;
        }

        renderer = SDL_CreateRenderer(window, -1, 0);


        if (renderer) {
            //Draw a black background
            SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
            std::cout << "Renderer created" << std::endl;
        }

        screen->create(renderer);

        std::cout << "Game successful initiated" << std::endl;
        isRunning = true;


    } else {
        isRunning = false;
    }

}

void Game::render() {

    SDL_RenderClear(renderer);

    screen->render(renderer);

    SDL_RenderPresent(renderer);
}

void Game::destroy() {
    SDL_DestroyWindow(window);
    SDL_DestroyRenderer(renderer);
    SDL_Quit();
    std::cout << "Game successful destroyed" << std::endl;
}

void Game::update() {
    screen->update();
}

void Game::handleEvents() {

    SDL_PollEvent(&event);
    switch (event.type) {
        case SDL_QUIT:
            isRunning = false;
            break;
        case SDL_KEYDOWN:
            switch (event.key.keysym.sym){
                case SDLK_ESCAPE:
                    isRunning = false;
                    break;
                default:
                    break;
            }
            break;
        default:
            break;
    }

}

bool Game::isGameRunning() {
    return isRunning;
}

void Game::setScreen(IScreen *screen1) {
    screen = screen1;
}

game.h

class Game {
public:
    Game();
    ~Game();

    void init(const char* title, int xPos, int yPos, int width, int height, Uint32 flag);

    void handleEvents();
    void update();
    void render();
    void setScreen(IScreen *screen1);
    void destroy();

    Game* getGame(){
        return this;
    }

    bool isGameRunning();

private:
    bool isRunning;

    //Define a pointer to a window and a renderer
    SDL_Window *window;
    SDL_Renderer *renderer;
    SDL_Event event;

    IScreen *screen;

};

SplashScreen.h

class SplashScreen: public IScreen{
public:

    explicit SplashScreen(Game *game);
    ~SplashScreen();

    void render(SDL_Renderer *renderer) override;
    void update() override;
    void create(SDL_Renderer *renderer) override;

private:
    SDL_Texture *texture;
    SDL_Rect rect;

    Game *game;

    int time = 0;

};

SplashScreen.cpp类是IScreen的实现

SplashScreen::SplashScreen(Game *game1){

    //Constructor
    game = game1;
}

SplashScreen::~SplashScreen(){

    //Deconstructor

}

void SplashScreen::update() {
    // Update the screen

    if(SDL_GetTicks() > 5000 + time){
        game->setScreen(new MenuScreen(game));
    }

}

void SplashScreen::render(SDL_Renderer *renderer) {

    SDL_RenderCopy(renderer, texture, NULL, &rect);

}


void SplashScreen::create(SDL_Renderer *renderer) {

    texture = TextureManager::loadTexture("player.png", renderer);

    rect.x = 50;
    rect.y = 50;
    rect.h = 32;
    rect.w = 32;

    time = SDL_GetTicks();

}

MenuScreen.h

class MenuScreen: public IScreen{
public:

    explicit MenuScreen(Game *game1);
    ~MenuScreen();

    void render(SDL_Renderer *renderer) override;
    void update() override;
    void create(SDL_Renderer *renderer) override;

private:
    SDL_Texture *tex;
    SDL_Rect rect;

    Game *game;

};

MenuScreen.cpp类也是IScreen的实现:

MenuScreen::MenuScreen(Game *game1) {
    game = game1;
}

MenuScreen::~MenuScreen() {

}

void MenuScreen::update() {
    std::cout << "Why can't it render" << std::endl;
}

void MenuScreen::render(SDL_Renderer *renderer) {

    std::cout << "Why can't it render" << std::endl;

    SDL_RenderCopy(renderer, tex, nullptr, &rect);

}

void MenuScreen::create(SDL_Renderer *renderer) {

    tex = TextureManager::loadTexture("test.png", renderer);

    rect.x = 100;
    rect.y = 100;
    rect.h = 32;
    rect.w = 32;

}

除了类名和图像文件的路径之外,两种实现都是相同的。两个文件(test.png(绿色图像)和player.png(蓝色图像))都存在并且可以成功加载。当我运行程序时,player.png呈现在 SplashScreen类。 但是当我将游戏类中的屏幕从SplashScreen更改为MenuScreen时,将调用所有MenuScreen函数,但不会渲染纹理。 SDL_GetError()不会返回任何错误,我没有得到任何异常,纹理和渲染器不为空(已经检查),我在屏幕上看不到任何东西(它是黑屏)。 如果一切正常,你应该在屏幕上看到一个彩色方块。

更新

TextureManager.cpp

SDL_Texture *TextureManager::loadTexture(const char *path, SDL_Renderer *renderer) {

    SDL_Surface* surface = IMG_Load(path);
    SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
    SDL_FreeSurface(surface);
    return texture;
}

IScreen.h

#include "SDL.h"

class IScreen{
public:

    virtual void create(SDL_Renderer *renderer) = 0;

    virtual void render(SDL_Renderer *renderer) = 0;
    virtual void update() = 0;


};

1 个答案:

答案 0 :(得分:0)

您的代码从不调用MenuScreen::create方法,因此永远不会创建SDL_Texture

您在评论中说您检查了属性tex的值并且它不为空,但由于它未在构造函数中初始化,因此它可能包含随机值

这些是与您的问题直接相关的更一般的评论,但正如我在评论中所说,您应该真正改变您的程序架构,因为您有很多固有的错误来自它。例如,当您将屏幕指针切换到MenuScreen的指针时,您会泄漏SplashScreen对象。

你应该看看C ++中的一个好的游戏状态引擎,并将启动屏幕,菜单和任何其他游戏状态作为状态引擎中的状态进行管理。例如,this tutorial具有良好的基本状态机实现。