Segmentation fault while using SDL - c++

[SOLVED]I'm following this tutorial (video) and I'm at this very moment. I had no problems with compiling, but when it comes to running the program it's just flashing for a second and turning off. So I've run the debugger and I found a segmentation fault from SDL_DisplayFormat in my load_image function, when I comment off lines where I load images it works ok, but I can't find the reason of the problem.
[SOLUTION] I haven't fill the .bmp files that is why the SDL_DisplayFormat didn't work. Once filed with drawning, everything started to work.
Here is my code:
#include "game.h"
/*TODO
*stworzyć plik z blokami "blocks.bmp"
*stworzyć plik z tlem "background.bmp"
*uzywac jako tla do obrazkow 000,255,255
*
*/
game::game()
{
//zaladowanie ekranu
SDL_Init(SDL_INIT_EVERYTHING);
screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGTH, 32, SDL_SWSURFACE);
//ladowanei obrazkow
//ustawianie polozenia i rozmiaru kamery
camera.x = camera.y = 0;
camera.w = SCREEN_WIDTH;
camera.h = SCREEN_HEIGTH;
//inicjalizacja kierunku w kotrym sie poruszamy
direction[0] = direction[1] = 0;
running = true;
block = (load_image("blocks.bmp"));
background = (load_image("background.bmp"));
}
game::~game()
{
SDL_FreeSurface(block);
SDL_FreeSurface(background);
SDL_Quit();
}
SDL_Surface* game::load_image (const char* filename)
{
SDL_Surface* tmp = SDL_LoadBMP(filename);
SDL_Surface* tmp2 = SDL_DisplayFormat(tmp);
//do odkomentowania kolorkey na razie zeby sprawdzac kolizje
// SDL_SetColorKey(tmp2, SDL_SRCCOLORKEY, SDL_MapRGB(screen->format, 0x00, 0xff, 0xff)
SDL_FreeSurface(tmp);
return tmp2;
}
void game::handleEvents()
{
SDL_Event event;
while(SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_QUIT:
running = false;
return;
case SDL_KEYDOWN:
switch(event.key.keysym.sym)
{
case SDLK_LEFT:
direction[0] = 1;
break;
case SDLK_RIGHT:
direction[1] = 1;
break;
}
break;
case SDL_KEYUP:
switch(event.key.keysym.sym)
{
case SDLK_LEFT:
direction[0] = 0;
break;
case SDLK_RIGHT:
direction[1] = 0;
break;
}
break;
}
}
}
void game::start()
{
while(1)
{
handleEvents();
SDL_Flip(screen);
}
}

One advise up front: Provide complete, minimal code including compile instructions. Yours doesn't have a main() function and the class definition is missing too (game.h). After reconstructing this and running it in a debugger, I find that the first SDL_LoadBMP() returns NULL (maybe that's the same at yours, but here it's definitely the case that I don't have the according files), so I have no clue if you have the same problem or not.
Now, what you can try to fix this is to check returnvalues. In this case, try this:
SDL_Surface* tmp = SDL_LoadBMP(filename);
if(!tmp)
throw std::runtime_error("SDL_LoadBMP() failed");
Using a unique_ptr or some custom wrapper class is also a good advice in order to not leak resources.

Related

Why doesn't the default case run here?

