SDL_Texture 没有在第二个实例中绘制
SDL_Texture doesn't get drawn in second instance
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 class 是 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 class 也是 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;
}
除了它们的 class 名称和图像文件的路径之外,这两种实现是相同的。这两个文件(test.png(绿色图像)和 player.png(蓝色图像))都存在并且可以成功加载。当我 运行 程序时, player.png 呈现在
启动画面 class。
但是,当我将游戏 class 中的屏幕从 SplashScreen 更改为 MenuScreen 时,会调用所有 MenuScreen 函数,但不会渲染纹理。
SDL_GetError() 没有 return 任何错误,我没有得到任何异常,纹理和渲染器不为空(已经检查)并且我在屏幕上看不到任何东西(它是黑屏)。
如果一切正常,您应该会在屏幕上看到一个彩色方块。
更新:
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;
};
您的代码从不调用 MenuScreen::create
方法,因此您的 SDL_Texture
永远不会创建。
你在评论中说你检查了属性 tex
的值并且它不是空的,但由于它没有在构造函数中初始化,它可能包含一个随机值。
这些是比与您的问题直接相关的更笼统的评论,但就像我在评论中所说的那样,您确实应该更改您的程序架构,因为它有很多固有的错误。例如,当您将屏幕指针切换到 MenuScreen 的指针时,您会泄漏 SplashScreen 对象。
你应该看看一个很好的 C++ 游戏状态引擎,并将启动画面、菜单和任何其他游戏状态作为状态引擎中的状态进行管理。例如,this tutorial 有一个很好的基本状态机实现。
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 class 是 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 class 也是 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;
}
除了它们的 class 名称和图像文件的路径之外,这两种实现是相同的。这两个文件(test.png(绿色图像)和 player.png(蓝色图像))都存在并且可以成功加载。当我 运行 程序时, player.png 呈现在 启动画面 class。 但是,当我将游戏 class 中的屏幕从 SplashScreen 更改为 MenuScreen 时,会调用所有 MenuScreen 函数,但不会渲染纹理。 SDL_GetError() 没有 return 任何错误,我没有得到任何异常,纹理和渲染器不为空(已经检查)并且我在屏幕上看不到任何东西(它是黑屏)。 如果一切正常,您应该会在屏幕上看到一个彩色方块。
更新:
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;
};
您的代码从不调用 MenuScreen::create
方法,因此您的 SDL_Texture
永远不会创建。
你在评论中说你检查了属性 tex
的值并且它不是空的,但由于它没有在构造函数中初始化,它可能包含一个随机值。
这些是比与您的问题直接相关的更笼统的评论,但就像我在评论中所说的那样,您确实应该更改您的程序架构,因为它有很多固有的错误。例如,当您将屏幕指针切换到 MenuScreen 的指针时,您会泄漏 SplashScreen 对象。
你应该看看一个很好的 C++ 游戏状态引擎,并将启动画面、菜单和任何其他游戏状态作为状态引擎中的状态进行管理。例如,this tutorial 有一个很好的基本状态机实现。