我对于试图解决这个问题感到非常沮丧。我一直关注http://lazyfoo.net/tutorials/SDL/index.php。然后我尝试用SDL2开始制作游戏,但很快就遇到了这个错误:我无法向屏幕渲染任何东西。屏幕弹出,我可以正确清除它。如果我调用SDL_GetError(),则输出为“Invalid Renderer”。我检查了代码,试图找出可能导致此错误的位置,并在互联网上搜索无济于事。可能导致问题的是我有一个具有render方法的类。此render方法在其纹理上调用render方法。那可能是我以某种方式搞砸的地方,但我不知道。
源代码:
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <string>
#include <stdio.h>
const int WINDOW_WIDTH = 1280;
const int WINDOW_HEIGHT= 960;
SDL_Window* gWindow = NULL;
SDL_Renderer* gRenderer = NULL;
enum MOVEMENT_STATES
{
DOWN1,
DOWN2,
LEFT1,
LEFT2,
RIGHT1,
RIGHT2,
UP1,
UP2,
MOVEMENT_STATES_TOTAL
};
//Texture wrapper class
class LTexture
{
public:
//Initializes variables
LTexture(std::string path);
//Deallocates memory
~LTexture();
#ifdef _SDL_TTF_H
//Creates image from font string
bool loadFromRenderedText( std::string textureText, SDL_Color textColor );
#endif
//Deallocates texture
void free();
//Set color modulation
void setColor( Uint8 red, Uint8 green, Uint8 blue );
//Set blending
void setBlendMode( SDL_BlendMode blending );
//Set alpha modulation
void setAlpha( Uint8 alpha );
//Renders texture at given point
void render( int x, int y, SDL_Rect* clip = NULL, double angle = 0.0, SDL_Point* center = NULL, SDL_RendererFlip flip = SDL_FLIP_NONE );
//Gets image dimensions
int getWidth();
int getHeight();
private:
//Loads image at specified path
bool loadFromFile( std::string path );
//The actual hardware texture
SDL_Texture* mTexture;
//Image dimensions
int mWidth;
int mHeight;
};
//Sprite classes
class Entity
{
public:
Entity(int hp);
~Entity();
//void handleEntity(); Unimplemented
void render(int x, int y);
int health;
int maxHealth;
LTexture* mCurrentTexture;
};
Entity::Entity(int hp)
{
mCurrentTexture = NULL;
health = hp;
maxHealth = hp;
}
Entity::~Entity()
{
mCurrentTexture = NULL;
}
void Entity::render(int x, int y)
{
//If current texture is non-null, render it
if (mCurrentTexture != NULL)
{
(*mCurrentTexture).render(x, y);
}
else
{
printf("Texture is null!\n");
}
}
LTexture::LTexture(std::string path)
{
//Initialize
mTexture = NULL;
loadFromFile(path);
mWidth = 0;
mHeight = 0;
}
LTexture::~LTexture()
{
//Deallocate
free();
}
bool LTexture::loadFromFile( std::string path )
{
//Get rid of preexisting texture
free();
//The final texture
SDL_Texture* newTexture = NULL;
//Load image at specified path
SDL_Surface* loadedSurface = IMG_Load( path.c_str() );
if( loadedSurface == NULL )
{
printf( "Unable to load image %s! SDL_image Error: %s\n", path.c_str(), IMG_GetError() );
}
else
{
//Color key image
SDL_SetColorKey( loadedSurface, SDL_TRUE, SDL_MapRGB( loadedSurface->format, 0, 0xFF, 0xFF ) );
//Create texture from surface pixels
newTexture = SDL_CreateTextureFromSurface( gRenderer, loadedSurface );
if( newTexture == NULL )
{
printf( "Unable to create texture from %s! SDL Error: %s\n", path.c_str(), SDL_GetError() );
}
else
{
//Get image dimensions
mWidth = loadedSurface->w;
mHeight = loadedSurface->h;
}
//Get rid of old loaded surface
SDL_FreeSurface( loadedSurface );
}
//Return success
mTexture = newTexture;
return mTexture != NULL;
}
#ifdef _SDL_TTF_H
bool LTexture::loadFromRenderedText( std::string textureText, SDL_Color textColor )
{
//Get rid of preexisting texture
free();
//Render text surface
SDL_Surface* textSurface = TTF_RenderText_Solid( gFont, textureText.c_str(), textColor );
if( textSurface != NULL )
{
//Create texture from surface pixels
mTexture = SDL_CreateTextureFromSurface( gRenderer, textSurface );
if( mTexture == NULL )
{
printf( "Unable to create texture from rendered text! SDL Error: %s\n", SDL_GetError() );
}
else
{
//Get image dimensions
mWidth = textSurface->w;
mHeight = textSurface->h;
}
//Get rid of old surface
SDL_FreeSurface( textSurface );
}
else
{
printf( "Unable to render text surface! SDL_ttf Error: %s\n", TTF_GetError() );
}
//Return success
return mTexture != NULL;
}
#endif
void LTexture::free()
{
//Free texture if it exists
if( mTexture != NULL )
{
SDL_DestroyTexture( mTexture );
mTexture = NULL;
mWidth = 0;
mHeight = 0;
}
}
void LTexture::setColor( Uint8 red, Uint8 green, Uint8 blue )
{
//Modulate texture rgb
SDL_SetTextureColorMod( mTexture, red, green, blue );
}
void LTexture::setBlendMode( SDL_BlendMode blending )
{
//Set blending function
SDL_SetTextureBlendMode( mTexture, blending );
}
void LTexture::setAlpha( Uint8 alpha )
{
//Modulate texture alpha
SDL_SetTextureAlphaMod( mTexture, alpha );
}
void LTexture::render( int x, int y, SDL_Rect* clip, double angle, SDL_Point* center, SDL_RendererFlip flip )
{
//Set rendering space and render to screen
SDL_Rect renderQuad = { x, y, mWidth, mHeight };
//Set clip rendering dimensions
if( clip != NULL )
{
renderQuad.w = clip->w;
renderQuad.h = clip->h;
}
//Render to screen
SDL_RenderCopyEx( gRenderer, mTexture, clip, &renderQuad, angle, center, flip );
}
int LTexture::getWidth()
{
return mWidth;
}
int LTexture::getHeight()
{
return mHeight;
}
bool init()
{
bool success = true;
//Initialize SDL
if(SDL_Init(SDL_INIT_VIDEO) < 0)
{
printf("SDL could not initialize! SDL Error: %s\n", SDL_GetError());
success = false;
}
else
{
//Enable VSync
if(!SDL_SetHint(SDL_HINT_RENDER_VSYNC, "1"))
{
printf("Warning: VSync not enabled!");
}
//Set texture filtering to linear
if( !SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "1" ) )
{
printf( "Warning: Linear texture filtering not enabled!" );
}
}
//Create window
gWindow = SDL_CreateWindow("Dungeon Dash", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_SHOWN);
if (gWindow == NULL)
{
printf("SDL could not create window! SDL Error: %s\n", SDL_GetError());
success = false;
}
else
{
//Create renderer for window
gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED);
if (gRenderer == NULL)
{
printf("SDL could not create renderer! SDL Error: %s\n", SDL_GetError());
success = false;
}
else
{
//Initialize renderer color
SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );
//Initialize PNG loading
int imgFlags = IMG_INIT_PNG;
if( !( IMG_Init( imgFlags ) & imgFlags ) )
{
printf( "SDL_image could not initialize! SDL_image Error: %s\n", IMG_GetError() );
success = false;
}
}
}
return success;
}
int main(int argc, char* args[])
{
if(!init())
{
printf("SDL could not initialize!\n");
}
else
{
bool quit = false;
SDL_Event e; //Event handler
//Load all textures
LTexture boltTexture("graphics/bolt.png");
LTexture burst1Texture("graphics/burst1.png");
LTexture burst2Texture("graphics/burst2.png");
LTexture chestTexture("graphics/chest.png");
LTexture coinTexture("graphics/coin.png");
LTexture emptyTileTexture("graphics/emptyTile.png");
LTexture floorTileTexture("graphics/floorTile.png");
LTexture healthPadTexture("graphics/healthPad.png");
LTexture keyTexture("graphics/key.png");
LTexture snakeDown1Texture("graphics/snakeDown1.png");
LTexture snakeDown2Texture("graphics/snakeDown2.png");
LTexture snakeLeft1Texture("graphics/snakeLeft1.png");
LTexture snakeLeft2Texture("graphics/snakeLeft2.png");
LTexture snakeRight1Texture("graphics/snakeRight1.png");
LTexture snakeRight2Texture("graphics/snakeRight2.png");
LTexture snakeUp1Texture("graphics/snakeUp1.png");
LTexture snakeUp2Texture("graphics/snakeUp2.png");
LTexture spiderDown1Texture("graphics/spiderDown1.png");
LTexture spiderDown2Texture("graphics/spiderDown2.png");
LTexture spiderLeft1Texture("graphics/spiderLeft1.png");
LTexture spiderLeft2Texture("graphics/spiderLeft2.png");
LTexture spiderRight1Texture("graphics/spiderRight1.png");
LTexture spiderRight2Texture("graphics/spiderRight2.png");
LTexture spiderUp1Texture("graphics/spiderUp1.png");
LTexture spiderUp2Texture("graphics/spiderUp2.png");
LTexture teleportPadTexture("graphics/teleportPad.png");
LTexture upgradePadTexture("graphics/upgradePad.png");
LTexture wallTileDownTexture("graphics/wallTileDown.png");
LTexture wallTileLeftTexture("graphics/wallTileLeft.png");
LTexture wallTileRightTexture("graphics/wallTileRight.png");
LTexture wallTileUpTexture("graphics/wallTileUp.png");
LTexture wizardDown1Texture("graphics/wizardDown1.png");
LTexture wizardDown2Texture("graphics/wizardDown2.png");
LTexture wizardLeft1Texture("graphics/wizardLeft1.png");
LTexture wizardLeft2Texture("graphics/wizardLeft2.png");
LTexture wizardRight1Texture("graphics/wizardRight1.png");
LTexture wizardRight2Texture("graphics/wizardRight2.png");
LTexture wizardUp1Texture("graphics/wizardUp1.png");
LTexture wizardUp2Texture("graphics/wizardUp2.png");
//Main player
Entity player1(20);
player1.mCurrentTexture = &wizardDown1Texture;
//Main loop
while(!quit)
{
//Event loop
while(SDL_PollEvent(&e) != 0)
{
if(e.type == SDL_QUIT)
{
quit = true;
}
}
//Clear screen
SDL_SetRenderDrawColor(gRenderer, 0, 0, 0, 255);
SDL_RenderClear(gRenderer);
player1.render(0, 0);
//Update screen
SDL_RenderPresent(gRenderer);
}
//If script reaches here, user has exited; quit program
//Free loaded images
boltTexture.free();
burst1Texture.free();
burst2Texture.free();
chestTexture.free();
coinTexture.free();
emptyTileTexture.free();
floorTileTexture.free();
healthPadTexture.free();
keyTexture.free();
snakeDown1Texture.free();
snakeDown2Texture.free();
snakeLeft1Texture.free();
snakeLeft2Texture.free();
snakeRight1Texture.free();
snakeRight2Texture.free();
snakeUp1Texture.free();
snakeUp2Texture.free();
spiderDown1Texture.free();
spiderDown2Texture.free();
spiderLeft1Texture.free();
spiderLeft2Texture.free();
spiderRight1Texture.free();
spiderRight2Texture.free();
spiderUp1Texture.free();
spiderUp2Texture.free();
teleportPadTexture.free();
upgradePadTexture.free();
wallTileDownTexture.free();
wallTileLeftTexture.free();
wallTileRightTexture.free();
wallTileUpTexture.free();
wizardDown1Texture.free();
wizardDown2Texture.free();
wizardLeft1Texture.free();
wizardLeft2Texture.free();
wizardRight1Texture.free();
wizardRight2Texture.free();
wizardUp1Texture.free();
wizardUp2Texture.free();
//Destroy window
SDL_DestroyRenderer( gRenderer );
SDL_DestroyWindow( gWindow );
gWindow = NULL;
gRenderer = NULL;
//Quit SDL subsystems
IMG_Quit();
SDL_Quit();
}
}
提前感谢您的帮助。
答案 0 :(得分:4)
我发现了这个问题,因为我从SDL_GetError得到了同样的错误。这里的答案表明SDL_GetError可能会说&#34;无效的渲染器&#34;在没有错误的情况下提供信息。只有在调用的最后一个SDL函数实际指示错误的情况下,才能依赖SDL_GetError。
但我的情况略有不同。我正在调用SDL_WaitEventTimeout,它返回1表示由于事件而提前返回,或者返回0表示过期计时器或错误,并使用户依赖SDL_GetError来确定是否发生错误。在这种情况下,在调用SDL_WaitEventTimeout之前调用SDL_ClearError至关重要。另外,当没有错误时,SDL_GetError返回一个空字符串,而不是空指针。
int frameRate = 30;
SDL_Event e;
SDL_ClearError();
int ret = SDL_WaitEventTimeout( &e, 1000/frameRate );
if ( ret )
{
// event received, process events
}
else
{
// timeout or error; have to check
const char *s = SDL_GetError();
if ( *s )
{
cout << "SDL_WaitEventTimeout: " << s << endl;
}
else
{
// normal timeout, do normal actions
}
}
这似乎是SDL_WaitEventTimeout设计中的一个缺陷,它在返回值中浪费了大部分空间。它确实应该在它导致错误时返回-1,在它超时时返回0,以及在事件发生时剩余的毫秒数。我怀疑它实际上已被弃用为帧定时器,我不得不依赖SDL_PollEvent来处理事件,并且必须使用OS /硬件本地定时器进行帧同步,这会浪费SDL的可移植性。
答案 1 :(得分:3)
抛出错误的行是创建渲染器的行,但可以忽略该错误(因为它不返回NULL)。 SDL使用宏来检查渲染器是否正常,如果不正常,它会自动设置该错误字符串。它可能过早地进行检查。但这与你的问题无关。
您的问题是因为在LTexture
构造函数中,您调用了loadFromFile()
,它正确地设置了mWidth
和mHeight
。然后再次将它们设置为0,使renderQuad
没有区域,从而使纹理不会渲染。
在此之前将它们设置为0,或者更好的是,在初始化列表中将它们设置为0:
LTexture::LTexture(std::string path)
: mTexture(NULL), mWidth(0), mHeight(0)
{
loadFromFile(path);
}
此外,LTexture
类有一个名为free
的方法,虽然不是保留名称,但可能会导致同事混淆(就像我一样:),你可能会考虑不同名。
答案 2 :(得分:0)
尝试更改传递给SDL_CreateRenderer()的标志。我和你有同样的问题,我最终发现,在我的机器上,SDL在硬件加速渲染方面遇到了麻烦(这恰好是默认设置)。尝试将SDL_RENDERER_ACCELERATED
更改为SDL_RENDERER_SOFTWARE
,看看是否有帮助。
此外,每当您遇到特别棘手的错误时,请尝试解决问题。这里有一个巨大的(用于Stack Overflow)代码量,并且你把它减少到只有渲染位然后(1)其他人可能能够更快地帮助你(2)你可能已经能够自己解决这个问题了。