I wrote these following lines of codes:
#include <sdl.h>
#include <iostream>
#include <stdio.h>
#include <string>
bool running = true;
enum KeyPressSurfaces {
KEY_PRESS_SURFACE_DEFAULT,
KEY_PRESS_SURFACE_UP,
KEY_PRESS_SURFACE_DOWN,
KEY_PRESS_SURFACE_LEFT,
KEY_PRESS_SURFACE_RIGHT,
//de deallocate surface
KEY_PRESS_SURFACE_TOTAL
};
int main(int argc, char** argv) {
//standard stuffs
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window = SDL_CreateWindow("vibin' with smug pika", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 300, 300, 0);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
SDL_Surface* loadSurface(std::string path);
SDL_Surface* surface = SDL_GetWindowSurface(window);
SDL_Surface* keypress [KEY_PRESS_SURFACE_TOTAL];
//anh hien tai dang duoc load, de BlitSurface len surface
//SDL_BlitSurface(current --> surface)
SDL_Surface* current = NULL;
//set windows icon
SDL_Surface* icon = SDL_LoadBMP("../pikachu/keypress_bmp/icon.bmp");
SDL_SetWindowIcon(window, icon);
SDL_Event event;
//load each image into the keypress array
keypress[KEY_PRESS_SURFACE_DEFAULT] = SDL_LoadBMP("../pikachu/keypress_bmp/default.bmp");
keypress[KEY_PRESS_SURFACE_UP] = SDL_LoadBMP("../pikachu/keypress_bmp/up.bmp");
keypress[KEY_PRESS_SURFACE_DOWN] = SDL_LoadBMP("../pikachu/keypress_bmp/down.bmp");
keypress[KEY_PRESS_SURFACE_LEFT] = SDL_LoadBMP("../pikachu/keypress_bmp/left.bmp");
keypress[KEY_PRESS_SURFACE_RIGHT] = SDL_LoadBMP("../pikachu/keypress_bmp/right.bmp");
while (running) {
while (SDL_PollEvent(&event)){
switch (event.type) {
//user click x
case SDL_QUIT:
running = false;
break;
//where all the user inputs are handled
case SDL_KEYDOWN:
switch (event.key.keysym.sym) {
case SDLK_UP:
current = keypress[KEY_PRESS_SURFACE_UP];
break;
case SDLK_DOWN:
current = keypress[KEY_PRESS_SURFACE_DOWN];
break;
case SDLK_LEFT:
current = keypress[KEY_PRESS_SURFACE_LEFT];
break;
case SDLK_RIGHT:
current = keypress[KEY_PRESS_SURFACE_RIGHT];
break;
case SDLK_SPACE:
current = keypress[KEY_PRESS_SURFACE_DEFAULT];
break;
default:
current = keypress[KEY_PRESS_SURFACE_DEFAULT];
}
}
}
SDL_BlitSurface(current, NULL, surface, NULL);
SDL_UpdateWindowSurface(window);
}
//deallocating surfaces
for(int i=0; i<KEY_PRESS_SURFACE_TOTAL; ++i) {
SDL_FreeSurface(keypress[i]);
keypress[i] = NULL;
}
//destroy everythangggg
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
return 0;
}
However, this bit:
default:
current = keypress[KEY_PRESS_SURFACE_DEFAULT];
does not run at all, no matter where I put it. The program should have shown the default image at the beginning, but there's only black when I compiled. Everything else runs fine and I cannot determine what mistake I make.
I'm using CodeBlock version 20.03 and the latest version of SDL2.
I created a solution for you, and I have some notes to check from your end,
Check if the file path is correct
../pikachu/keypress_bmp/default.bmp.
When you want to trigger the default, you should press another key
e.i Enter, A, B, etc.
I have downloaded an SDL library I am not sure if you are using the
same, but mine is V2.
I have commented on your code, which I didn't use here in the image
path.
here is my code and result:
//#include <sdl.h>
#include <SDL.h>
#include <iostream>
#include <stdio.h>
#include <string>
bool running = true;
enum KeyPressSurfaces {
KEY_PRESS_SURFACE_DEFAULT,
KEY_PRESS_SURFACE_UP,
KEY_PRESS_SURFACE_DOWN,
KEY_PRESS_SURFACE_LEFT,
KEY_PRESS_SURFACE_RIGHT,
//de deallocate surface
KEY_PRESS_SURFACE_TOTAL
};
int main(int argc, char** argv) {
//standard stuffs
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window = SDL_CreateWindow("vibin' with smug pika", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 300, 300, 0);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
SDL_Surface* loadSurface(std::string path);
SDL_Surface* surface = SDL_GetWindowSurface(window);
SDL_Surface* keypress[KEY_PRESS_SURFACE_TOTAL];
//anh hien tai dang duoc load, de BlitSurface len surface
//SDL_BlitSurface(current --> surface)
SDL_Surface* current = NULL;
//set windows icon
//SDL_Surface* icon = SDL_LoadBMP("../pikachu/keypress_bmp/icon.bmp");
SDL_Surface* icon = SDL_LoadBMP("C:/Users/Awat/Desktop/bmp/img1.bmp");
SDL_SetWindowIcon(window, icon);
SDL_Event event;
//load each image into the keypress array
/*
keypress[KEY_PRESS_SURFACE_DEFAULT] = SDL_LoadBMP("../pikachu/keypress_bmp/default.bmp");
keypress[KEY_PRESS_SURFACE_UP] = SDL_LoadBMP("../pikachu/keypress_bmp/up.bmp");
keypress[KEY_PRESS_SURFACE_DOWN] = SDL_LoadBMP("../pikachu/keypress_bmp/down.bmp");
keypress[KEY_PRESS_SURFACE_LEFT] = SDL_LoadBMP("../pikachu/keypress_bmp/left.bmp");
keypress[KEY_PRESS_SURFACE_RIGHT] = SDL_LoadBMP("../pikachu/keypress_bmp/right.bmp");
*/
keypress[KEY_PRESS_SURFACE_DEFAULT] = SDL_LoadBMP("C:/Users/Awat/Desktop/bmp/imgD.bmp");
keypress[KEY_PRESS_SURFACE_UP] = SDL_LoadBMP("C:/Users/Awat/Desktop/bmp/img3.bmp");
keypress[KEY_PRESS_SURFACE_DOWN] = SDL_LoadBMP("C:/Users/Awat/Desktop/bmp/img4.bmp");
keypress[KEY_PRESS_SURFACE_LEFT] = SDL_LoadBMP("C:/Users/Awat/Desktop/bmp/img5.bmp");
keypress[KEY_PRESS_SURFACE_RIGHT] = SDL_LoadBMP("C:/Users/Awat/Desktop/bmp/img6.bmp");
while (running) {
while (SDL_PollEvent(&event)) {
switch (event.type) {
//user click x
case SDL_QUIT:
running = false;
break;
//where all the user inputs are handled
case SDL_KEYDOWN:
switch (event.key.keysym.sym) {
case SDLK_UP:
current = keypress[KEY_PRESS_SURFACE_UP];
break;
case SDLK_DOWN:
current = keypress[KEY_PRESS_SURFACE_DOWN];
break;
case SDLK_LEFT:
current = keypress[KEY_PRESS_SURFACE_LEFT];
break;
case SDLK_RIGHT:
current = keypress[KEY_PRESS_SURFACE_RIGHT];
break;
case SDLK_SPACE:
current = keypress[KEY_PRESS_SURFACE_DEFAULT];
break;
default:
current = keypress[KEY_PRESS_SURFACE_DEFAULT];
}
}
}
SDL_BlitSurface(current, NULL, surface, NULL);
SDL_UpdateWindowSurface(window);
}
//deallocating surfaces
for (int i = 0; i < KEY_PRESS_SURFACE_TOTAL; ++i) {
SDL_FreeSurface(keypress[i]);
keypress[i] = NULL;
}
//destroy everythangggg
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
return 0;
}

