#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.
Related
I'm trying to display the string "hey" using a true type font in SDL, but there are glitches. Here is the text as it should appear (I took a screen recording, so the lower part in this shot is just the control for the video player):
And here it is with a glitch:
As you can see the upper part of the letter "h" is missing.
Here is the code that I used:
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include <iostream>
#include <string>
int fatal( std::string m ) {
std::cout << "Fatal error: " << m << "\n";
exit(-1);
}
void drawText(TTF_Font* font,SDL_Renderer* r, std::string message) {
SDL_Color c = {255,255,255,255};
SDL_Surface *temp = TTF_RenderText_Blended( font, message.c_str(), c);
if ( temp == NULL )
fatal("failed to create surface");
SDL_Texture *txt = SDL_CreateTextureFromSurface( r, temp );
if ( txt == NULL )
fatal("failed to create texture");
SDL_FreeSurface( temp );
SDL_Rect src;
src.x = 0;
src.y = 0;
SDL_QueryTexture( txt, NULL, NULL, &src.w, &src.h );
SDL_Rect pos;
pos.x = 80;
pos.y = 80;
pos.w = src.w;
pos.h = src.h;
if ( SDL_RenderCopy(r,txt,&src,&pos) != 0)
fatal("SDL_RenderCopy failed");
SDL_DestroyTexture(txt);
}
extern "C" int main( int argc, char** argv ) {
SDL_Renderer *renderer;
SDL_Window *window;
if ( SDL_Init( SDL_INIT_VIDEO ) != 0 )
fatal("sdl_init failed");
if ( TTF_Init() != 0 )
fatal("ttf_init failed");
if ( SDL_CreateWindowAndRenderer ( 200, 200, 0, &window, &renderer ) != 0 )
fatal("sdl_createwindowandrenderer failed");
TTF_Font* font = TTF_OpenFont( "Arial.ttf", 30 );
if ( font == NULL )
fatal("failed to open font");
SDL_Event e;
while ( 1 ) {
if ( SDL_PollEvent(&e) ) {
if (e.type == SDL_QUIT)
break;
}
// clear back buffer
SDL_SetRenderDrawColor(renderer,0,0,255,255);
SDL_RenderClear(renderer);
drawText(font,renderer,"hey");
SDL_RenderPresent(renderer);
}
return 0;
}
Which I compiled on macOS 10.15.6 using the following command
g++ -std=c++17 textTest.cpp -lSDL2 -lSDL2_ttf
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.
This is basically my code here, very simple just to load an image to display. But the first thing I open a window surface, the surface has characters like 'X','S' out of nowhere:
int main( int argc, char* args[] )
{
SDL_Init( SDL_INIT_VIDEO );
SDL_Surface* screen = SDL_SetVideoMode( WINDOW_WIDTH, WINDOW_HEIGHT, 0,
SDL_HWSURFACE | SDL_DOUBLEBUF );
SDL_WM_SetCaption( WINDOW_TITLE, 0 );
SDL_Surface* bitmap = SDL_LoadBMP("bat.bmp");
// Part of the bitmap that we want to draw
SDL_Rect source;
source.x = 24;
source.y = 63;
source.w = 65;
source.h = 44;
// Part of the screen we want to draw the sprite to
SDL_Rect destination;
destination.x = 100;
destination.y = 100;
destination.w = 65;
destination.h = 44;
SDL_Event event;
bool gameRunning = true;
int i=1000;
while (i)
{
if (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
gameRunning = false;
}
}
SDL_BlitSurface(bitmap, &source, screen, &destination);
SDL_Flip(screen);
i--;
}
SDL_FreeSurface(bitmap);
SDL_Quit();
return 0;
}
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...
My Makefile -
all:
g++ main.cpp -I/usr/local/include -L/usr/local/lib -lSDL2 -lSDL_image
My Code I am using as taken from a tutorial -
/*This source code copyrighted by Lazy Foo' Productions (2004-2013) */
//Using SDL, SDL_image, standard IO, and strings
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <stdio.h>
#include <string>
//Screen dimension constants
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
//Texture wrapper class
class LTexture
{
public:
//Initializes variables
LTexture();
//Deallocates memory
~LTexture();
//Loads image at specified path
bool loadFromFile( std::string path );
#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:
//The actual hardware texture
SDL_Texture* mTexture;
//Image dimensions
int mWidth;
int mHeight;
};
//The application time based timer
class LTimer
{
public:
//Initializes variables
LTimer();
//The various clock actions
void start();
void stop();
void pause();
void unpause();
//Gets the timer's time
Uint32 getTicks();
//Checks the status of the timer
bool isStarted();
bool isPaused();
private:
//The clock time when the timer started
Uint32 mStartTicks;
//The ticks stored when the timer was paused
Uint32 mPausedTicks;
//The timer status
bool mPaused;
bool mStarted;
};
//The dot that will move around on the screen
class Dot
{
public:
//The dimensions of the dot
static const int DOT_WIDTH = 20;
static const int DOT_HEIGHT = 20;
//Maximum axis velocity of the dot
static const int DOT_VEL = 10;
//Initializes the variables
Dot();
//Takes key presses and adjusts the dot's velocity
void handleEvent( SDL_Event& e );
//Moves the dot
void move();
//Shows the dot on the screen
void render();
private:
//The X and Y offsets of the dot
int mPosX, mPosY;
//The velocity of the dot
int mVelX, mVelY;
};
//Starts up SDL and creates window
bool init();
//Loads media
bool loadMedia();
//Frees media and shuts down SDL
void close();
//The window we'll be rendering to
SDL_Window* gWindow = NULL;
//The window renderer
SDL_Renderer* gRenderer = NULL;
//Scene textures
LTexture gDotTexture;
LTexture::LTexture()
{
//Initialize
mTexture = NULL;
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;
}
Dot::Dot()
{
//Initialize the offsets
mPosX = 0;
mPosY = 0;
//Initialize the velocity
mVelX = 0;
mVelY = 0;
}
void Dot::handleEvent( SDL_Event& e )
{
//If a key was pressed
if( e.type == SDL_KEYDOWN && e.key.repeat == 0 )
{
//Adjust the velocity
switch( e.key.keysym.sym )
{
case SDLK_UP: mVelY -= DOT_VEL; break;
case SDLK_DOWN: mVelY += DOT_VEL; break;
case SDLK_LEFT: mVelX -= DOT_VEL; break;
case SDLK_RIGHT: mVelX += DOT_VEL; break;
}
}
//If a key was released
else if( e.type == SDL_KEYUP && e.key.repeat == 0 )
{
//Adjust the velocity
switch( e.key.keysym.sym )
{
case SDLK_UP: mVelY += DOT_VEL; break;
case SDLK_DOWN: mVelY -= DOT_VEL; break;
case SDLK_LEFT: mVelX += DOT_VEL; break;
case SDLK_RIGHT: mVelX -= DOT_VEL; break;
}
}
}
void Dot::move()
{
//Move the dot left or right
mPosX += mVelX;
//If the dot went too far to the left or right
if( ( mPosX < 0 ) || ( mPosX + DOT_WIDTH > SCREEN_WIDTH ) )
{
//Move back
mPosX -= mVelX;
}
//Move the dot up or down
mPosY += mVelY;
//If the dot went too far up or down
if( ( mPosY < 0 ) || ( mPosY + DOT_HEIGHT > SCREEN_HEIGHT ) )
{
//Move back
mPosY -= mVelY;
}
}
void Dot::render()
{
//Show the dot
gDotTexture.render( mPosX, mPosY );
}
bool init()
{
//Initialization flag
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( "SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
if( gWindow == NULL )
{
printf( "Window could not be created! 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( "Renderer could not be created! 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;
}
bool loadMedia()
{
//Loading success flag
bool success = true;
//Load dot texture
if( !gDotTexture.loadFromFile( "26_motion/dot.bmp" ) )
{
printf( "Failed to load dot texture!\n" );
success = false;
}
return success;
}
void close()
{
//Free loaded images
gDotTexture.free();
//Destroy window
SDL_DestroyRenderer( gRenderer );
SDL_DestroyWindow( gWindow );
gWindow = NULL;
gRenderer = NULL;
//Quit SDL subsystems
IMG_Quit();
SDL_Quit();
}
int main( int argc, char* args[] )
{
//Start up SDL and create window
if( !init() )
{
printf( "Failed to initialize!\n" );
}
else
{
//Load media
if( !loadMedia() )
{
printf( "Failed to load media!\n" );
}
else
{
//Main loop flag
bool quit = false;
//Event handler
SDL_Event e;
//The dot that will be moving around on the screen
Dot dot;
//While application is running
while( !quit )
{
//Handle events on queue
while( SDL_PollEvent( &e ) != 0 )
{
//User requests quit
if( e.type == SDL_QUIT )
{
quit = true;
}
//Handle input for the dot
dot.handleEvent( e );
}
//Move the dot
dot.move();
//Clear screen
SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );
SDL_RenderClear( gRenderer );
//Render objects
dot.render();
//Update screen
SDL_RenderPresent( gRenderer );
}
}
}
//Free resources and close SDL
close();
return 0;
}
My Error -
g++ main.cpp -I/usr/local/include -L/usr/local/lib -lSDL2 -lSDL_image.lib
ld: library not found for -lSDL_image.lib
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [all] Error 1
I am unable to get this to load. I used brew to install SDL2_image and it appears to exist in usr/local/lib and such. I see libSDL_image.a and other assorted items.
Can someone please tell me how to edit my makefile for mac so that I can compile the code I am attempting to use. I am not sure why -lSDL_image would not work as it should do so.
To load SDL_image it should be
-lSDL_image
but your not using SDL 1.X your are using SDL 2 so it should be
-lSDL2_image
If it still says that it can't find it then you need to make sure it is in a path that ld searches in.
-L/Path/To/SDL_image
If that still doesn't work make sure that you have the development library and not just the runtime binaries
You can grab the development libraries for SDL_image here : http://www.libsdl.org/projects/SDL_image/