I want to create my first game.
Nothing special, just blue rectangle moving when WSAD keys are pressed.
The problem is that when I run my game, there are bugs with rectangle(See image below). Bugs appears only during horizontal movement, and not vertical.
Which is interesting, when I changed line:
renderer = SDL_CreateRenderer(display, -1, SDL_RENDERER_ACCELERATED)
to:
renderer = SDL_CreateRenderer(display, -1, SDL_RENDERER_SOFTWARE)
everything is OK
I am using Windows 10, MinGw with CMake(C++14), and SDL 2.0.8, Intel core i5 7th gen, Radeon M7 R465
Im my code OnRender function is responsible for rendering, maybe I made something wrong in it?(Function in my code posted at end of question)
I am also using SDL_WINDOW_OPENGL flag to create my window, but changing it to SDL_WINDOW_SHOWN doesn't change anything.
#include <SDL2/SDL.h>
class Game
{
private:
SDL_Surface *display_surf = nullptr;
SDL_Renderer *renderer = nullptr;
SDL_Window *display = nullptr;
private:
bool running, prW = false, prS = false, prD = false, prA = false;
int x, y;
int spd_y, spd_x;
int scr_w, scr_h;
public:
Game();
int OnExecute();
public:
bool OnInit();
void OnEvent( SDL_Event *event );
void OnLoop();
void OnRender();
void OnCleanup();
};
Game::Game()
{
running = false;
}
int Game::OnExecute()
{
if( !OnInit() )
{
return -1;
}
running = true;
SDL_Event event;
while( running )
{
while( SDL_PollEvent( &event ) )
{
OnEvent( &event );
}
OnLoop();
OnRender();
SDL_Delay( 1 );
}
OnCleanup();
return 0;
}
bool Game::OnInit()
{
if( SDL_Init( SDL_INIT_EVERYTHING ) < 0 )
{
return false;
}
SDL_DisplayMode dspm;
if( SDL_GetDesktopDisplayMode( 0, &dspm ) < 0 )
{
return false;
}
scr_h = dspm.h;
scr_w = dspm.w;
if( ( display = SDL_CreateWindow( "Game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1920, 1080,
SDL_WINDOW_OPENGL ) ) == nullptr )
{
return false;
}
display_surf = SDL_GetWindowSurface( display );
if( ( renderer = SDL_CreateRenderer( display, -1, SDL_RENDERER_ACCELERATED ) ) == nullptr )
{
return false;
}
x = 0;
y = 0;
spd_x = 0;
spd_y = 0;
SDL_SetWindowFullscreen( display, SDL_WINDOW_FULLSCREEN );
return true;
}
void Game::OnEvent( SDL_Event *event )
{
if( event->type == SDL_QUIT )
{
running = false;
return;
}
switch( event->type )
{
case SDL_KEYDOWN:
switch( event->key.keysym.sym )
{
case SDLK_w:
if( prS )
{
spd_y = 0;
}
else
{
spd_y = -5;
}
prW = true;
break;
case SDLK_s:
if( prW )
{
spd_y = 0;
}
else
{
spd_y = 5;
}
prS = true;
break;
case SDLK_d:
if( prA )
{
spd_x = 0;
}
else
{
spd_x = 5;
}
prD = true;
break;
case SDLK_a:
if( prD )
{
spd_x = 0;
}
else
{
spd_x = -5;
}
prA = true;
break;
default:
return;
}
break;
case SDL_KEYUP:
switch( event->key.keysym.sym )
{
case SDLK_w:
if( !prS )
{
spd_y = 0;
}
else
{
spd_y = 5;
}
prW = false;
break;
case SDLK_s:
if( !prW )
{
spd_y = 0;
}
else
{
spd_y = -5;
}
prS = false;
break;
case SDLK_a:
if( !prD )
{
spd_x = 0;
}
else
{
spd_x = 5;
}
prA = false;
break;
case SDLK_d:
if( !prA )
{
spd_x = 0;
}
else
{
spd_x = -5;
}
prD = false;
break;
default:
return;
}
default:
return;
}
}
void Game::OnLoop()
{
x += spd_x;
y += spd_y;
if( x < 0 )
{
x = 0;
}
else if( x > scr_w - 100 )
{
x = scr_w - 100;
}
if( y < 0 )
{
y = 0;
}
else if( y > scr_h - 100 )
{
y = scr_h - 100;
}
}
void Game::OnRender()
{
SDL_SetRenderDrawColor( renderer, 0, 0, 0, 0x00 );
SDL_RenderClear( renderer );
SDL_Rect charc;
charc.x = x;
charc.y = y;
charc.w = 100;
charc.h = 100;
SDL_SetRenderDrawColor( renderer, 0, 0, 0xff, 0 );
SDL_RenderFillRect( renderer, &charc );
SDL_RenderPresent( renderer );
}
void Game::OnCleanup()
{
SDL_DestroyWindow( display );
SDL_Quit();
}
int main( int argc, char** argv )
{
Game game;
return game.OnExecute();
}
Looks a lot like tearing caused by a high frame-rate & lack of vsync.
I can get tear-less drawing by passing SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC to flags on SDL_CreateRenderer():
#include <SDL2/SDL.h>
#include <iostream>
class Game
{
private:
SDL_Renderer *renderer = nullptr;
SDL_Window *display = nullptr;
private:
bool running, prW = false, prS = false, prD = false, prA = false;
int x, y;
int spd_y, spd_x;
int scr_w, scr_h;
public:
Game();
int OnExecute();
public:
bool OnInit();
void OnEvent( SDL_Event *event );
void OnLoop();
void OnRender();
void OnCleanup();
};
Game::Game()
{
running = false;
}
int Game::OnExecute()
{
if( !OnInit() )
{
return -1;
}
running = true;
SDL_Event event;
Uint32 beg = SDL_GetTicks();
size_t frames = 0;
while( running )
{
while( SDL_PollEvent( &event ) )
{
OnEvent( &event );
}
OnLoop();
OnRender();
frames++;
Uint32 end = SDL_GetTicks();
if( end - beg > 1000 )
{
std::cout << "Frame time: " << ( end - beg ) / frames << " ms" << std::endl;
beg = end;
frames = 0;
}
}
OnCleanup();
return 0;
}
bool Game::OnInit()
{
if( SDL_Init( SDL_INIT_EVERYTHING ) < 0 )
{
return false;
}
if( ( display = SDL_CreateWindow( "Game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, 0 ) ) == nullptr )
{
return false;
}
scr_w = 1280;
scr_h = 720;
Uint32 rflags = SDL_RENDERER_ACCELERATED;
rflags |= SDL_RENDERER_PRESENTVSYNC;
if( ( renderer = SDL_CreateRenderer( display, -1, rflags ) ) == nullptr )
{
return false;
}
x = 0;
y = 0;
spd_x = 0;
spd_y = 0;
return true;
}
void Game::OnEvent( SDL_Event *event )
{
if( event->type == SDL_QUIT )
{
running = false;
return;
}
switch( event->type )
{
case SDL_KEYDOWN:
switch( event->key.keysym.sym )
{
case SDLK_w:
if( prS )
{
spd_y = 0;
}
else
{
spd_y = -5;
}
prW = true;
break;
case SDLK_s:
if( prW )
{
spd_y = 0;
}
else
{
spd_y = 5;
}
prS = true;
break;
case SDLK_d:
if( prA )
{
spd_x = 0;
}
else
{
spd_x = 5;
}
prD = true;
break;
case SDLK_a:
if( prD )
{
spd_x = 0;
}
else
{
spd_x = -5;
}
prA = true;
break;
default:
return;
}
break;
case SDL_KEYUP:
switch( event->key.keysym.sym )
{
case SDLK_w:
if( !prS )
{
spd_y = 0;
}
else
{
spd_y = 5;
}
prW = false;
break;
case SDLK_s:
if( !prW )
{
spd_y = 0;
}
else
{
spd_y = -5;
}
prS = false;
break;
case SDLK_a:
if( !prD )
{
spd_x = 0;
}
else
{
spd_x = 5;
}
prA = false;
break;
case SDLK_d:
if( !prA )
{
spd_x = 0;
}
else
{
spd_x = -5;
}
prD = false;
break;
default:
return;
}
default:
return;
}
}
void Game::OnLoop()
{
x += spd_x;
y += spd_y;
if( x < 0 )
{
x = 0;
}
else if( x > scr_w - 100 )
{
x = scr_w - 100;
}
if( y < 0 )
{
y = 0;
}
else if( y > scr_h - 100 )
{
y = scr_h - 100;
}
}
void Game::OnRender()
{
SDL_SetRenderDrawColor( renderer, 0, 0, 0, 0x00 );
SDL_RenderClear( renderer );
SDL_Rect charc;
charc.x = x;
charc.y = y;
charc.w = 100;
charc.h = 100;
SDL_SetRenderDrawColor( renderer, 0, 0, 0xff, 0 );
SDL_RenderFillRect( renderer, &charc );
SDL_Delay( 1 );
SDL_RenderPresent( renderer );
}
void Game::OnCleanup()
{
SDL_DestroyWindow( display );
SDL_Quit();
}
int main( int argc, char** argv )
{
Game game;
return game.OnExecute();
}
If I just pass SDL_RENDERER_ACCELERATED I get tearing and a vastly higher frame-rate.
Make sure your OS isn't configured to disable vsync by default.
Many developers seem to get some unwanted behaviours when enabling SDL_RENDERER_ACCELERATED flag on SDL 2.0.8.
A ticket has been opened in libsdl's bugzilla (https://bugzilla.libsdl.org/show_bug.cgi?id=4110). It's about another problem but issue with hardware rendering is mentioned in description.
For now, I use software rendering (SDL_RENDERER_SOFTWARE) as a fallback. Not really what I wanted to do but now I get the expected result.
I'll try PREVENTSYNC...
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 15 hours ago.
Improve this question
I am making a Cpp sdl game which launches as it should and is playable but only for about 7 second as after that the screen goes black. If I keep the game running with black screen it eventually shows LLVM ERROR: out of memory. While using local windows debugger in Visual Studio I get:
Exception thrown at 0x71002A85 (SDL2_ttf.dll) in game.exe: 0xC0000005: Access violation reading location 0x00000000
and/or
Unhandled exception at 0x7A6C3ED8 (nvoglv32.dll) in game.exe: Fatal program exit requested
Not sure if this information is of any use but changing SDL_Delay() from 1 to higher value e.g. 100, extends the amount of time it takes before the screen goes black. Also changing the SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED) from '-1' to '1' extends the time it takes for the game to go black screen.
I tried different versions of SDL libraries and I don't think its a hardware issue. I used Visual Studio performance profiler and the CPU and GPU usage was normal. Performance profiler did show a 1.8 GB for process memory which did seem quite high, perhaps it's because of inefficient code(?).
I included some of the code and a snapshot.
main.cpp:
int main(int argc, char **argv)
{
/* initialize SDL */
if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )
{
assert(0 && "Failed to initialize video!");
exit(-1);
}
SDL_Window* window = SDL_CreateWindow("Pacman", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1024, 768, SDL_WINDOW_OPENGL);
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); //changing from -1 to 1 increase the amout of time the app runs before black screen
if(!window)
{
assert(0 && "Failed to create window!");
exit(-1);
}
IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG);
if (TTF_Init() == -1)
{
assert(0 && "Failed to create ttf!");
exit(-1);
}
Drawer* drawer = Drawer::Create(window, renderer);
Pacman* pacman = Pacman::Create(drawer);
float lastFrame = (float) SDL_GetTicks() * 0.001f;
SDL_Event event;
while (SDL_PollEvent(&event) >= 0)
{
float currentFrame = (float) SDL_GetTicks() * 0.001f;
float elapsedTime = currentFrame - lastFrame;
if (!pacman->Update(elapsedTime))
break;
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
pacman->Draw();
lastFrame = currentFrame;
SDL_RenderPresent(renderer);
SDL_Delay(1);
}
delete pacman;
delete drawer;
TTF_Quit();
IMG_Quit();
SDL_Quit( );
return 0;
}
Drawer.cpp:
Drawer* Drawer::Create(SDL_Window* aWindow, SDL_Renderer* aRenderer)
{
Drawer* drawer = new Drawer(aWindow, aRenderer);
if (!drawer->Init())
{
delete drawer;
drawer = NULL;
}
return drawer;
}
Drawer::Drawer(SDL_Window* aWindow, SDL_Renderer* aRenderer)
: myWindow(aWindow)
, myRenderer(aRenderer)
, world()
{
}
Drawer::~Drawer(void)
{
}
bool Drawer::Init()
{
if (!myWindow)
return false;
return true;
}
void Drawer::Draw(const char* anImage, int aCellX, int aCellY)
{
SDL_Surface* surface = IMG_Load( anImage ) ;
if (!surface)
return;
SDL_Texture* optimizedSurface = SDL_CreateTextureFromSurface(myRenderer, surface);
SDL_Rect sizeRect;
sizeRect.x = 0 ;
sizeRect.y = 0 ;
sizeRect.w = surface->w ;
sizeRect.h = surface->h ;
SDL_Rect posRect;
posRect.x = aCellX;
posRect.y = aCellY;
posRect.w = sizeRect.w;
posRect.h = sizeRect.h;
SDL_RenderCopy(myRenderer, optimizedSurface, &sizeRect, &posRect);
}
void Drawer::DrawText(const char* aText, const char* aFontFile, int aX, int aY)
{
TTF_Font* font = TTF_OpenFont(aFontFile, 24);
if (font == nullptr) {
// Handle font loading error here (e.g. log an error message, throw an exception, etc.)
return;
}
SDL_Color fg = { 255, 0, 0, 255 };
SDL_Surface* surface = TTF_RenderText_Solid(font, aText, fg);
SDL_Texture* optimizedSurface = SDL_CreateTextureFromSurface(myRenderer, surface);
SDL_Rect sizeRect;
sizeRect.x = 0;
sizeRect.y = 0;
sizeRect.w = surface->w;
sizeRect.h = surface->h;
SDL_Rect posRect;
posRect.x = aX;
posRect.y = aY;
posRect.w = sizeRect.w;
posRect.h = sizeRect.h;
SDL_RenderCopy(myRenderer, optimizedSurface, &sizeRect, &posRect);
SDL_DestroyTexture(optimizedSurface);
SDL_FreeSurface(surface);
TTF_CloseFont(font);
}
world.cpp:
World::World(void)
{
}
World::~World()
{
for (auto tile : myPathmapTiles)
{
delete tile;
}
for (auto dot : myDots)
{
delete dot;
}
for (auto bigDot : myBigDots)
{
delete bigDot;
}
}
void World::Init()
{
InitPathmap();
InitDots();
InitBigDots();
}
bool World::InitPathmap()
{
std::string line;
std::ifstream myfile ("map.txt");
if (myfile.is_open())
{
int lineIndex = 0;
while (! myfile.eof() )
{
std::getline (myfile,line);
for (unsigned int i = 0; i < line.length(); i++)
{
PathmapTile* tile = new PathmapTile(i, lineIndex, (line[i] == 'x'));
myPathmapTiles.push_back(tile);
}
lineIndex++;
}
myfile.close();
}
return true;
}
bool World::InitDots()
{
std::string line;
std::ifstream myfile ("map.txt");
if (myfile.is_open())
{
int lineIndex = 0;
while (! myfile.eof() )
{
std::getline (myfile,line);
for (unsigned int i = 0; i < line.length(); i++)
{
if (line[i] == '.')
{
Dot* dot = new Dot(Vector2f(i * 22.0f, lineIndex * 22.0f));
myDots.push_back(dot);
}
}
lineIndex++;
}
myfile.close();
}
return true;
}
bool World::InitBigDots()
{
std::string line;
std::ifstream myfile ("map.txt");
if (myfile.is_open())
{
int lineIndex = 0;
while (! myfile.eof() )
{
std::getline (myfile,line);
for (unsigned int i = 0; i < line.length(); i++)
{
if (line[i] == 'o')
{
BigDot* dot = new BigDot(Vector2f(i * 22.0f, lineIndex * 22.0f));
myBigDots.push_back(dot);
}
}
lineIndex++;
}
myfile.close();
}
return true;
}
void World::Draw(Drawer* aDrawer)
{
aDrawer->Draw("playfield.png");
for(std::list<Dot*>::iterator list_iter = myDots.begin(); list_iter != myDots.end(); list_iter++)
{
Dot* dot = *list_iter;
dot->Draw(aDrawer);
}
for(std::list<BigDot*>::iterator list_iter = myBigDots.begin(); list_iter != myBigDots.end(); list_iter++)
{
BigDot* dot = *list_iter;
dot->Draw(aDrawer);
}
}
bool World::TileIsValid(int anX, int anY)
{
for(std::list<PathmapTile*>::iterator list_iter = myPathmapTiles.begin(); list_iter != myPathmapTiles.end(); list_iter++)
{
PathmapTile* tile = *list_iter;
if (anX == tile->myX && anY == tile->myY && !tile->myIsBlockingFlag)
return true;
}
return false;
}
bool World::HasIntersectedDot(const Vector2f& aPosition)
{
for(std::list<Dot*>::iterator list_iter = myDots.begin(); list_iter != myDots.end(); list_iter++)
{
Dot* dot = *list_iter;
if ((dot->GetPosition() - aPosition).Length() < 5.f)
{
myDots.remove(dot);
delete dot;
return true;
}
}
return false;
}
bool World::HasIntersectedBigDot(const Vector2f& aPosition)
{
for(std::list<BigDot*>::iterator list_iter = myBigDots.begin(); list_iter != myBigDots.end(); list_iter++)
{
BigDot* dot = *list_iter;
if ((dot->GetPosition() - aPosition).Length() < 5.f)
{
myBigDots.remove(dot);
delete dot;
return true;
}
}
return false;
}
bool World::HasIntersectedCherry(const Vector2f& aPosition)
{
return true;
}
void World::GetPath(int aFromX, int aFromY, int aToX, int aToY, std::list<PathmapTile*>& aList)
{
PathmapTile* fromTile = GetTile(aFromX, aFromY);
PathmapTile* toTile = GetTile(aToX, aToY);
for(std::list<PathmapTile*>::iterator list_iter = myPathmapTiles.begin(); list_iter != myPathmapTiles.end(); list_iter++)
{
PathmapTile* tile = *list_iter;
tile->myIsVisitedFlag = false;
}
Pathfind(fromTile, toTile, aList);
}
PathmapTile* World::GetTile(int aFromX, int aFromY)
{
for(std::list<PathmapTile*>::iterator list_iter = myPathmapTiles.begin(); list_iter != myPathmapTiles.end(); list_iter++)
{
PathmapTile* tile = *list_iter;
if (tile->myX == aFromX && tile->myY == aFromY)
{
return tile;
}
}
return NULL;
}
bool World::ListDoesNotContain(PathmapTile* aFromTile, std::list<PathmapTile*>& aList)
{
for(std::list<PathmapTile*>::iterator list_iter = aList.begin(); list_iter != aList.end(); list_iter++)
{
PathmapTile* tile = *list_iter;
if (tile == aFromTile)
{
return false;
}
}
return true;
}
bool SortFromGhostSpawn(PathmapTile* a, PathmapTile* b)
{
int la = abs(a->myX - 13) + abs(a->myY - 13);
int lb = abs(b->myX - 13) + abs(b->myY - 13);
return la < lb;
}
bool World::Pathfind(PathmapTile* aFromTile, PathmapTile* aToTile, std::list<PathmapTile*>& aList)
{
aFromTile->myIsVisitedFlag = true;
if (aFromTile->myIsBlockingFlag)
return false;
if (aFromTile == aToTile)
return true;
std::list<PathmapTile*> neighborList;
PathmapTile* up = GetTile(aFromTile->myX, aFromTile->myY - 1);
if (up && !up->myIsVisitedFlag && !up->myIsBlockingFlag && ListDoesNotContain(up, aList))
neighborList.push_front(up);
PathmapTile* down = GetTile(aFromTile->myX, aFromTile->myY + 1);
if (down && !down->myIsVisitedFlag && !down->myIsBlockingFlag && ListDoesNotContain(down, aList))
neighborList.push_front(down);
PathmapTile* right = GetTile(aFromTile->myX + 1, aFromTile->myY);
if (right && !right->myIsVisitedFlag && !right->myIsBlockingFlag && ListDoesNotContain(right, aList))
neighborList.push_front(right);
PathmapTile* left = GetTile(aFromTile->myX - 1, aFromTile->myY);
if (left && !left->myIsVisitedFlag && !left->myIsBlockingFlag && ListDoesNotContain(left, aList))
neighborList.push_front(left);
neighborList.sort(SortFromGhostSpawn);
for(std::list<PathmapTile*>::iterator list_iter = neighborList.begin(); list_iter != neighborList.end(); list_iter++)
{
PathmapTile* tile = *list_iter;
aList.push_back(tile);
if (Pathfind(tile, aToTile, aList))
return true;
aList.pop_back();
}
return false;
}
Snapshot:
Snapshot
I have tried to write a code that creates a window which shows a particular image when pressed a particular arrow key and closes the window when the x button(on the screen) is clicked:
#include <SDL.h>
#include <iostream>
#include <string>
using namespace std;
enum Gamestate
{
Play, Exit
};
enum Keypress
{
KEY_PRESS_DEFAULT,
KEY_PRESS_UP,
KEY_PRESS_DOWN,
KEY_PRESS_RIGHT,
KEY_PRESS_LEFT,
KEY_PRESS_TOTAL,
};
class Game
{
public:
Game();
~Game();
void run();
private:
//data members
int WINDOW_WIDTH;
int WINDOW_HEIGHT;
SDL_Window* window = NULL;
SDL_Surface* screenSurface = NULL;
SDL_Surface* loadSurface[ KEY_PRESS_TOTAL ];
SDL_Surface* defaultSurface = NULL;
Gamestate _gamestate;
private:
//methods
void init();
void gameLoop();
void processInput();
void updateWindowSurface();
};
void error( string error1 )
{
int itq;
cout << error1 << endl;
SDL_GetError();
cout << endl << "Enter any key to quit" << endl;
cin >> itq;
SDL_Quit();
}
Game::Game()
{
WINDOW_WIDTH = 640;
WINDOW_HEIGHT = 480;
_gamestate = Play;
}
void Game::run()
{
init();
gameLoop();
}
void Game::init()
{
SDL_Init( SDL_INIT_EVERYTHING );
window = SDL_CreateWindow( "GAME", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_SHOWN );
if( window == NULL )
{
error( "SDL could not create a window!" );
}
screenSurface = SDL_GetWindowSurface( window );
if( window == NULL )
{
error( "SDL could not create a screen!" );
}
loadSurface[ KEY_PRESS_DEFAULT ] = SDL_LoadBMP( "press.bmp" );
if( loadSurface[ KEY_PRESS_DEFAULT ] == NULL )
{
error( "Unable to load the Surface!" );
}
loadSurface[ KEY_PRESS_UP ] = SDL_LoadBMP( "up.bmp" );
if( loadSurface[ KEY_PRESS_UP ] == NULL )
{
error( "Unable to load Image!" );
}
loadSurface[ KEY_PRESS_DOWN ] = SDL_LoadBMP( "down.bmp" );
if( loadSurface[ KEY_PRESS_DOWN ] == NULL )
{
error( "Unable to load Image!" );
}
loadSurface[ KEY_PRESS_RIGHT ] = SDL_LoadBMP( "right.bmp" );
if( loadSurface[ KEY_PRESS_RIGHT ] == NULL )
{
error( "Unable to load Image!" );
}
loadSurface[ KEY_PRESS_LEFT ] = SDL_LoadBMP( "left.bmp" );
if( loadSurface[ KEY_PRESS_LEFT ] == NULL )
{
error( "Unable to load Image!" );
}
defaultSurface = loadSurface[ KEY_PRESS_DEFAULT ];
}
void Game::gameLoop()
{
while( _gamestate != Exit )
{
processInput();
updateWindowSurface();
}
}
void Game::processInput()
{
SDL_Event e;
while( SDL_PollEvent( &e ) != 0 )
{
if( e.type == SDL_QUIT )
{
_gamestate = Exit;
}
else if( e.type == SDL_KEYDOWN )
{
switch( e.key.keysym.sym )
{
case SDLK_UP:
defaultSurface = loadSurface[ KEY_PRESS_UP ];
break;
case SDLK_DOWN:
defaultSurface = loadSurface[ KEY_PRESS_DOWN ];
break;
case SDLK_RIGHT:
defaultSurface = loadSurface[ KEY_PRESS_RIGHT ];
break;
case SDLK_LEFT:
defaultSurface = loadSurface[ KEY_PRESS_LEFT ];
break;
default:
defaultSurface = loadSurface[ KEY_PRESS_DEFAULT ];
}
}
}
}
void Game::updateWindowSurface()
{
SDL_BlitSurface( defaultSurface, NULL, screenSurface, NULL );
SDL_UpdateWindowSurface( window );
}
Game::~Game()
{
for( int i = 0; i <= KEY_PRESS_TOTAL; i++ )
{
SDL_FreeSurface( loadSurface[ i ] );
loadSurface[ i ] = NULL;
}
SDL_DestroyWindow( window );
window = NULL;
SDL_Quit();
}
int main( int argc, char* args[] )
{
Game game;
game.run();
return 0;
}
When I press the arrow keys the images which display is correct but when I try to close it, the program crashes. But when I try closing the window before pressing any arrow keys it works just fine.
Can any one help me with it?
I am making a pong clone in C++/SDL2. To take keyboard input from multiple keys, I would like to use SDL_GetKeyboardState(NULL) with a Uint8. However, it isn't working as expected.
Expected behavior: pong paddles move up and down with each keypress.
Actual behavior: keys are not registered.
Here is my code (note that variables written in uppercase letters are from variables.h):
// g++ main.cpp `pkg-config sdl2 SDL2_ttf --cflags --libs`
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include <iostream> // For io
#include <time.h> // Rand seeder
const bool debug = true;
// Basic stuff needed for SDL2
const int WINDOW_WIDTH = 800;
const int WINDOW_HEIGHT = 600;
const int WINDOW_CENTER_X = WINDOW_WIDTH / 2;
const int WINDOW_CENTER_Y = WINDOW_HEIGHT / 2;
const char* WINDOW_TITLE = "Pong";
// Define the location of the paddles in the bitmap
const int PADDLE_BITMAP_X = 0;
const int PADDLE_BITMAP_Y = 0;
const int BALL_BITMAP_X = 100;
const int BALL_BITMAP_Y = 0;
// Positions of player 1 and player 2
const int PADDLE1_X = 50;
const int PADDLE2_X = WINDOW_WIDTH - 75;
// Paddle width and height
const int PADDLE_WIDTH = 20;
const int PADDLE_HEIGHT = 100;
// Speed of both players
const int PLAYER_SPEED = 0;
// Ball Speed -- this will not be constant
// The Ball Modifier will modify the speed based on the place it lands on the paddle
// Ball speed will never go under 10, and will accelerate over time
// Ball diameter
const int BALL_SPEED = 100;
const int BALL_MODIFIER = 5;
const int BALL_DIAMETER = 10;
const int BALL_CENTER_X = WINDOW_CENTER_X - BALL_DIAMETER;
const int BALL_CENTER_Y = WINDOW_CENTER_Y - BALL_DIAMETER;
const int LANG = 3;
const int LANG_ENGLISH = 3;
const int LANG_GERMAN = 4;
// Game Entity data structure
struct GameObject
{
SDL_Rect ScreenLocation;
SDL_Rect BitmapLocation;
int SpeedX;
int SpeedY;
};
// SDL stuff
SDL_Window* gWindow = NULL;
SDL_Renderer* gWindowRenderer;
SDL_Rect gScreen;
SDL_Event e;
// Game objects
GameObject gPlayer1; // Paddle 1
GameObject gPlayer2; // Paddle 2
GameObject gBall; // Ball
// Scores. I feel like it's better to leave them uninitialized.
int gPlayer1Score;
int gPlayer2Score;
void Render();
bool init();
bool GameQuit;
void Quit();
int main( int argc, char* argv[] )
{
// const Uint8* keyStates = SDL_GetKeyboardState(NULL);
if( init() == false )
{
std::cout << "Init failed. Bye bye!\n";
return 1;
}
while( !GameQuit )
{
const Uint8* keyStates = SDL_GetKeyboardState( NULL );
while( SDL_PollEvent( &e ) )
{
if( e.type == SDL_QUIT )
GameQuit = true;
if( e.type == SDL_KEYDOWN )
{
switch( e.key.keysym.scancode )
{
case SDL_SCANCODE_ESCAPE:
GameQuit = true;
break;
}
}
}
if( keyStates[ SDL_SCANCODE_UP ] )
{
gPlayer1.ScreenLocation.y -= PLAYER_SPEED;
}
if( keyStates[ SDL_SCANCODE_DOWN ] )
{
gPlayer1.ScreenLocation.y += PLAYER_SPEED;
}
if( keyStates[ SDL_SCANCODE_W ] )
{
gPlayer2.ScreenLocation.y -= PLAYER_SPEED;
}
if( keyStates[ SDL_SCANCODE_S ] )
{
gPlayer2.ScreenLocation.y += PLAYER_SPEED;
}
Render();
}
Quit();
return 0;
}
bool init()
{
bool success = true;
if( SDL_Init( SDL_INIT_VIDEO < 0 ) )
{
success = false;
return success;
}
if( TTF_Init() < 0 )
{
success = false;
return success;
}
srand( time( NULL ) ); // Seed rng
// From SDL_Rect.h
// 64 typedef struct SDL_Rect
// 65 {
// 66 int x, y;
// 67 int w, h;
// 68 } SDL_Rect;
GameQuit = false;
gPlayer1.ScreenLocation.y = ( ( WINDOW_HEIGHT / 2 ) - ( PADDLE_HEIGHT / 2 ) );
gPlayer1.ScreenLocation.x = PADDLE1_X;
gPlayer1.ScreenLocation.w = PADDLE_WIDTH;
gPlayer1.ScreenLocation.h = PADDLE_HEIGHT;
gPlayer2.ScreenLocation.y = ( ( WINDOW_HEIGHT / 2 ) - ( PADDLE_HEIGHT / 2 ) );
gPlayer2.ScreenLocation.x = PADDLE2_X;
gPlayer2.ScreenLocation.w = PADDLE_WIDTH;
gPlayer2.ScreenLocation.h = PADDLE_HEIGHT;
gBall.ScreenLocation.x = BALL_CENTER_X;
gBall.ScreenLocation.y = BALL_CENTER_Y;
gBall.ScreenLocation.w = BALL_DIAMETER;
gBall.ScreenLocation.h = BALL_DIAMETER;
gPlayer1.BitmapLocation.x = PADDLE_BITMAP_X;
gPlayer1.BitmapLocation.y = PADDLE_BITMAP_Y;
gPlayer1.BitmapLocation.w = PADDLE_WIDTH;
gPlayer1.BitmapLocation.h = PADDLE_HEIGHT;
gPlayer2.BitmapLocation.x = PADDLE_BITMAP_X;
gPlayer2.BitmapLocation.y = PADDLE_BITMAP_Y;
gPlayer2.BitmapLocation.w = PADDLE_WIDTH;
gPlayer2.BitmapLocation.h = PADDLE_HEIGHT;
gBall.BitmapLocation.x = BALL_BITMAP_X;
gBall.BitmapLocation.y = BALL_BITMAP_Y;
gBall.BitmapLocation.w = BALL_DIAMETER;
gBall.BitmapLocation.h = BALL_DIAMETER;
gPlayer1.SpeedY = PLAYER_SPEED;
gPlayer1.SpeedX = 0;
gPlayer2.SpeedY = PLAYER_SPEED;
gPlayer2.SpeedX = 0;
gPlayer1Score = 0;
gPlayer2Score = 0;
gScreen.x = 0;
gScreen.y = 0;
gScreen.w = WINDOW_WIDTH;
gScreen.h = WINDOW_HEIGHT;
// Note to self: Leave this out since color keying NULL will segfault.
// SDL_SetColorKey(gBitmap, SDL_TRUE, SDL_MapRGB(gBitmap->format, 255, 0, 255));
gWindow = SDL_CreateWindow(
WINDOW_TITLE,
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
WINDOW_WIDTH,
WINDOW_HEIGHT,
SDL_WINDOW_MAXIMIZED );
// Render SDL Window
gWindowRenderer = SDL_CreateRenderer( gWindow, -1, 0 );
if( gWindowRenderer == nullptr )
{
success = false;
return success;
}
SDL_RenderSetLogicalSize( gWindowRenderer, WINDOW_WIDTH, WINDOW_HEIGHT );
SDL_SetRenderDrawColor( gWindowRenderer, 0x00, 0x00, 0x00, 0xFF );
return success;
}
// Display Menu Text
bool Menu()
{
bool success = false;
if( LANG == LANG_ENGLISH )
{
// DisplayText("Start (G)ame", 350, 250, 12, 255, 255, 255);
// DisplayText("(Q)uit Game", 350, 270, 12, 255, 255, 255);
success = true;
return success;
}
else if( LANG == LANG_GERMAN )
{
// DisplayText("(G) Spielen", 350, 270, 12, 255, 255, 255);
// DisplayText("(Q) Spiel verlassen", 350, 270, 12, 255, 255, 255);
success = true;
return success;
}
else
{
return success;
}
}
void Render()
{
SDL_RenderClear( gWindowRenderer );
SDL_SetRenderDrawColor( gWindowRenderer, 0x00, 0x00, 0x00, 0xFF );
SDL_RenderFillRect( gWindowRenderer, &gScreen );
SDL_SetRenderDrawColor( gWindowRenderer, 0xFF, 0xFF, 0xFF, 0xFF );
SDL_RenderFillRect( gWindowRenderer, &gPlayer1.ScreenLocation );
SDL_RenderFillRect( gWindowRenderer, &gPlayer2.ScreenLocation );
SDL_RenderFillRect( gWindowRenderer, &gBall.ScreenLocation );
SDL_RenderPresent( gWindowRenderer );
}
void Quit()
{
SDL_DestroyWindow( gWindow );
SDL_Quit();
}
I'm not sure what I'm doing wrong and would appreciate a concise answer.
Thank you for your time.
Builds & runs fine on my Debian 10 system, though PLAYER_SPEED is zero so nothing useful happens to gPlayer1.ScreenLocation.y/gPlayer2.ScreenLocation.y in the keyStates if-blocks.
Setting PLAYER_SPEED to something other than zero fixes that on my end.
I am attempting to make a simple scrolling shooter game with SDL2. I have a moving player on a screen, and I am trying to make the player shoot a bullet using an array (so they can shoot multiple bullets) however, when I press the space bar, nothing happens, and instead the bullet image sort of flashes in the top left corner.
Heres the same code in codepad: http://codepad.org/rOhE1AqY
#include <SDL.h>
#include <stdio.h> //use for things like printf, same as cout
#include <iostream>
#include <string>
#include <time.h>
using namespace std;
//screend dimensions& sprtie dimensions
const int SCREEN_HEIGHT = 600;
const int SCREEN_WIDTH = 400;
const int SPRITE_WIDTH = 60;
const int SPRITE_HEIGHT = 80;
const int MAX_BULLETS = 50;
SDL_Window* Window = NULL;//the window rendering to
SDL_Surface* ScreenSurface = NULL;//surface contained by window
SDL_Surface* Background = NULL;
SDL_Surface* Player = NULL;
SDL_Surface* Enemy = NULL;
SDL_Surface* Bullet = NULL;
SDL_Surface* newBullet = NULL;
SDL_Rect posPlayer, posEnemy, posBullet, posnewBullet;
const Uint8* keystate = SDL_GetKeyboardState(NULL);
SDL_Event event;
class thePlayer
{
public:
thePlayer();
void player_movement();
void show_player();
private:
};
class theBullet
{
public:
theBullet();
bool isActive;
int x_position;
int y_position;
void bullet_movement();
void add_new_bullet();
void show_bullet();
private:
};
theBullet arrayofBullets[MAX_BULLETS];
class theEnemy
{
public:
theEnemy();
void enemy_movement();
void show_enemy();
private:
};
thePlayer::thePlayer()
{
posPlayer.x = 170;
posPlayer.y = SCREEN_HEIGHT;
posPlayer.w = 20;
posPlayer.h = 30;
}
void thePlayer::player_movement()
{
if(keystate[SDL_SCANCODE_LEFT])
{
posPlayer.x -= 2;
}
if(keystate[SDL_SCANCODE_RIGHT])
{
posPlayer.x += 2;
}
if(keystate[SDL_SCANCODE_UP])
{
posPlayer.y -= 2;
}
if(keystate[SDL_SCANCODE_DOWN])
{
posPlayer.y += 2;
}
if ((posPlayer.x + SPRITE_WIDTH) > SCREEN_WIDTH)
{
posPlayer.x = (SCREEN_WIDTH - SPRITE_WIDTH);
}
if ((posPlayer.y + SPRITE_HEIGHT) > SCREEN_HEIGHT)
{
posPlayer.y = (SCREEN_HEIGHT - SPRITE_HEIGHT);
}
}
void thePlayer::show_player()
{
SDL_BlitSurface(Player, NULL, ScreenSurface, &posPlayer);
SDL_SetColorKey(Player, SDL_TRUE, SDL_MapRGB(Player->format, 255, 255, 255));
}
theBullet::theBullet()
{
/*posBullet.x;
posBullet.y;
posBullet.w = 10;
posBullet.h = 15;*/
}
void theBullet::bullet_movement()
{
/*if(keystate[SDL_SCANCODE_SPACE])
{
posBullet.x = posPlayer.x + 25;
posBullet.y = posPlayer.y + 10;
}
posBullet.y -= 2;
if(posBullet.y < 0)
{
posBullet.y = -50;
}*/
}
void theBullet::show_bullet()
{
//SDL_BlitSurface(Bullet, NULL, ScreenSurface, &posBullet);
//SDL_SetColorKey(Bullet, SDL_TRUE, SDL_MapRGB(Player->format, 255, 255, 255));//removes white background
}
theEnemy::theEnemy()
{
srand (time(NULL));
posEnemy.x = rand() % 300 + 50;
posEnemy.y =0;
posEnemy.w = 35;
posEnemy.h = 60;
}
void theEnemy::enemy_movement()
{
posEnemy.y += 1;
if(posEnemy.y > SCREEN_HEIGHT)
{
posEnemy.y = SCREEN_HEIGHT +50;
}
}
void theEnemy::show_enemy()
{
SDL_BlitSurface(Enemy, NULL, ScreenSurface, &posEnemy);
SDL_SetColorKey(Enemy, SDL_TRUE, SDL_MapRGB(Player->format, 255, 255, 255));
}
bool initialise()
{
bool success = true;
if (SDL_Init(SDL_INIT_EVERYTHING) !=0)
{
cout<<"SDL_Init Error."<<SDL_GetError()<<endl;
success = false;
}
else
{
//create the window for game
Window = SDL_CreateWindow("Scrolling Shooter Game", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
if (Window == NULL)
{
cout<<"Window Error"<<SDL_GetError()<<endl;
success = false;
}
else
{
//get window surface
ScreenSurface = SDL_GetWindowSurface(Window);
}
}
return success;
}
bool LoadingMedia()
{
bool success = true;
Background = SDL_LoadBMP("background.bmp");
if (Background == NULL)
{
cout<<"Error in loading background."<<SDL_GetError()<<endl;
success = false;
}
Player = SDL_LoadBMP("spaceship.bmp");
if (Player == NULL)
{
cout<<"Error in loading player."<<SDL_GetError()<<endl;
success = false;
}
Enemy = SDL_LoadBMP("enemy.bmp");
if (Enemy == NULL)
{
cout<<"Error in loading enemy."<<SDL_GetError()<<endl;
success = false;
}
Bullet = SDL_LoadBMP("bullet.bmp");
if (Bullet == NULL)
{
cout<<"Error in loading bullet."<<SDL_GetError()<<endl;
success = false;
}
return success;
}
void closedown()
{
SDL_FreeSurface(Background);
Background = NULL;
SDL_FreeSurface(Player);
Player = NULL;
SDL_FreeSurface(Enemy);
Enemy = NULL;
SDL_DestroyWindow(Window);
Window = NULL;
SDL_Quit();
}
int main(int argc, char** argv)
{
bool quit = false;
thePlayer myPlayer;
theEnemy myEnemy;
theBullet myBullet;
if (!initialise())
{
cout<<"Failed to initialise"<<SDL_GetError()<<endl;
}
else
{
if (!LoadingMedia())
{
cout<<"Error loading media"<<SDL_GetError()<<endl;
}
}
//makes all bullets false
for (int i=0; i<MAX_BULLETS; i++)
{
arrayofBullets[i].isActive = false;
}
//GAME LOOP
while (quit == false)
{
SDL_BlitSurface(Background, NULL, ScreenSurface, NULL);
myPlayer.show_player();
myPlayer.player_movement();
while (SDL_PollEvent(&event))
{
if( event.type == SDL_QUIT )
{
quit = true;
break;
}
if(keystate[SDL_SCANCODE_SPACE])
{
for (int i=0; i<MAX_BULLETS; i++)
{
if (arrayofBullets[i].isActive == false)
{
arrayofBullets[i].x_position = posPlayer.x + 25;
arrayofBullets[i].y_position = posPlayer.y + 10;
arrayofBullets[i].isActive = true;
break;
}
}
}
//update game objects
for (int i=0; i<MAX_BULLETS; i++)
{
if (arrayofBullets[i].isActive == true)
{
arrayofBullets[i].y_position -= 2;
if (arrayofBullets[i].y_position < 0)
{
arrayofBullets[i].isActive = false;
}
}
}
for (int i=0; i<MAX_BULLETS; i++)
{
if (arrayofBullets[i].isActive == true)
{
SDL_BlitSurface(Bullet, NULL, ScreenSurface, NULL);
}
}
}
//myPlayer.show_player();
//myBullet.show_bullet();
//myEnemy.show_enemy();
//myPlayer.player_movement();
//myBullet.bullet_movement();
//myEnemy.enemy_movement();
SDL_UpdateWindowSurface(Window); //updates screen
}
closedown();
return 0;
}
SDL_BlitSurface(Bullet, NULL, ScreenSurface, NULL);
You haven't specified destination rect, so it will blit on left-top corner.
It should be
SDL_Rect dstrect;
dstrect.x = arrayofBullets[i].x_position;
dstrect.y = arrayofBullets[i].y_position;
dstrect.w = Bullet->w;
dstrect.h = Bullet->h;
SDL_BlitSurface(Bullet, NULL, ScreenSurface, &dstrect);
#include "SDL/SDL.h"
#include "SDL/SDL_Image.h"
#include <string>
using namespace std;
//Const screen variables
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;
const char* SCREEN_CAPTION = "Pyro";
const float GRAVITY = 9.8; //Metres per second **NEEDS TO BE ADJUSTED BECAUSE IT'S IN METRES, NOT PIXELS**
const int jumpHeight = 10;
//Non-Const variables
bool running = true;
bool isJumping = true;
int jump = 0;
int frame = 0;
int level = 1;
SDL_Event event;
Uint8 *keystate = NULL;
//SDL Surfaces
SDL_Surface *screen = NULL;
SDL_Surface *background = NULL;
SDL_Surface *sprite = NULL;
SDL_Surface *bEnemy[10];
//Structs
typedef struct entity {
int health;
int damage;
SDL_Rect hitbox;
bool evolved;
} playerType, enemyType;
playerType player;
enemyType basicEnemy[10];
//Functions
SDL_Surface *loadImage( std::string filename )
{
SDL_Surface *loadedImage = NULL;
SDL_Surface *optimizedImage = NULL;
loadedImage = IMG_Load( filename.c_str() );
if( loadedImage != NULL )
{
optimizedImage = SDL_DisplayFormatAlpha( loadedImage );
SDL_FreeSurface( loadedImage );
}
return optimizedImage;
}
void applySurface( int x, int y, SDL_Surface* source, SDL_Surface* location )
{
SDL_Rect offset;
offset.x = x;
offset.y = y;
SDL_BlitSurface( source, NULL, location, &offset );
}
//Main Function
int main( int argc, char* argv[] )
{
if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 )
{
return 1;
}
screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE );
if( screen == NULL )
{
return 1;
}
SDL_WM_SetCaption( SCREEN_CAPTION, NULL );
background = loadImage( "images/background.png" );
sprite = loadImage( "images/player.png" );
SDL_FreeSurface( sprite );
SDL_FreeSurface( background );
while( running )
{
//Main game loop
if( SDL_PollEvent( &event ) )
{
switch( event.type )
{
case SDL_QUIT:
running = false;
break;
case SDL_KEYDOWN:
switch( event.key.keysym.sym )
{
case SDLK_q:
running = false;
break;
}
break;
}
}
keystate = SDL_GetKeyState(NULL);
if( keystate[SDLK_q] ) player.evolved = !player.evolved;
if( keystate[SDLK_UP] )
{
if(isJumping != true)
{
isJumping = true;
}
}
if( keystate[SDLK_LEFT] ) player.hitbox.x -= 1;
if( keystate[SDLK_RIGHT] ) player.hitbox.y += 1;
//Window collision
if( player.hitbox.x < 0 ) {player.hitbox.x = 0;}
else if( player.hitbox.x > SCREEN_WIDTH - player.hitbox.w ) {player.hitbox.x = SCREEN_WIDTH - player.hitbox.w;}
if( player.hitbox.y < 0 ) {player.hitbox.y = 0;}
else if( player.hitbox.y > SCREEN_HEIGHT - player.hitbox.h ) {player.hitbox.y = SCREEN_HEIGHT - player.hitbox.h;}
//Jumping
if( isJumping == true )
{
if(jump >= jumpHeight)
{
jump--;
player.hitbox.y++;
}else {
jump++;
player.hitbox.y--;
}
}
//Updating the screen
applySurface( 0, 0, background, screen );
applySurface( player.hitbox.x, player.hitbox.y, sprite, screen );
if( SDL_Flip( screen ) == -1 )
{
return 1;
}
}
SDL_Quit();
return 0;
}
^ That is the exact code I have. When I run the file it immediately closes. It is compiled with: g++ -o myprogram.exe mysource.cpp -lmingw32 -lSDLmain -lSDL -lSDL_image -static-libgcc -static-libstdc++.
The files I have linked to do exist; they are currently placeholders (background is some random png image I found, and the player is an image of 8-bit mario).
How do I stop my program from closing immediately?
SDL_FreeSurface( sprite );
SDL_FreeSurface( background );
This is where your problem lies.
These lines should appear at the end of the program right before you call SDL_Quit().
Currently, you're blitting freed surfaces onto the window.