SDL 2.0 Key repeat and delay

I'm having a problem with SDL 2.0 keyboard input in pong-like game. When I order to move to the left by pressing left arrow, it is processed by SDL_PollEvents() and responds correctly if the key was pressed once. However, if I keep the key pressed, I get a short delay (as long as Windows key repeat delay) before moving continuously.
Here is function processing events:
void Event::PlayerEvent (Player &player)
{
while (SDL_PollEvent (&mainEvent))
{
switch (mainEvent.type)
{
case SDL_KEYDOWN :
switch (mainEvent.key.keysym.sym)
{
case SDLK_ESCAPE :
gameRunning = false;
break;
case SDLK_LEFT :
player.moving = player.left;
break;
case SDLK_RIGHT :
player.moving = player.right;
}
break;
case SDL_QUIT :
gameRunning = false;
}
}
}
EDIT: After all, I managed to fix this issue by calling
SystemParametersInfo (SPI_SETKEYBOARDDELAY, 0, 0, 0) at the start of the program and SystemParametersInfo (SPI_SETKEYBOARDDELAY, 1, 0, 0) at the end, to return to standard key repeat delay.
For game movement, you would typically not use events, but rather use states.
Try using SDL_GetKeyboardState() outside of the event loop:
const Uint8* keystates = SDL_GetKeyboardState(NULL);
...
if(keystates[SDL_SCANCODE_LEFT])
player.moving = player.left;
else if(keystates[SDL_SCANCODE_RIGHT])
player.moving = player.right;
using SPI_SETKEYBOARDDELAY is not a good approach. This way your game will not be protable anymore since its only available on Windows.
Instead you should use like menthiond in an answer before SDL_GetKeyboardState.
Howeve be aware that you still have to collect the SDL_PollEvent. Otherwise SDL_GetKeyboardState will be always empty.
So it should be like this:
//...
SDL_Event sdlEvent;
while (SDL_PollEvent(&sdlEvent)) {
if (sdlEvent.type == SDL_QUIT) {
//..
}
}
const Uint8* keystates = SDL_GetKeyboardState(NULL);
if(keystates[SDL_SCANCODE_LEFT]) {
//...
}
if(keystates[SDL_SCANCODE_RIGHT]) {
/...
}
//...
simple as that
int vertical = 0;
int horizontal = 0;
float x = 500;
float y = 500;
float speed = 5.0;
in your sdl loop:
if (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_KEYDOWN:
{
switch (event.key.keysym.sym)
{
case SDLK_LEFT: horizontal=-1; break;
case SDLK_RIGHT: horizontal = 1; break;
case SDLK_UP: vertical=-1; break;
case SDLK_DOWN: vertical=+1; break;
}
break;
}
case SDL_KEYUP:
{
switch (event.key.keysym.sym)
{
case SDLK_LEFT: horizontal = 0; break;
case SDLK_RIGHT: horizontal = 0; break;
case SDLK_UP: vertical = 0; break;
case SDLK_DOWN: vertical = 0; break;
}
break;
}
}
}
x += horizontal * speed;
y += vertical * speed;
Use the SDL_GetKeyboardState capturing outside of - while (SDL_PollEvent (&mainEvent)), that works fine.

