Can someone write up a source for a program that just has a "game loop", which just keeps looping until you press Esc, and the program shows a basic image. Heres the source I have right now but I have to use SDL_Delay(2000); to keep the program alive for 2 seconds, during which the program is frozen.
#include "SDL.h"
int main(int argc, char* args[]) {
SDL_Surface* hello = NULL;
SDL_Surface* screen = NULL;
SDL_Init(SDL_INIT_EVERYTHING);
screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE);
hello = SDL_LoadBMP("hello.bmp");
SDL_BlitSurface(hello, NULL, screen, NULL);
SDL_Flip(screen);
SDL_Delay(2000);
SDL_FreeSurface(hello);
SDL_Quit();
return 0;
}
I just want the program to be open until I press Esc. I know how the loop works, I just don't know if I implement inside the main() function, or outside of it. I've tried both, and both times it failed. If you could help me out that would be great :P
Here is a complete and working example. Instead of using a frame-time regulation you can also use SDL_WaitEvent.
#include <SDL/SDL.h>
#include <cstdlib>
#include <iostream>
using namespace std;
const Uint32 fps = 40;
const Uint32 minframetime = 1000 / fps;
int main (int argc, char *argv[])
{
if (SDL_Init (SDL_INIT_VIDEO) != 0)
{
cout << "Error initializing SDL: " << SDL_GetError () << endl;
return 1;
}
atexit (&SDL_Quit);
SDL_Surface *screen = SDL_SetVideoMode (640, 480, 32, SDL_DOUBLEBUF);
if (screen == NULL)
{
cout << "Error setting video mode: " << SDL_GetError () << endl;
return 1;
}
SDL_Surface *pic = SDL_LoadBMP ("hello.bmp");
if (pic == NULL)
{
cout << "Error loading image: " << SDL_GetError () << endl;
return 1;
}
bool running = true;
SDL_Event event;
Uint32 frametime;
while (running)
{
frametime = SDL_GetTicks ();
while (SDL_PollEvent (&event) != 0)
{
switch (event.type)
{
case SDL_KEYDOWN: if (event.key.keysym.sym == SDLK_ESCAPE)
running = false;
break;
}
}
if (SDL_GetTicks () - frametime < minframetime)
SDL_Delay (minframetime - (SDL_GetTicks () - frametime));
}
SDL_BlitSurface (pic, NULL, screen, NULL);
SDL_Flip (screen);
SDL_FreeSurface (pic);
SDL_Delay (2000);
return 0;
}
Tried with something like
SDL_Event e;
while( SDL_WaitEvent(&e) )
{
if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE) break;
}
? You can find many tutorials and example out there; just a fast-search example.
Added note: WaitEvent "freezes" the program so you can't do anything .. you just wait; other waiting technics can be desired (as PollEvent, or WaitEvent again after the initializtion of a timer).
Since you're already using SDL, you could use the SDL_PollEvent function to run an event loop, checking to see if the key press event was ESC. Looks like this would be along the lines of mySDL_Event.key.keysym.sym == SDLK_ESCAPE.
#include <conio.h>
...
while (!kbhit())
{
hello = SDL_LoadBMP("hello.bmp");
SDL_BlitSurface(hello, NULL, screen, NULL);
SDL_Flip(screen);
}
...
Related
Pressing CTRL+C while in the terminal sometimes fails to end the program:
int main(int argc, char *argv[]) {
DrawingWindow window = DrawingWindow(WIDTH, HEIGHT, false);
SDL_Event event;
while(true) {
if (window.pollForInputEvents(event)) handleEvent(event);
draw();
window.renderFrame();
}
}
}
bool DrawingWindow::pollForInputEvents(SDL_Event &event) {
if (SDL_PollEvent(&event)) {
if ((event.type == SDL_QUIT) || ((event.type == SDL_KEYDOWN) && (event.key.keysym.sym == SDLK_ESCAPE))) {
SDL_DestroyTexture(texture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
printMessageAndQuit("Exiting", nullptr);
}
SDL_Event dummy;
// Clear the event queue by getting all available events
// This seems like bad practice (because it will skip some events) however preventing backlog is paramount !
while (SDL_PollEvent(&dummy));
return true;
}
return false;
}
void printMessageAndQuit(const std::string &message, const char *error) {
if (error == nullptr) {
std::cout << message << std::endl;
exit(0);
} else {
std::cout << message << " " << error << std::endl;
exit(1);
}
}
When CTRL+C succeeds (which is most of the time), it does print "Exiting".
I don't know what handleEvent supposed to do, and your code have braces mismatch so looks like it isn't even your actual code. As written, pollForInputEvents fetches one event, checks if it could be considered a quit condition, and then discards all other events in the queue regardless. If event you're looking for happens to be non-first (e.g. as first event you may have keydown of 'ctrl' or mouse move, or window close event, ...), then it never gets processed. handleEvent has the same problem - it gets only first event in frame.
Generally speaking, event processing have to happen in a fast non-blocking loop, which handles events faster than new events are getting in. Processing only one event per frame is a not fast enough, and there is absolutely no reason to process only one event. Events gets accumulated in a queue, you process all events, draw your image frame (potentially slow), present on screen (potentially blocking on vsync), then repeat.
It looks counterintuitive that your event processing is split into two functions.
As I don't see the rest of your code, with "minimal" changes it should be something like:
#include <SDL2/SDL.h>
#include <iostream>
#define WIDTH 640
#define HEIGHT 480
static void handleEvent(SDL_Event &event) {}
static void draw(SDL_Renderer *renderer) {
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
}
class DrawingWindow {
public:
DrawingWindow(int width, int height, bool fs) {
SDL_Init(SDL_INIT_VIDEO);
window = SDL_CreateWindow("test",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
width, height, 0);
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC);
}
bool pollForInputEvents(SDL_Event &event);
void renderFrame() {
SDL_RenderPresent(renderer);
}
SDL_Window *window;
SDL_Renderer *renderer;
};
void printMessageAndQuit(const std::string &message, const char *error) {
if (error == nullptr) {
std::cout << message << std::endl;
exit(0);
} else {
std::cout << message << " " << error << std::endl;
exit(1);
}
}
bool DrawingWindow::pollForInputEvents(SDL_Event &event) {
if (SDL_PollEvent(&event)) {
if ((event.type == SDL_QUIT) || ((event.type == SDL_KEYDOWN) && (event.key.keysym.sym == SDLK_ESCAPE))) {
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
printMessageAndQuit("Exiting", nullptr);
}
return true;
}
return false;
}
int main(int argc, char *argv[]) {
DrawingWindow window = DrawingWindow(WIDTH, HEIGHT, false);
SDL_Event event;
while(true) {
while(window.pollForInputEvents(event)) handleEvent(event);
draw(window.renderer);
window.renderFrame();
}
}
In the following code:
#include <iostream>
#include "SDL.h"
using namespace std;
int main(int argc, char** argv)
{
SDL_Surface* screenSurface = nullptr;
SDL_Surface* image = nullptr;
SDL_Window* window = nullptr;
const Uint8* keystate;
SDL_Rect offset;
offset.x = 100;
offset.y = 200;
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
cout << "Window initialization error: " << SDL_GetError();
}
else
{
window = SDL_CreateWindow("game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_SHOWN);
bool isRunning = true;
SDL_Event ev;
//game loop
while (isRunning)
{
while (SDL_PollEvent(&ev) != 0)
{
if (ev.type == SDL_QUIT)
isRunning = false;
}
keystate = SDL_GetKeyboardState(NULL);
if (keystate[SDL_SCANCODE_W])
{
offset.y -= 1;
}
else if (keystate[SDL_SCANCODE_A])
{
offset.x -= 1;
}
else if (keystate[SDL_SCANCODE_S])
{
offset.y += 1;
}
else if (keystate[SDL_SCANCODE_D])
{
offset.x += 1;
}
screenSurface = SDL_GetWindowSurface(window);
image = SDL_LoadBMP("world.bmp");
SDL_BlitSurface(image, NULL, screenSurface, &offset);
SDL_UpdateWindowSurface(window);
cout << SDL_GetError() << endl;
}
}
SDL_FreeSurface(image);
SDL_DestroyWindow(window);
image = nullptr;
window = nullptr;
SDL_Quit();
return 0;
}
I get an error, saying: "SDL_UpperBlit: passed a NULL surface error." But the error did not occur until I went from using a switch statement in the while loop for SDL_PollEvent, to just using if statements using SDL_SCANCODE_ in the isRunning while loop. So the error does not occur instantly, but after a short while, like 10 seconds or so. So I am able to move around the world.bmp with WASD for a short while, then I get the error "SDL_UpperBlit: passed a NULL surface error.".
What's the solution for this?
image = SDL_LoadBMP("world.bmp");
This loads world.bmp from the disk, creates a brand new surface and stores the image inside. You never destroy this surface, and you don't check for errors either.
As you're running this once per frame, SDL quickly runs out of resources, SDL_LoadBMP returns NULL to signal it, and you pass that NULL to SDL_BlitSurface.
Only load your resources once, and take care of destroying them at the right time. C++ has smart pointers and RAII to do that for you.
I have this simple code for SDL.
#include <iostream>
#include <SDL2/SDL.h>
#include <SDL2_image/SDL_image.h>
using namespace std;
int main(int argc, char * argv[]){
if (SDL_Init(SDL_INIT_EVERYTHING) != 0){
return 1;
}
SDL_Window * win = SDL_CreateWindow("Window", 0, 0, 1920, 1080, SDL_WINDOW_FULLSCREEN_DESKTOP);
if(win == nullptr){
return 1;
}
SDL_Quit();
return 0;
}
None of this shows a window, I have error checked everything. It was working previously, but now it just opens and closes. I'm running on Xcode, if that helps.
Like the others state, your program terminates immediately so the window should "flash" momentarily. You can have the window appear for a few seconds by using SDL_Delay:
SDL_Window *win = SDL_CreateWindow("Hello World!", 100, 100, 640, 480, SDL_WINDOW_SHOWN);
if (win == nullptr){
std::cout << "SDL_CreateWindow Error: " << SDL_GetError() << std::endl;
SDL_Quit();
return 1;
}
SDL_Delay(2000);
SDL_DestroyWindow(win);
SDL_Quit();
And remember to call SDL_DestroyWindow.
A while(true) {} loop will just cause your program to freeze. You probably want something like the following so that it listens for events, and you can close the window at your leisure.
SDL_Event e;
bool quit = false;
while (!quit){
while (SDL_PollEvent(&e)){
if (e.type == SDL_QUIT){
quit = true;
}
if (e.type == SDL_KEYDOWN){
quit = true;
}
if (e.type == SDL_MOUSEBUTTONDOWN){
quit = true;
}
}
}
So I got into SDL2 with C++ quite recently and I did this very simple code :
int main(int argc, char** argv)
{
SDL_Event *event;
bool done = false;
if(SDL_Init(SDL_INIT_VIDEO) != 0)
{
std::cerr << "Problèmes pour initialiser la SDL : " << SDL_GetError() << std::endl;
return 1;
}
SDL_Window *window = 0;
window = SDL_CreateWindow("Mopion", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH, HEIGHT, SDL_WINDOW_SHOWN);
if(window == 0)
{
done = true;
}
while(!done)
{
while(SDL_PollEvent(event))
{
switch(event->type)
{
case SDL_QUIT:
done = true;
break;
case SDL_KEYUP:
if(event->key.keysym.sym == SDLK_q)
{
done = true;
}
break;
default:
break;
}
}
}
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
While that code executes at first quite well, when I hit the "Q" key, the window closes but I got a Windows Error Window saying that "My program stopped working." which is not very convenient.
Using the debugger, I found that everything is fine until SDL_Quit() is called.
Anyone has any idea why this is going on ?
Thanks a lot !
You don't reserve memory for your SDL_Event, and are most probably corrupting your stack. Declare it as automatic and pass it by address to SDL_PollEvent().
You're using uninitialized pointer:
SDL_Event *event;
And you need to fix some errors:
1. If SDL_CreateWindow() returns 0, it means that there is no window and you must not use SDL_DestroyWindow().
2. You're using events, so you should call SDL_Init() like this: SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS).
Why the window that created by SDL Game Library are automatically closed after specific time.
I know the reason is SDL_Delay() function, but if not used that function, the game will appear runtime error.
How can I create a window that continuously work without appear in specific period time ?
My code(Simplest code):
SDL_Window *window;
SDL_Renderer *render;
int main(int argc, char* args[]){
if(SDL_Init(SDL_INIT_EVERYTHING) >= 0){
window = SDL_CreateWindow("Simple game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_SHOWN);
if(window != 0){
render = SDL_CreateRenderer(window, -1, 0);
}
}else{
return 1;
}
SDL_SetRenderDrawColor(render, 0, 0, 0, 255);
SDL_RenderClear(render);
SDL_RenderPresent(render);
SDL_Delay(3000);
SDL_Quit();
return 0
}
You need to loop forever and call SDL update screen functions. Read LazyFoo tutorials found here: http://lazyfoo.net/SDL_tutorials
Or here a short code to get you started:
#include <iostream>
#include "SDL/SDL.h" // basic SDL
#include <string>
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BBP = 32; // bits per-pixel
SDL_Surface* screen = NULL; // display screen
SDL_Event event; // grab events
using namespace std;
bool init() {
// initialize SDL
if(SDL_Init( SDL_INIT_EVERYTHING ) == -1)
return false;
//the screen image
screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT,
SCREEN_BBP, SDL_SWSURFACE );
if(!screen) {
cout << "error creating screen" << endl;
return false;
}
//Set the window caption
SDL_WM_SetCaption("Event Test", NULL );
return true;
}
int main(int argc, char* argv[])
{
try
{
// make sure the program waits for a quit
bool quit = false;
cout << "Starting SDL..." << endl;
// Start SDL
if(!init()) {
cout << "initialize error" << endl;
return false;
}
// main loop
while( quit == false )
{
if (SDL_PollEvent(&event))
{
// The x button click
if(event.type == SDL_QUIT)
{
//quit the program
quit = true;
}
}
// Fill the screen white
SDL_FillRect( screen, &screen->clip_rect, SDL_MapRGB(
screen->format, 0xFF, 0xFF, 0xFF ) );
//Update screen
if(SDL_Flip(screen) == -1)
return -1;
}
}
catch (exception& e)
{
cerr << "exception caught: " << e.what() << endl;
return -1;
}
return 0;
}