Error during compilation of SDL test

I'm learning to programming with SDL2. Currently, I'm making a basic exercise. My program load a background image, and a complete sprite sheet on the background. But I'm having problems while executing the program. When I execute the binary, the program window closes immediately by itself; I cant see anything. I think it is a problem with the main loop, but it looks right for me. This is my code
#include "SDL.h"
void main () {
int gameover = 0;
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* TheWindow;
SDL_Renderer* RenderEngine;
SDL_Surface* LoadedSurface;
SDL_Surface* LoadedImage;
SDL_Texture* CharacterImg;
SDL_Texture* BackgroundImg;
TheWindow = SDL_CreateWindow("Character Test",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 580, SDL_WINDOW_RESIZABLE);
RenderEngine = SDL_CreateRenderer( TheWindow, -1, SDL_RENDERER_ACCELERATED);
LoadedSurface= SDL_LoadBMP("./maptest.bmp");
BackgroundImg = SDL_CreateTextureFromSurface( RenderEngine, LoadedSurface);
SDL_FreeSurface(LoadedSurface);
LoadedImage = SDL_LoadBMP("./sprite.bmp");
CharacterImg = SDL_CreateTextureFromSurface( RenderEngine, LoadedImage);
SDL_FreeSurface(LoadedImage);
SDL_Event event;
while (!gameover)
{
if (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
gameover = 1;
break;
case SDL_KEYDOWN:
switch (event.key.keysym.sym) {
case SDLK_ESCAPE:
case SDLK_q:
gameover = 1;
break;
}
}
break;
}
SDL_RenderClear(RenderEngine);
SDL_RenderCopy(RenderEngine, BackgroundImg, NULL, NULL);
SDL_RenderCopy(RenderEngine, CharacterImg, 120, 80);
SDL_RenderPresent(RenderEngine);
}
SDL_Quit();
}
Your code will quit the while-loop if any SDL_PollEvent happens:
while (!gameover)
{
if (SDL_PollEvent(&event)) //Any SDL_PollEvent that gets into if...
{
switch (event.type)
{
case SDL_QUIT:
gameover = 1;
break;
case SDL_KEYDOWN:
switch (event.key.keysym.sym)
{
case SDLK_ESCAPE:
case SDLK_q:
gameover = 1;
break;
}
}
break; //...will eventually hit this break if it didn't break before
}
SDL_RenderClear(RenderEngine);
SDL_RenderCopy(RenderEngine, BackgroundImg, NULL, NULL);
SDL_RenderCopy(RenderEngine, CharacterImg, 120, 80);
SDL_RenderPresent(RenderEngine);
}

Moving Bitmaps in SDL

My image cant load can someone tell me why please?
I'm trying to change the offset when I press WASD, it will work in Code::Blocks but not the .exe file.
#ifdef __cplusplus
#include <cstdlib>
#else
#include <stdlib.h>
#endif
#include <SDL/SDL.h>
int WIDTH = 800;
int HEIGHT = 600;
int main (int argc, char** argv)
{
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Surface *screen = SDL_SetVideoMode(WIDTH, HEIGHT, 32, SDL_SWSURFACE|SDL_DOUBLEBUF);
if (!screen){
printf("Unable to set 800x600 video: %s\n", SDL_GetError());
return 1;
}
SDL_WM_SetCaption("The Killer Of The Night Pre-Release 0.0.1", NULL);
SDL_Surface *player = SDL_LoadBMP("lol.bmp");
if (!player){
printf("Unable to load the image here's the error: %s\n", SDL_GetError());
}
SDL_Rect offset;
offset.x = 100;
offset.y = 200;
bool done = false;
while (!done)
{
SDL_Event event;
SDL_PollEvent(&event);
if (event.type == SDL_QUIT)
{
done = true;
}
if (event.type == SDL_KEYDOWN)
{
switch(event.key.keysym.sym)
{
case SDLK_ESCAPE:
done = true;
break;
case SDLK_w:
offset.y -= 1;
break;
case SDLK_a:
offset.x -= 1;
break;
case SDLK_s:
offset.y += 1;
break;
case SDLK_d:
offset.x += 1;
break;
}
}
SDL_FillRect(screen, 0, SDL_MapRGB(screen->format, 25,25,255));
SDL_BlitSurface(player, 0, screen, &offset);
SDL_Flip(screen);
}
return 0;
}
It's working fine in Code::Blocks but when I run the .exe file it's not working!?!
You need to put lol.bmp in the directory with your exe.
When you run an executable in CodeBlocks, the working directory is the directory of the Code Block project file (.cbp), which is where your lol.bmp is located. You need to put that file in the bin/Debug/ folder or bin/Release/ folder depending on your build target.
More info would be nice since "it's not working" doesn't really say what's failing. For example is it a dll error, or like previously stated is lol.bmp not in the proper folder. Also I believe SDL_Rect needs a height and width as well.

Event handling bug with SDL

I am making a snake game using SDL and C++, and I found a bug involving events.
In this game, there are two important functions for now : the play function (the "main" function of the game) and the pause function. When the P key is pressed, the play function calls and executes the pause function. In it, you have two possibilities: either continue or quit the game.
Now, here is the problem. When I try to click "Continue game", the game flashes for a split second and comes back to the pause menu. When I keep the mouse button down, I realize the game itself is frozen until an event of any kind happens. If it does, it just comes back to where it was.
After some tests, I also noticed that the bug was due to the SDL_PollEvent function. So I changed this function in the play function to SDL_WaitEvent, which put the game back when I asked him to. However, another problem is created: since, in my play function, there is a timer that uses SDL_GetTicks, the game needs a trigger event to be fluid. For example, when I constantly move the cursor in any direction, the game can run. When I stop, it freezes.
Is there a way to fix this bug?
Here is the event handler in the play function:
SDL_PollEvent(&event); // Handle events
switch(event.type)
{
case SDL_QUIT:
quit = true;
break;
case SDL_KEYDOWN:
switch(event.key.keysym.sym) // Change direction at certain key press
{
case SDLK_s:
currentDirection = SNAKE_DOWN;
break;
case SDLK_w:
currentDirection = SNAKE_UP;
break;
case SDLK_a:
currentDirection = SNAKE_LEFT;
break;
case SDLK_d:
currentDirection = SNAKE_RIGHT;
break;
case SDLK_ESCAPE: // Quit if escape key pressed
quit = true;
break;
case SDLK_p:
if (pause(screen) == false)
quit = true;
break;
break;
default: ; // Code to block the compiler's -Wall flag (does not do anything to the program itself)
}
break;
}
And here is the complete pause function:
bool pause(SDL_Surface *screen)
{
SDL_Surface *pauseMessage, *continueButton, *quitButton;
SDL_Rect posPauseMessage, posContinueButton, posQuitButton;
TTF_Font *fipps;
SDL_Color color = {255, 255, 255};
SDL_Event event;
int x = 0, y = 0;
bool quit = false, returnFalse = false;
fipps = TTF_OpenFont("fipps.ttf", 50);
pauseMessage = TTF_RenderText_Blended(fipps, "PAUSED", color);
continueButton = TTF_RenderText_Blended(fipps, "Continue Game", color);
quitButton = TTF_RenderText_Blended(fipps, "Exit to menu", color);
posPauseMessage.x = (screen->w - pauseMessage->w) / 2;
posPauseMessage.y = 200;
posContinueButton.x = (screen->w - continueButton->w) / 2;
posContinueButton.y = posPauseMessage.y + 200;
posQuitButton.x = (screen->w - quitButton->w) / 2;
posQuitButton.y = posContinueButton.y + 100;
while (!quit)
{
SDL_WaitEvent(&event);
switch(event.type)
{
case SDL_QUIT:
returnFalse = true;
quit = true;
break;
case SDL_MOUSEBUTTONUP:
x = event.button.x;
y = event.button.y;
if ((x > posContinueButton.x) && (x < posContinueButton.x + continueButton->w) && (y > posContinueButton.y) && (y < posContinueButton.y + continueButton->h))
quit = true;
else if ((x > posQuitButton.x) && (x < posQuitButton.x + quitButton->w) && (y > posQuitButton.y) && (y < posQuitButton.y + quitButton->h))
returnFalse = true;
quit = true;
break;
}
SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
SDL_BlitSurface(pauseMessage, NULL, screen, &posPauseMessage);
SDL_BlitSurface(continueButton, NULL, screen, &posContinueButton);
SDL_BlitSurface(quitButton, NULL, screen, &posQuitButton);
SDL_Flip(screen);
}
TTF_CloseFont(fipps);
SDL_FreeSurface(pauseMessage);
SDL_FreeSurface(continueButton);
SDL_FreeSurface(quitButton);
if (returnFalse)
return false;
return true;
}
Thanks to #jordsti, I found a solution : I need to put the SDL_PollEvent as a condition for a while loop, which contains the switch block.