SDL/C++ High-Low Guessing Game (Version 2)
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
3
down vote
favorite
So after getting a very thorough review and feedback from indi in my previous attempt, SDL/C++ High-Low Guessing Game, I decided to go through the game and fix as many mistakes as I could. But going through the feedback also just opened up even more questions.
Things I was unable to do
Get rid of all global variables. I was able to remove or move most of the global variables, but I had an issue with the
SDL_Window*
,SDL_Renderer
, andTTF_Font
. It was suggested that I used astd::unique_ptr
, so I made the window astd::unique_ptr
, but I was unable to use that window as a parameter for creating the renderer because there was no suitable conversion from astd::unique_ptr
to aSDL_Window*
. Thus I just kept them in global until I can figure out how to make it work.Use the struct "tags" for my
LTexture
class. It was suggested to usestruct from_surface_tag from_surface;
andstruct from_text_tag from_text;
to indicate which version of the constructor I was using. The compiler just kept saying thatfrom_text
orfrom_surface
were undefined. I realize that there mainly for the reader of the code, so I just made anenum
to use as the tags.Used the state machine that was suggested. I make the engine that was suggested, but I failed miserably. Instead I created a very basic state machine that hopefully works and gets rid of the
playAgain -> mainMenu -> playAgain
loop. Hopefully I'll be able to understand how to other one once I get more experience.Lastly, I did not make not make the
LTexture
class it's own file, mainly because I struggled getting the SDL one's to work.
Here is my code:
SDLInit.h
#pragma once
class sdl
public:
sdl();
sdl(sdl&& other) noexcept;
~sdl();
auto operator=(sdl&& other) noexcept->sdl&;
// Non-copyable
sdl(sdl const&) = delete;
auto operator=(sdl const&)->sdl& = delete;
friend void _swap(sdl& a, sdl& b) noexcept;
private:
bool _own = false;
;
class sdl_img
public:
sdl_img();
sdl_img(sdl_img&& other) noexcept;
~sdl_img();
auto operator=(sdl_img&& other) noexcept->sdl_img&;
// Non-copyable
sdl_img(sdl_img const&) = delete;
auto operator=(sdl_img const&)->sdl_img& = delete;
friend void _swap(sdl_img& a, sdl_img& b) noexcept;
private:
bool _own = false;
;
class sdl_ttf
public:
sdl_ttf();
sdl_ttf(sdl_ttf&& other) noexcept;
~sdl_ttf();
auto operator=(sdl_ttf&& other) noexcept->sdl_ttf&;
// Non-copyable
sdl_ttf(sdl_ttf const&) = delete;
auto operator=(sdl_ttf const&)->sdl_ttf& = delete;
friend void _swap(sdl_ttf& a, sdl_ttf& b) noexcept;
private:
bool _own = false;
;
SDLInit.cpp
#include <iostream>
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>
#include "SDLInit.h"
//Initialize SDL
sdl::sdl()
auto const result = SDL_Init(SDL_INIT_VIDEO);
if (result != 0)
std::cout << "SDL could not initialize";
sdl::sdl(sdl&& other) noexcept
_swap(*this, other);
sdl::~sdl()
if (_own)
SDL_Quit();
auto sdl::operator=(sdl&& other) noexcept -> sdl&
_swap(*this, other);
return *this;
void _swap(sdl& a, sdl& b) noexcept
using std::swap;
swap(a._own, b._own);
//Initialize SDL Image
sdl_img::sdl_img()
auto const result = IMG_Init(IMG_INIT_PNG);
if (result == 0)
std::cout << "SDL Image could not initialize";
sdl_img::sdl_img(sdl_img&& other) noexcept
_swap(*this, other);
sdl_img::~sdl_img()
if (_own)
IMG_Quit();
auto sdl_img::operator=(sdl_img&& other) noexcept -> sdl_img&
_swap(*this, other);
return *this;
void _swap(sdl_img& a, sdl_img& b) noexcept
using std::swap;
swap(a._own, b._own);
//Initialize SDL True Type Fonts
sdl_ttf::sdl_ttf()
auto const result = TTF_Init();
if (result != 0)
std::cout << "SDL TTF could not initialize";
sdl_ttf::sdl_ttf(sdl_ttf&& other) noexcept
_swap(*this, other);
sdl_ttf::~sdl_ttf()
if (_own)
TTF_Quit();
auto sdl_ttf::operator=(sdl_ttf&& other) noexcept -> sdl_ttf&
_swap(*this, other);
return *this;
void _swap(sdl_ttf& a, sdl_ttf& b) noexcept
using std::swap;
swap(a._own, b._own);
Main.cpp
#include <iostream>
#include <random>
#include <string>
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>
#include "SDLInit.h"
constexpr int SCREEN_WIDTH = 640;
constexpr int SCREEN_HEIGHT = 480;
SDL_Window* gWindow = nullptr;
SDL_Renderer* gRenderer = nullptr;
TTF_Font* gFont = nullptr;
enum class GameStates
MAIN_MENU,
MAIN_LOOP,
PLAY_AGAIN,
EXIT,
;
struct Game
int numberofGuesses = 0;
const int min = 1;
int max = 0;
int randomNumber = 0;
bool game_was_won = false;
;
std::mt19937& random_engine()
static std::mt19937 mersenne(std::random_device());
return mersenne;
int getRandomNumber(int x, int y)
std::uniform_int_distribution<> dist x,y ;
return dist(random_engine());
//used to tag how the texture was rendered
enum TextureType from_surface, from_text ;
class LTexture
public:
LTexture(TextureType type, SDL_Renderer* renderer, std::string const& path);
LTexture(TextureType type, SDL_Renderer* renderer, std::string const& text, SDL_Color color, int width);
LTexture(LTexture&& other) noexcept
swap(*this, other);
~LTexture();
void render(SDL_Renderer* renderer, int x, int y);
LTexture& operator=(LTexture&& other) noexcept
swap(*this, other);
return *this;
SDL_Texture* mTexture = nullptr;
int mWidth = 0;
int mHeight = 0;
SDL_Rect mButton = ;
LTexture(LTexture const&) = delete;
LTexture& operator=(LTexture const&) = delete;
friend void swap(LTexture& a, LTexture& b) noexcept;
;
LTexture::LTexture(TextureType type, SDL_Renderer* renderer, std::string const& path)
SDL_Surface *surface = IMG_Load(path.c_str());
if (!surface)
std::cout << "Failed to create surface";
mTexture = SDL_CreateTextureFromSurface(gRenderer, surface);
if (!mTexture)
std::cout << "Failed to create texture";
mWidth = surface->w;
mHeight = surface->h;
LTexture::LTexture(TextureType type, SDL_Renderer* renderer, std::string const& text, SDL_Color color, int width)
SDL_Surface* textSurface = TTF_RenderText_Blended_Wrapped(gFont, text.c_str(), color, width);
if (!textSurface)
std::cout << "Failed to create surface";
mTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
if (!mTexture)
std::cout << "Failed to created texture";
mWidth = textSurface->w;
mHeight = textSurface->h;
SDL_FreeSurface(textSurface);
void LTexture::render(SDL_Renderer* renderer, int x, int y)
SDL_Rect destRect = x, y, mWidth, mHeight ;
SDL_RenderCopy(renderer, mTexture, nullptr, &destRect);
//create a rectangle that coincides with texture to check for button presses
mButton = x, y, mWidth, mHeight ;
void swap(LTexture& a, LTexture& b) noexcept
using std::swap;
swap(a.mTexture, b.mTexture);
swap(a.mWidth, b.mWidth);
swap(a.mHeight, b.mHeight);
swap(a.mButton, b.mButton);
LTexture::~LTexture()
if (mTexture)
SDL_DestroyTexture(mTexture);
bool button_is_pressed(SDL_Event const& event, SDL_Rect const& button_rect)
if (event.type == SDL_MOUSEBUTTONDOWN)
auto const& mouse_button_event = event.button;
auto const mouse_position = SDL_Point mouse_button_event.x, mouse_button_event.y ;
return (mouse_button_event.button == SDL_BUTTON_LEFT) && SDL_PointInRect(&mouse_position, &button_rect);
return false;
// compare random number to guess player provided
int compare(int randomNumber, int guess)
if (randomNumber < guess)
return -1;
if (randomNumber > guess)
return 1;
return 0;
bool playAgain_input(GameStates& gameState, LTexture const& yesButton, LTexture const& noButton)
SDL_Event e;
while (SDL_PollEvent(&e) != 0)
button_is_pressed(e, noButton.mButton))
gameState = GameStates::EXIT;
return false;
if (button_is_pressed(e, yesButton.mButton))
gameState = GameStates::MAIN_MENU;
return false;
return true;
bool playAgain_update()
return true;
bool playAgain_render(LTexture& highLowTexture, LTexture& winlose, LTexture& playAgain, LTexture& yesButton, LTexture& noButton)
SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderClear(gRenderer);
highLowTexture.render(gRenderer, 0, 0);
winlose.render(gRenderer, 335, 70);
playAgain.render(gRenderer, 325, 300);
yesButton.render(gRenderer, 300, 350);
noButton.render(gRenderer, 300 + yesButton.mWidth + 10, 350);
SDL_RenderPresent(gRenderer);
return true;
void playAgain(GameStates& gameState, Game game)
SDL_Color const textColor = 0,0,0 ;
auto const textWidth = 250;
auto highLowTexture = LTexture(from_surface, gRenderer, "Resources/HiLo.png");
auto playAgain = LTexture(from_text, gRenderer, "Play Again?", textColor, textWidth);
auto yesButton = LTexture from_surface, gRenderer, "Resources/HiLoYes.png" ;
auto noButton = LTexture from_surface, gRenderer, "Resources/HiLoNo.png" ;
std::string dialogue;
//change dialogue based on if player won or not
if (game.game_was_won)
dialogue = "YOU WON!!! The correct answer was " + std::to_string(game.randomNumber) + ".";
else
dialogue = "You lose. The correct answer was " + std::to_string(game.randomNumber) + ".";
auto winlose = LTexture from_text, gRenderer, dialogue, textColor, textWidth ;
while (playAgain_input(gameState, yesButton, noButton) && playAgain_update() && playAgain_render(highLowTexture, winlose, playAgain, yesButton, noButton))
bool gameLoop_input(GameStates& gameState, std::string& guessInput, int& guess, int& guessCount)
SDL_Event e;
SDL_StartTextInput();
while (SDL_PollEvent(&e) != 0)
if (e.type == SDL_QUIT)
gameState = GameStates::EXIT;
return false;
if (e.type == SDL_TEXTINPUT)
if (e.type == SDL_KEYDOWN)
e.key.keysym.sym == SDLK_KP_ENTER)
//if input is not empty
if (guessInput != " ")
//convert guess to int
guess = stoi(guessInput);
//reset string
guessInput = " ";
++guessCount;
else if (e.key.keysym.sym == SDLK_BACKSPACE && guessInput.length() > 0)
guessInput.pop_back();
SDL_StopTextInput();
return true;
bool gameLoop_update(GameStates& gameState, std::string& dialogue, int guess, int guessCount, Game& game)
if (guessCount == 0)
dialogue = "I'm thinking of a number between " + std::to_string(game.min) + " and " + std::to_string(game.max) + ". You have " + std::to_string(game.numberofGuesses) + " guesses.";
// if player ran out of moves
else if (guessCount == game.numberofGuesses)
game.game_was_won = false;
gameState = GameStates::PLAY_AGAIN;
return false;
else
int cmp = compare(game.randomNumber, guess);
//change dialogue based on comparison
if (cmp > 0)
dialogue = "Your guess was too low.";
else if (cmp < 0)
dialogue = "Your guess was too high.";
else
game.game_was_won = true;
gameState = GameStates::PLAY_AGAIN;
return false;
return true;
bool gameLoop_render(LTexture& highLowTexture, LTexture& guessPrompt, std::string guessInput, std::string dialogue, SDL_Color textColor, int textWidth, int guessCount, Game game)
SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderClear(gRenderer);
highLowTexture.render(gRenderer, 0, 0);
guessPrompt.render(gRenderer, 350, 250);
auto bubbleText = LTexture(from_text, gRenderer, dialogue, textColor, textWidth);
bubbleText.render(gRenderer, 335, 70);
auto guessCounter = LTexture(from_text, gRenderer, "Guesses remaining: " + std::to_string(game.numberofGuesses - guessCount), textColor, textWidth);
guessCounter.render(gRenderer, 350, 200);
auto inputTexture = LTexture(from_text, gRenderer, guessInput, textColor, textWidth);
if (guessInput == "")
inputTexture = LTexture(from_text, gRenderer, " ", textColor, textWidth);
inputTexture.render(gRenderer, 350 + guessPrompt.mWidth, textWidth);
SDL_RenderPresent(gRenderer);
return true;
void gameLoop(GameStates& gameState, Game& game)
std::string guessInput = " ";
std::string dialogue = " ";
SDL_Color const textColor = 0,0,0 ;
auto const textWidth = 250;
auto highLowTexture = LTexture(from_surface, gRenderer, "Resources/HiLo.png");
auto guessPrompt = LTexture(from_text, gRenderer, "Enter a number:", textColor, textWidth);
int guessCount = 0;
int guess = 0;
while (gameLoop_input(gameState, guessInput, guess, guessCount) &&
gameLoop_update(gameState, dialogue, guess, guessCount, game) &&
gameLoop_render(highLowTexture, guessPrompt, guessInput, dialogue, textColor, textWidth, guessCount, game))
bool mainMenu_input(GameStates& gameState, Game& game, LTexture& tenButton, LTexture& hundredButton, LTexture& thousandButton)
SDL_Event e;
while (SDL_PollEvent(&e) != 0)
if (e.type == SDL_QUIT)
gameState = GameStates::EXIT;
return false;
//change game settings based on button
if (button_is_pressed(e, tenButton.mButton))
game.numberofGuesses = 5;
game.max = 10;
game.randomNumber = getRandomNumber(game.min, game.max);
gameState = GameStates::MAIN_LOOP;
//used to make sure game works properly
std::cout << game.randomNumber;
return false;
else if (button_is_pressed(e, hundredButton.mButton))
game.numberofGuesses = 7;
game.max = 100;
game.randomNumber = getRandomNumber(game.min, game.max);
gameState = GameStates::MAIN_LOOP;
std::cout << game.randomNumber;
return false;
else if (button_is_pressed(e, thousandButton.mButton))
game.numberofGuesses = 9;
game.max = 1000;
game.randomNumber = getRandomNumber(game.min, game.max);
gameState = GameStates::MAIN_LOOP;
std::cout << game.randomNumber;
return false;
return true;
bool mainMenu_update()
return true;
bool mainMenu_render(LTexture& menuTexture, LTexture& tenButton, LTexture& hundredButton, LTexture& thousandButton)
SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderClear(gRenderer);
menuTexture.render(gRenderer, 0, 0);
tenButton.render(gRenderer, (SCREEN_WIDTH / 2) - (tenButton.mWidth / 2), 175);
hundredButton.render(gRenderer, (SCREEN_WIDTH / 2) - (tenButton.mWidth / 2), 225);
thousandButton.render(gRenderer, (SCREEN_WIDTH / 2) - (tenButton.mWidth / 2), 275);
SDL_RenderPresent(gRenderer);
return true;
void mainMenu(GameStates& gameState, Game& game)
auto menuTexture = LTexture(from_surface, gRenderer, "Resources/HiLoMenu.png");
auto tenButton = LTexture(from_surface, gRenderer, "Resources/HiLo10.png");
auto hundredButton = LTexture(from_surface, gRenderer, "Resources/HiLo100.png");
auto thousandButton = LTexture(from_surface, gRenderer, "Resources/HiLo1000.png");
while (mainMenu_input(gameState, game, tenButton, hundredButton, thousandButton) &&
mainMenu_update() &&
mainMenu_render(menuTexture, tenButton, hundredButton, thousandButton))
void init()
SDL_RENDERER_PRESENTVSYNC);
if (gRenderer == nullptr)
std::cout << "Failed to create renderer";
gFont = TTF_OpenFont("Resources/opensans.ttf", 20);
if (gFont == nullptr)
std::cout << "Failed to open font";
void close()
if (gFont)
TTF_CloseFont(gFont);
if (gWindow)
SDL_DestroyWindow(gWindow);
if (gRenderer)
SDL_DestroyRenderer(gRenderer);
int main(int argc, char* args)
init();
GameStates gameState = GameStates::MAIN_MENU;
Game game;
while (gameState != GameStates::EXIT)
switch (gameState)
case GameStates::MAIN_MENU:
mainMenu(gameState, game);
break;
case GameStates::MAIN_LOOP:
gameLoop(gameState, game);
break;
case GameStates::PLAY_AGAIN:
playAgain(gameState, game);
break;
close();
return 0;
I know I still have a lot to learn, but any additional feedback would be greatly appreciated.
I also have a few more questions:
I was previously told that my code looks very "C-ish". If it still is, what makes it "C-ish"? I probably just don't know enough about the difference between the two to really tell.
What is the difference between doing something like
sdl sdlinit;
andauto sdlinit = sdl
? Additionally, how do you determine when to use auto and when to specify?
Thanks again for your time.
c++ sdl
add a comment |Â
up vote
3
down vote
favorite
So after getting a very thorough review and feedback from indi in my previous attempt, SDL/C++ High-Low Guessing Game, I decided to go through the game and fix as many mistakes as I could. But going through the feedback also just opened up even more questions.
Things I was unable to do
Get rid of all global variables. I was able to remove or move most of the global variables, but I had an issue with the
SDL_Window*
,SDL_Renderer
, andTTF_Font
. It was suggested that I used astd::unique_ptr
, so I made the window astd::unique_ptr
, but I was unable to use that window as a parameter for creating the renderer because there was no suitable conversion from astd::unique_ptr
to aSDL_Window*
. Thus I just kept them in global until I can figure out how to make it work.Use the struct "tags" for my
LTexture
class. It was suggested to usestruct from_surface_tag from_surface;
andstruct from_text_tag from_text;
to indicate which version of the constructor I was using. The compiler just kept saying thatfrom_text
orfrom_surface
were undefined. I realize that there mainly for the reader of the code, so I just made anenum
to use as the tags.Used the state machine that was suggested. I make the engine that was suggested, but I failed miserably. Instead I created a very basic state machine that hopefully works and gets rid of the
playAgain -> mainMenu -> playAgain
loop. Hopefully I'll be able to understand how to other one once I get more experience.Lastly, I did not make not make the
LTexture
class it's own file, mainly because I struggled getting the SDL one's to work.
Here is my code:
SDLInit.h
#pragma once
class sdl
public:
sdl();
sdl(sdl&& other) noexcept;
~sdl();
auto operator=(sdl&& other) noexcept->sdl&;
// Non-copyable
sdl(sdl const&) = delete;
auto operator=(sdl const&)->sdl& = delete;
friend void _swap(sdl& a, sdl& b) noexcept;
private:
bool _own = false;
;
class sdl_img
public:
sdl_img();
sdl_img(sdl_img&& other) noexcept;
~sdl_img();
auto operator=(sdl_img&& other) noexcept->sdl_img&;
// Non-copyable
sdl_img(sdl_img const&) = delete;
auto operator=(sdl_img const&)->sdl_img& = delete;
friend void _swap(sdl_img& a, sdl_img& b) noexcept;
private:
bool _own = false;
;
class sdl_ttf
public:
sdl_ttf();
sdl_ttf(sdl_ttf&& other) noexcept;
~sdl_ttf();
auto operator=(sdl_ttf&& other) noexcept->sdl_ttf&;
// Non-copyable
sdl_ttf(sdl_ttf const&) = delete;
auto operator=(sdl_ttf const&)->sdl_ttf& = delete;
friend void _swap(sdl_ttf& a, sdl_ttf& b) noexcept;
private:
bool _own = false;
;
SDLInit.cpp
#include <iostream>
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>
#include "SDLInit.h"
//Initialize SDL
sdl::sdl()
auto const result = SDL_Init(SDL_INIT_VIDEO);
if (result != 0)
std::cout << "SDL could not initialize";
sdl::sdl(sdl&& other) noexcept
_swap(*this, other);
sdl::~sdl()
if (_own)
SDL_Quit();
auto sdl::operator=(sdl&& other) noexcept -> sdl&
_swap(*this, other);
return *this;
void _swap(sdl& a, sdl& b) noexcept
using std::swap;
swap(a._own, b._own);
//Initialize SDL Image
sdl_img::sdl_img()
auto const result = IMG_Init(IMG_INIT_PNG);
if (result == 0)
std::cout << "SDL Image could not initialize";
sdl_img::sdl_img(sdl_img&& other) noexcept
_swap(*this, other);
sdl_img::~sdl_img()
if (_own)
IMG_Quit();
auto sdl_img::operator=(sdl_img&& other) noexcept -> sdl_img&
_swap(*this, other);
return *this;
void _swap(sdl_img& a, sdl_img& b) noexcept
using std::swap;
swap(a._own, b._own);
//Initialize SDL True Type Fonts
sdl_ttf::sdl_ttf()
auto const result = TTF_Init();
if (result != 0)
std::cout << "SDL TTF could not initialize";
sdl_ttf::sdl_ttf(sdl_ttf&& other) noexcept
_swap(*this, other);
sdl_ttf::~sdl_ttf()
if (_own)
TTF_Quit();
auto sdl_ttf::operator=(sdl_ttf&& other) noexcept -> sdl_ttf&
_swap(*this, other);
return *this;
void _swap(sdl_ttf& a, sdl_ttf& b) noexcept
using std::swap;
swap(a._own, b._own);
Main.cpp
#include <iostream>
#include <random>
#include <string>
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>
#include "SDLInit.h"
constexpr int SCREEN_WIDTH = 640;
constexpr int SCREEN_HEIGHT = 480;
SDL_Window* gWindow = nullptr;
SDL_Renderer* gRenderer = nullptr;
TTF_Font* gFont = nullptr;
enum class GameStates
MAIN_MENU,
MAIN_LOOP,
PLAY_AGAIN,
EXIT,
;
struct Game
int numberofGuesses = 0;
const int min = 1;
int max = 0;
int randomNumber = 0;
bool game_was_won = false;
;
std::mt19937& random_engine()
static std::mt19937 mersenne(std::random_device());
return mersenne;
int getRandomNumber(int x, int y)
std::uniform_int_distribution<> dist x,y ;
return dist(random_engine());
//used to tag how the texture was rendered
enum TextureType from_surface, from_text ;
class LTexture
public:
LTexture(TextureType type, SDL_Renderer* renderer, std::string const& path);
LTexture(TextureType type, SDL_Renderer* renderer, std::string const& text, SDL_Color color, int width);
LTexture(LTexture&& other) noexcept
swap(*this, other);
~LTexture();
void render(SDL_Renderer* renderer, int x, int y);
LTexture& operator=(LTexture&& other) noexcept
swap(*this, other);
return *this;
SDL_Texture* mTexture = nullptr;
int mWidth = 0;
int mHeight = 0;
SDL_Rect mButton = ;
LTexture(LTexture const&) = delete;
LTexture& operator=(LTexture const&) = delete;
friend void swap(LTexture& a, LTexture& b) noexcept;
;
LTexture::LTexture(TextureType type, SDL_Renderer* renderer, std::string const& path)
SDL_Surface *surface = IMG_Load(path.c_str());
if (!surface)
std::cout << "Failed to create surface";
mTexture = SDL_CreateTextureFromSurface(gRenderer, surface);
if (!mTexture)
std::cout << "Failed to create texture";
mWidth = surface->w;
mHeight = surface->h;
LTexture::LTexture(TextureType type, SDL_Renderer* renderer, std::string const& text, SDL_Color color, int width)
SDL_Surface* textSurface = TTF_RenderText_Blended_Wrapped(gFont, text.c_str(), color, width);
if (!textSurface)
std::cout << "Failed to create surface";
mTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
if (!mTexture)
std::cout << "Failed to created texture";
mWidth = textSurface->w;
mHeight = textSurface->h;
SDL_FreeSurface(textSurface);
void LTexture::render(SDL_Renderer* renderer, int x, int y)
SDL_Rect destRect = x, y, mWidth, mHeight ;
SDL_RenderCopy(renderer, mTexture, nullptr, &destRect);
//create a rectangle that coincides with texture to check for button presses
mButton = x, y, mWidth, mHeight ;
void swap(LTexture& a, LTexture& b) noexcept
using std::swap;
swap(a.mTexture, b.mTexture);
swap(a.mWidth, b.mWidth);
swap(a.mHeight, b.mHeight);
swap(a.mButton, b.mButton);
LTexture::~LTexture()
if (mTexture)
SDL_DestroyTexture(mTexture);
bool button_is_pressed(SDL_Event const& event, SDL_Rect const& button_rect)
if (event.type == SDL_MOUSEBUTTONDOWN)
auto const& mouse_button_event = event.button;
auto const mouse_position = SDL_Point mouse_button_event.x, mouse_button_event.y ;
return (mouse_button_event.button == SDL_BUTTON_LEFT) && SDL_PointInRect(&mouse_position, &button_rect);
return false;
// compare random number to guess player provided
int compare(int randomNumber, int guess)
if (randomNumber < guess)
return -1;
if (randomNumber > guess)
return 1;
return 0;
bool playAgain_input(GameStates& gameState, LTexture const& yesButton, LTexture const& noButton)
SDL_Event e;
while (SDL_PollEvent(&e) != 0)
button_is_pressed(e, noButton.mButton))
gameState = GameStates::EXIT;
return false;
if (button_is_pressed(e, yesButton.mButton))
gameState = GameStates::MAIN_MENU;
return false;
return true;
bool playAgain_update()
return true;
bool playAgain_render(LTexture& highLowTexture, LTexture& winlose, LTexture& playAgain, LTexture& yesButton, LTexture& noButton)
SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderClear(gRenderer);
highLowTexture.render(gRenderer, 0, 0);
winlose.render(gRenderer, 335, 70);
playAgain.render(gRenderer, 325, 300);
yesButton.render(gRenderer, 300, 350);
noButton.render(gRenderer, 300 + yesButton.mWidth + 10, 350);
SDL_RenderPresent(gRenderer);
return true;
void playAgain(GameStates& gameState, Game game)
SDL_Color const textColor = 0,0,0 ;
auto const textWidth = 250;
auto highLowTexture = LTexture(from_surface, gRenderer, "Resources/HiLo.png");
auto playAgain = LTexture(from_text, gRenderer, "Play Again?", textColor, textWidth);
auto yesButton = LTexture from_surface, gRenderer, "Resources/HiLoYes.png" ;
auto noButton = LTexture from_surface, gRenderer, "Resources/HiLoNo.png" ;
std::string dialogue;
//change dialogue based on if player won or not
if (game.game_was_won)
dialogue = "YOU WON!!! The correct answer was " + std::to_string(game.randomNumber) + ".";
else
dialogue = "You lose. The correct answer was " + std::to_string(game.randomNumber) + ".";
auto winlose = LTexture from_text, gRenderer, dialogue, textColor, textWidth ;
while (playAgain_input(gameState, yesButton, noButton) && playAgain_update() && playAgain_render(highLowTexture, winlose, playAgain, yesButton, noButton))
bool gameLoop_input(GameStates& gameState, std::string& guessInput, int& guess, int& guessCount)
SDL_Event e;
SDL_StartTextInput();
while (SDL_PollEvent(&e) != 0)
if (e.type == SDL_QUIT)
gameState = GameStates::EXIT;
return false;
if (e.type == SDL_TEXTINPUT)
if (e.type == SDL_KEYDOWN)
e.key.keysym.sym == SDLK_KP_ENTER)
//if input is not empty
if (guessInput != " ")
//convert guess to int
guess = stoi(guessInput);
//reset string
guessInput = " ";
++guessCount;
else if (e.key.keysym.sym == SDLK_BACKSPACE && guessInput.length() > 0)
guessInput.pop_back();
SDL_StopTextInput();
return true;
bool gameLoop_update(GameStates& gameState, std::string& dialogue, int guess, int guessCount, Game& game)
if (guessCount == 0)
dialogue = "I'm thinking of a number between " + std::to_string(game.min) + " and " + std::to_string(game.max) + ". You have " + std::to_string(game.numberofGuesses) + " guesses.";
// if player ran out of moves
else if (guessCount == game.numberofGuesses)
game.game_was_won = false;
gameState = GameStates::PLAY_AGAIN;
return false;
else
int cmp = compare(game.randomNumber, guess);
//change dialogue based on comparison
if (cmp > 0)
dialogue = "Your guess was too low.";
else if (cmp < 0)
dialogue = "Your guess was too high.";
else
game.game_was_won = true;
gameState = GameStates::PLAY_AGAIN;
return false;
return true;
bool gameLoop_render(LTexture& highLowTexture, LTexture& guessPrompt, std::string guessInput, std::string dialogue, SDL_Color textColor, int textWidth, int guessCount, Game game)
SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderClear(gRenderer);
highLowTexture.render(gRenderer, 0, 0);
guessPrompt.render(gRenderer, 350, 250);
auto bubbleText = LTexture(from_text, gRenderer, dialogue, textColor, textWidth);
bubbleText.render(gRenderer, 335, 70);
auto guessCounter = LTexture(from_text, gRenderer, "Guesses remaining: " + std::to_string(game.numberofGuesses - guessCount), textColor, textWidth);
guessCounter.render(gRenderer, 350, 200);
auto inputTexture = LTexture(from_text, gRenderer, guessInput, textColor, textWidth);
if (guessInput == "")
inputTexture = LTexture(from_text, gRenderer, " ", textColor, textWidth);
inputTexture.render(gRenderer, 350 + guessPrompt.mWidth, textWidth);
SDL_RenderPresent(gRenderer);
return true;
void gameLoop(GameStates& gameState, Game& game)
std::string guessInput = " ";
std::string dialogue = " ";
SDL_Color const textColor = 0,0,0 ;
auto const textWidth = 250;
auto highLowTexture = LTexture(from_surface, gRenderer, "Resources/HiLo.png");
auto guessPrompt = LTexture(from_text, gRenderer, "Enter a number:", textColor, textWidth);
int guessCount = 0;
int guess = 0;
while (gameLoop_input(gameState, guessInput, guess, guessCount) &&
gameLoop_update(gameState, dialogue, guess, guessCount, game) &&
gameLoop_render(highLowTexture, guessPrompt, guessInput, dialogue, textColor, textWidth, guessCount, game))
bool mainMenu_input(GameStates& gameState, Game& game, LTexture& tenButton, LTexture& hundredButton, LTexture& thousandButton)
SDL_Event e;
while (SDL_PollEvent(&e) != 0)
if (e.type == SDL_QUIT)
gameState = GameStates::EXIT;
return false;
//change game settings based on button
if (button_is_pressed(e, tenButton.mButton))
game.numberofGuesses = 5;
game.max = 10;
game.randomNumber = getRandomNumber(game.min, game.max);
gameState = GameStates::MAIN_LOOP;
//used to make sure game works properly
std::cout << game.randomNumber;
return false;
else if (button_is_pressed(e, hundredButton.mButton))
game.numberofGuesses = 7;
game.max = 100;
game.randomNumber = getRandomNumber(game.min, game.max);
gameState = GameStates::MAIN_LOOP;
std::cout << game.randomNumber;
return false;
else if (button_is_pressed(e, thousandButton.mButton))
game.numberofGuesses = 9;
game.max = 1000;
game.randomNumber = getRandomNumber(game.min, game.max);
gameState = GameStates::MAIN_LOOP;
std::cout << game.randomNumber;
return false;
return true;
bool mainMenu_update()
return true;
bool mainMenu_render(LTexture& menuTexture, LTexture& tenButton, LTexture& hundredButton, LTexture& thousandButton)
SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderClear(gRenderer);
menuTexture.render(gRenderer, 0, 0);
tenButton.render(gRenderer, (SCREEN_WIDTH / 2) - (tenButton.mWidth / 2), 175);
hundredButton.render(gRenderer, (SCREEN_WIDTH / 2) - (tenButton.mWidth / 2), 225);
thousandButton.render(gRenderer, (SCREEN_WIDTH / 2) - (tenButton.mWidth / 2), 275);
SDL_RenderPresent(gRenderer);
return true;
void mainMenu(GameStates& gameState, Game& game)
auto menuTexture = LTexture(from_surface, gRenderer, "Resources/HiLoMenu.png");
auto tenButton = LTexture(from_surface, gRenderer, "Resources/HiLo10.png");
auto hundredButton = LTexture(from_surface, gRenderer, "Resources/HiLo100.png");
auto thousandButton = LTexture(from_surface, gRenderer, "Resources/HiLo1000.png");
while (mainMenu_input(gameState, game, tenButton, hundredButton, thousandButton) &&
mainMenu_update() &&
mainMenu_render(menuTexture, tenButton, hundredButton, thousandButton))
void init()
SDL_RENDERER_PRESENTVSYNC);
if (gRenderer == nullptr)
std::cout << "Failed to create renderer";
gFont = TTF_OpenFont("Resources/opensans.ttf", 20);
if (gFont == nullptr)
std::cout << "Failed to open font";
void close()
if (gFont)
TTF_CloseFont(gFont);
if (gWindow)
SDL_DestroyWindow(gWindow);
if (gRenderer)
SDL_DestroyRenderer(gRenderer);
int main(int argc, char* args)
init();
GameStates gameState = GameStates::MAIN_MENU;
Game game;
while (gameState != GameStates::EXIT)
switch (gameState)
case GameStates::MAIN_MENU:
mainMenu(gameState, game);
break;
case GameStates::MAIN_LOOP:
gameLoop(gameState, game);
break;
case GameStates::PLAY_AGAIN:
playAgain(gameState, game);
break;
close();
return 0;
I know I still have a lot to learn, but any additional feedback would be greatly appreciated.
I also have a few more questions:
I was previously told that my code looks very "C-ish". If it still is, what makes it "C-ish"? I probably just don't know enough about the difference between the two to really tell.
What is the difference between doing something like
sdl sdlinit;
andauto sdlinit = sdl
? Additionally, how do you determine when to use auto and when to specify?
Thanks again for your time.
c++ sdl
You should flag a moderator and request your accounts be merged
â bruglesco
Aug 1 at 4:02
Regardingauto
usage, have a look at this quite good answer which hopefully makes things a bit clearer.
â yuri
Aug 1 at 6:17
The correct way of using smart ptr for Window & Renderer is :std::unique_ptr<SDL_Window, void(*)(SDL_Window*)> window(SDL_CreateWindow(...), SDL_DestroyWindow);
std::unique_ptr<SDL_Renderer, void(*)(SDL_Renderer*)> renderer(SDL_CreateRenderer(window.get(), ...), SDL_DestroyRenderer);
Then you usewindow.get()
which returnsSDL_Window*
, andrenderer.get()
which returnsSDL_Renderer*
.
â Julien Vernay
Aug 1 at 21:10
add a comment |Â
up vote
3
down vote
favorite
up vote
3
down vote
favorite
So after getting a very thorough review and feedback from indi in my previous attempt, SDL/C++ High-Low Guessing Game, I decided to go through the game and fix as many mistakes as I could. But going through the feedback also just opened up even more questions.
Things I was unable to do
Get rid of all global variables. I was able to remove or move most of the global variables, but I had an issue with the
SDL_Window*
,SDL_Renderer
, andTTF_Font
. It was suggested that I used astd::unique_ptr
, so I made the window astd::unique_ptr
, but I was unable to use that window as a parameter for creating the renderer because there was no suitable conversion from astd::unique_ptr
to aSDL_Window*
. Thus I just kept them in global until I can figure out how to make it work.Use the struct "tags" for my
LTexture
class. It was suggested to usestruct from_surface_tag from_surface;
andstruct from_text_tag from_text;
to indicate which version of the constructor I was using. The compiler just kept saying thatfrom_text
orfrom_surface
were undefined. I realize that there mainly for the reader of the code, so I just made anenum
to use as the tags.Used the state machine that was suggested. I make the engine that was suggested, but I failed miserably. Instead I created a very basic state machine that hopefully works and gets rid of the
playAgain -> mainMenu -> playAgain
loop. Hopefully I'll be able to understand how to other one once I get more experience.Lastly, I did not make not make the
LTexture
class it's own file, mainly because I struggled getting the SDL one's to work.
Here is my code:
SDLInit.h
#pragma once
class sdl
public:
sdl();
sdl(sdl&& other) noexcept;
~sdl();
auto operator=(sdl&& other) noexcept->sdl&;
// Non-copyable
sdl(sdl const&) = delete;
auto operator=(sdl const&)->sdl& = delete;
friend void _swap(sdl& a, sdl& b) noexcept;
private:
bool _own = false;
;
class sdl_img
public:
sdl_img();
sdl_img(sdl_img&& other) noexcept;
~sdl_img();
auto operator=(sdl_img&& other) noexcept->sdl_img&;
// Non-copyable
sdl_img(sdl_img const&) = delete;
auto operator=(sdl_img const&)->sdl_img& = delete;
friend void _swap(sdl_img& a, sdl_img& b) noexcept;
private:
bool _own = false;
;
class sdl_ttf
public:
sdl_ttf();
sdl_ttf(sdl_ttf&& other) noexcept;
~sdl_ttf();
auto operator=(sdl_ttf&& other) noexcept->sdl_ttf&;
// Non-copyable
sdl_ttf(sdl_ttf const&) = delete;
auto operator=(sdl_ttf const&)->sdl_ttf& = delete;
friend void _swap(sdl_ttf& a, sdl_ttf& b) noexcept;
private:
bool _own = false;
;
SDLInit.cpp
#include <iostream>
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>
#include "SDLInit.h"
//Initialize SDL
sdl::sdl()
auto const result = SDL_Init(SDL_INIT_VIDEO);
if (result != 0)
std::cout << "SDL could not initialize";
sdl::sdl(sdl&& other) noexcept
_swap(*this, other);
sdl::~sdl()
if (_own)
SDL_Quit();
auto sdl::operator=(sdl&& other) noexcept -> sdl&
_swap(*this, other);
return *this;
void _swap(sdl& a, sdl& b) noexcept
using std::swap;
swap(a._own, b._own);
//Initialize SDL Image
sdl_img::sdl_img()
auto const result = IMG_Init(IMG_INIT_PNG);
if (result == 0)
std::cout << "SDL Image could not initialize";
sdl_img::sdl_img(sdl_img&& other) noexcept
_swap(*this, other);
sdl_img::~sdl_img()
if (_own)
IMG_Quit();
auto sdl_img::operator=(sdl_img&& other) noexcept -> sdl_img&
_swap(*this, other);
return *this;
void _swap(sdl_img& a, sdl_img& b) noexcept
using std::swap;
swap(a._own, b._own);
//Initialize SDL True Type Fonts
sdl_ttf::sdl_ttf()
auto const result = TTF_Init();
if (result != 0)
std::cout << "SDL TTF could not initialize";
sdl_ttf::sdl_ttf(sdl_ttf&& other) noexcept
_swap(*this, other);
sdl_ttf::~sdl_ttf()
if (_own)
TTF_Quit();
auto sdl_ttf::operator=(sdl_ttf&& other) noexcept -> sdl_ttf&
_swap(*this, other);
return *this;
void _swap(sdl_ttf& a, sdl_ttf& b) noexcept
using std::swap;
swap(a._own, b._own);
Main.cpp
#include <iostream>
#include <random>
#include <string>
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>
#include "SDLInit.h"
constexpr int SCREEN_WIDTH = 640;
constexpr int SCREEN_HEIGHT = 480;
SDL_Window* gWindow = nullptr;
SDL_Renderer* gRenderer = nullptr;
TTF_Font* gFont = nullptr;
enum class GameStates
MAIN_MENU,
MAIN_LOOP,
PLAY_AGAIN,
EXIT,
;
struct Game
int numberofGuesses = 0;
const int min = 1;
int max = 0;
int randomNumber = 0;
bool game_was_won = false;
;
std::mt19937& random_engine()
static std::mt19937 mersenne(std::random_device());
return mersenne;
int getRandomNumber(int x, int y)
std::uniform_int_distribution<> dist x,y ;
return dist(random_engine());
//used to tag how the texture was rendered
enum TextureType from_surface, from_text ;
class LTexture
public:
LTexture(TextureType type, SDL_Renderer* renderer, std::string const& path);
LTexture(TextureType type, SDL_Renderer* renderer, std::string const& text, SDL_Color color, int width);
LTexture(LTexture&& other) noexcept
swap(*this, other);
~LTexture();
void render(SDL_Renderer* renderer, int x, int y);
LTexture& operator=(LTexture&& other) noexcept
swap(*this, other);
return *this;
SDL_Texture* mTexture = nullptr;
int mWidth = 0;
int mHeight = 0;
SDL_Rect mButton = ;
LTexture(LTexture const&) = delete;
LTexture& operator=(LTexture const&) = delete;
friend void swap(LTexture& a, LTexture& b) noexcept;
;
LTexture::LTexture(TextureType type, SDL_Renderer* renderer, std::string const& path)
SDL_Surface *surface = IMG_Load(path.c_str());
if (!surface)
std::cout << "Failed to create surface";
mTexture = SDL_CreateTextureFromSurface(gRenderer, surface);
if (!mTexture)
std::cout << "Failed to create texture";
mWidth = surface->w;
mHeight = surface->h;
LTexture::LTexture(TextureType type, SDL_Renderer* renderer, std::string const& text, SDL_Color color, int width)
SDL_Surface* textSurface = TTF_RenderText_Blended_Wrapped(gFont, text.c_str(), color, width);
if (!textSurface)
std::cout << "Failed to create surface";
mTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
if (!mTexture)
std::cout << "Failed to created texture";
mWidth = textSurface->w;
mHeight = textSurface->h;
SDL_FreeSurface(textSurface);
void LTexture::render(SDL_Renderer* renderer, int x, int y)
SDL_Rect destRect = x, y, mWidth, mHeight ;
SDL_RenderCopy(renderer, mTexture, nullptr, &destRect);
//create a rectangle that coincides with texture to check for button presses
mButton = x, y, mWidth, mHeight ;
void swap(LTexture& a, LTexture& b) noexcept
using std::swap;
swap(a.mTexture, b.mTexture);
swap(a.mWidth, b.mWidth);
swap(a.mHeight, b.mHeight);
swap(a.mButton, b.mButton);
LTexture::~LTexture()
if (mTexture)
SDL_DestroyTexture(mTexture);
bool button_is_pressed(SDL_Event const& event, SDL_Rect const& button_rect)
if (event.type == SDL_MOUSEBUTTONDOWN)
auto const& mouse_button_event = event.button;
auto const mouse_position = SDL_Point mouse_button_event.x, mouse_button_event.y ;
return (mouse_button_event.button == SDL_BUTTON_LEFT) && SDL_PointInRect(&mouse_position, &button_rect);
return false;
// compare random number to guess player provided
int compare(int randomNumber, int guess)
if (randomNumber < guess)
return -1;
if (randomNumber > guess)
return 1;
return 0;
bool playAgain_input(GameStates& gameState, LTexture const& yesButton, LTexture const& noButton)
SDL_Event e;
while (SDL_PollEvent(&e) != 0)
button_is_pressed(e, noButton.mButton))
gameState = GameStates::EXIT;
return false;
if (button_is_pressed(e, yesButton.mButton))
gameState = GameStates::MAIN_MENU;
return false;
return true;
bool playAgain_update()
return true;
bool playAgain_render(LTexture& highLowTexture, LTexture& winlose, LTexture& playAgain, LTexture& yesButton, LTexture& noButton)
SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderClear(gRenderer);
highLowTexture.render(gRenderer, 0, 0);
winlose.render(gRenderer, 335, 70);
playAgain.render(gRenderer, 325, 300);
yesButton.render(gRenderer, 300, 350);
noButton.render(gRenderer, 300 + yesButton.mWidth + 10, 350);
SDL_RenderPresent(gRenderer);
return true;
void playAgain(GameStates& gameState, Game game)
SDL_Color const textColor = 0,0,0 ;
auto const textWidth = 250;
auto highLowTexture = LTexture(from_surface, gRenderer, "Resources/HiLo.png");
auto playAgain = LTexture(from_text, gRenderer, "Play Again?", textColor, textWidth);
auto yesButton = LTexture from_surface, gRenderer, "Resources/HiLoYes.png" ;
auto noButton = LTexture from_surface, gRenderer, "Resources/HiLoNo.png" ;
std::string dialogue;
//change dialogue based on if player won or not
if (game.game_was_won)
dialogue = "YOU WON!!! The correct answer was " + std::to_string(game.randomNumber) + ".";
else
dialogue = "You lose. The correct answer was " + std::to_string(game.randomNumber) + ".";
auto winlose = LTexture from_text, gRenderer, dialogue, textColor, textWidth ;
while (playAgain_input(gameState, yesButton, noButton) && playAgain_update() && playAgain_render(highLowTexture, winlose, playAgain, yesButton, noButton))
bool gameLoop_input(GameStates& gameState, std::string& guessInput, int& guess, int& guessCount)
SDL_Event e;
SDL_StartTextInput();
while (SDL_PollEvent(&e) != 0)
if (e.type == SDL_QUIT)
gameState = GameStates::EXIT;
return false;
if (e.type == SDL_TEXTINPUT)
if (e.type == SDL_KEYDOWN)
e.key.keysym.sym == SDLK_KP_ENTER)
//if input is not empty
if (guessInput != " ")
//convert guess to int
guess = stoi(guessInput);
//reset string
guessInput = " ";
++guessCount;
else if (e.key.keysym.sym == SDLK_BACKSPACE && guessInput.length() > 0)
guessInput.pop_back();
SDL_StopTextInput();
return true;
bool gameLoop_update(GameStates& gameState, std::string& dialogue, int guess, int guessCount, Game& game)
if (guessCount == 0)
dialogue = "I'm thinking of a number between " + std::to_string(game.min) + " and " + std::to_string(game.max) + ". You have " + std::to_string(game.numberofGuesses) + " guesses.";
// if player ran out of moves
else if (guessCount == game.numberofGuesses)
game.game_was_won = false;
gameState = GameStates::PLAY_AGAIN;
return false;
else
int cmp = compare(game.randomNumber, guess);
//change dialogue based on comparison
if (cmp > 0)
dialogue = "Your guess was too low.";
else if (cmp < 0)
dialogue = "Your guess was too high.";
else
game.game_was_won = true;
gameState = GameStates::PLAY_AGAIN;
return false;
return true;
bool gameLoop_render(LTexture& highLowTexture, LTexture& guessPrompt, std::string guessInput, std::string dialogue, SDL_Color textColor, int textWidth, int guessCount, Game game)
SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderClear(gRenderer);
highLowTexture.render(gRenderer, 0, 0);
guessPrompt.render(gRenderer, 350, 250);
auto bubbleText = LTexture(from_text, gRenderer, dialogue, textColor, textWidth);
bubbleText.render(gRenderer, 335, 70);
auto guessCounter = LTexture(from_text, gRenderer, "Guesses remaining: " + std::to_string(game.numberofGuesses - guessCount), textColor, textWidth);
guessCounter.render(gRenderer, 350, 200);
auto inputTexture = LTexture(from_text, gRenderer, guessInput, textColor, textWidth);
if (guessInput == "")
inputTexture = LTexture(from_text, gRenderer, " ", textColor, textWidth);
inputTexture.render(gRenderer, 350 + guessPrompt.mWidth, textWidth);
SDL_RenderPresent(gRenderer);
return true;
void gameLoop(GameStates& gameState, Game& game)
std::string guessInput = " ";
std::string dialogue = " ";
SDL_Color const textColor = 0,0,0 ;
auto const textWidth = 250;
auto highLowTexture = LTexture(from_surface, gRenderer, "Resources/HiLo.png");
auto guessPrompt = LTexture(from_text, gRenderer, "Enter a number:", textColor, textWidth);
int guessCount = 0;
int guess = 0;
while (gameLoop_input(gameState, guessInput, guess, guessCount) &&
gameLoop_update(gameState, dialogue, guess, guessCount, game) &&
gameLoop_render(highLowTexture, guessPrompt, guessInput, dialogue, textColor, textWidth, guessCount, game))
bool mainMenu_input(GameStates& gameState, Game& game, LTexture& tenButton, LTexture& hundredButton, LTexture& thousandButton)
SDL_Event e;
while (SDL_PollEvent(&e) != 0)
if (e.type == SDL_QUIT)
gameState = GameStates::EXIT;
return false;
//change game settings based on button
if (button_is_pressed(e, tenButton.mButton))
game.numberofGuesses = 5;
game.max = 10;
game.randomNumber = getRandomNumber(game.min, game.max);
gameState = GameStates::MAIN_LOOP;
//used to make sure game works properly
std::cout << game.randomNumber;
return false;
else if (button_is_pressed(e, hundredButton.mButton))
game.numberofGuesses = 7;
game.max = 100;
game.randomNumber = getRandomNumber(game.min, game.max);
gameState = GameStates::MAIN_LOOP;
std::cout << game.randomNumber;
return false;
else if (button_is_pressed(e, thousandButton.mButton))
game.numberofGuesses = 9;
game.max = 1000;
game.randomNumber = getRandomNumber(game.min, game.max);
gameState = GameStates::MAIN_LOOP;
std::cout << game.randomNumber;
return false;
return true;
bool mainMenu_update()
return true;
bool mainMenu_render(LTexture& menuTexture, LTexture& tenButton, LTexture& hundredButton, LTexture& thousandButton)
SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderClear(gRenderer);
menuTexture.render(gRenderer, 0, 0);
tenButton.render(gRenderer, (SCREEN_WIDTH / 2) - (tenButton.mWidth / 2), 175);
hundredButton.render(gRenderer, (SCREEN_WIDTH / 2) - (tenButton.mWidth / 2), 225);
thousandButton.render(gRenderer, (SCREEN_WIDTH / 2) - (tenButton.mWidth / 2), 275);
SDL_RenderPresent(gRenderer);
return true;
void mainMenu(GameStates& gameState, Game& game)
auto menuTexture = LTexture(from_surface, gRenderer, "Resources/HiLoMenu.png");
auto tenButton = LTexture(from_surface, gRenderer, "Resources/HiLo10.png");
auto hundredButton = LTexture(from_surface, gRenderer, "Resources/HiLo100.png");
auto thousandButton = LTexture(from_surface, gRenderer, "Resources/HiLo1000.png");
while (mainMenu_input(gameState, game, tenButton, hundredButton, thousandButton) &&
mainMenu_update() &&
mainMenu_render(menuTexture, tenButton, hundredButton, thousandButton))
void init()
SDL_RENDERER_PRESENTVSYNC);
if (gRenderer == nullptr)
std::cout << "Failed to create renderer";
gFont = TTF_OpenFont("Resources/opensans.ttf", 20);
if (gFont == nullptr)
std::cout << "Failed to open font";
void close()
if (gFont)
TTF_CloseFont(gFont);
if (gWindow)
SDL_DestroyWindow(gWindow);
if (gRenderer)
SDL_DestroyRenderer(gRenderer);
int main(int argc, char* args)
init();
GameStates gameState = GameStates::MAIN_MENU;
Game game;
while (gameState != GameStates::EXIT)
switch (gameState)
case GameStates::MAIN_MENU:
mainMenu(gameState, game);
break;
case GameStates::MAIN_LOOP:
gameLoop(gameState, game);
break;
case GameStates::PLAY_AGAIN:
playAgain(gameState, game);
break;
close();
return 0;
I know I still have a lot to learn, but any additional feedback would be greatly appreciated.
I also have a few more questions:
I was previously told that my code looks very "C-ish". If it still is, what makes it "C-ish"? I probably just don't know enough about the difference between the two to really tell.
What is the difference between doing something like
sdl sdlinit;
andauto sdlinit = sdl
? Additionally, how do you determine when to use auto and when to specify?
Thanks again for your time.
c++ sdl
So after getting a very thorough review and feedback from indi in my previous attempt, SDL/C++ High-Low Guessing Game, I decided to go through the game and fix as many mistakes as I could. But going through the feedback also just opened up even more questions.
Things I was unable to do
Get rid of all global variables. I was able to remove or move most of the global variables, but I had an issue with the
SDL_Window*
,SDL_Renderer
, andTTF_Font
. It was suggested that I used astd::unique_ptr
, so I made the window astd::unique_ptr
, but I was unable to use that window as a parameter for creating the renderer because there was no suitable conversion from astd::unique_ptr
to aSDL_Window*
. Thus I just kept them in global until I can figure out how to make it work.Use the struct "tags" for my
LTexture
class. It was suggested to usestruct from_surface_tag from_surface;
andstruct from_text_tag from_text;
to indicate which version of the constructor I was using. The compiler just kept saying thatfrom_text
orfrom_surface
were undefined. I realize that there mainly for the reader of the code, so I just made anenum
to use as the tags.Used the state machine that was suggested. I make the engine that was suggested, but I failed miserably. Instead I created a very basic state machine that hopefully works and gets rid of the
playAgain -> mainMenu -> playAgain
loop. Hopefully I'll be able to understand how to other one once I get more experience.Lastly, I did not make not make the
LTexture
class it's own file, mainly because I struggled getting the SDL one's to work.
Here is my code:
SDLInit.h
#pragma once
class sdl
public:
sdl();
sdl(sdl&& other) noexcept;
~sdl();
auto operator=(sdl&& other) noexcept->sdl&;
// Non-copyable
sdl(sdl const&) = delete;
auto operator=(sdl const&)->sdl& = delete;
friend void _swap(sdl& a, sdl& b) noexcept;
private:
bool _own = false;
;
class sdl_img
public:
sdl_img();
sdl_img(sdl_img&& other) noexcept;
~sdl_img();
auto operator=(sdl_img&& other) noexcept->sdl_img&;
// Non-copyable
sdl_img(sdl_img const&) = delete;
auto operator=(sdl_img const&)->sdl_img& = delete;
friend void _swap(sdl_img& a, sdl_img& b) noexcept;
private:
bool _own = false;
;
class sdl_ttf
public:
sdl_ttf();
sdl_ttf(sdl_ttf&& other) noexcept;
~sdl_ttf();
auto operator=(sdl_ttf&& other) noexcept->sdl_ttf&;
// Non-copyable
sdl_ttf(sdl_ttf const&) = delete;
auto operator=(sdl_ttf const&)->sdl_ttf& = delete;
friend void _swap(sdl_ttf& a, sdl_ttf& b) noexcept;
private:
bool _own = false;
;
SDLInit.cpp
#include <iostream>
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>
#include "SDLInit.h"
//Initialize SDL
sdl::sdl()
auto const result = SDL_Init(SDL_INIT_VIDEO);
if (result != 0)
std::cout << "SDL could not initialize";
sdl::sdl(sdl&& other) noexcept
_swap(*this, other);
sdl::~sdl()
if (_own)
SDL_Quit();
auto sdl::operator=(sdl&& other) noexcept -> sdl&
_swap(*this, other);
return *this;
void _swap(sdl& a, sdl& b) noexcept
using std::swap;
swap(a._own, b._own);
//Initialize SDL Image
sdl_img::sdl_img()
auto const result = IMG_Init(IMG_INIT_PNG);
if (result == 0)
std::cout << "SDL Image could not initialize";
sdl_img::sdl_img(sdl_img&& other) noexcept
_swap(*this, other);
sdl_img::~sdl_img()
if (_own)
IMG_Quit();
auto sdl_img::operator=(sdl_img&& other) noexcept -> sdl_img&
_swap(*this, other);
return *this;
void _swap(sdl_img& a, sdl_img& b) noexcept
using std::swap;
swap(a._own, b._own);
//Initialize SDL True Type Fonts
sdl_ttf::sdl_ttf()
auto const result = TTF_Init();
if (result != 0)
std::cout << "SDL TTF could not initialize";
sdl_ttf::sdl_ttf(sdl_ttf&& other) noexcept
_swap(*this, other);
sdl_ttf::~sdl_ttf()
if (_own)
TTF_Quit();
auto sdl_ttf::operator=(sdl_ttf&& other) noexcept -> sdl_ttf&
_swap(*this, other);
return *this;
void _swap(sdl_ttf& a, sdl_ttf& b) noexcept
using std::swap;
swap(a._own, b._own);
Main.cpp
#include <iostream>
#include <random>
#include <string>
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>
#include "SDLInit.h"
constexpr int SCREEN_WIDTH = 640;
constexpr int SCREEN_HEIGHT = 480;
SDL_Window* gWindow = nullptr;
SDL_Renderer* gRenderer = nullptr;
TTF_Font* gFont = nullptr;
enum class GameStates
MAIN_MENU,
MAIN_LOOP,
PLAY_AGAIN,
EXIT,
;
struct Game
int numberofGuesses = 0;
const int min = 1;
int max = 0;
int randomNumber = 0;
bool game_was_won = false;
;
std::mt19937& random_engine()
static std::mt19937 mersenne(std::random_device());
return mersenne;
int getRandomNumber(int x, int y)
std::uniform_int_distribution<> dist x,y ;
return dist(random_engine());
//used to tag how the texture was rendered
enum TextureType from_surface, from_text ;
class LTexture
public:
LTexture(TextureType type, SDL_Renderer* renderer, std::string const& path);
LTexture(TextureType type, SDL_Renderer* renderer, std::string const& text, SDL_Color color, int width);
LTexture(LTexture&& other) noexcept
swap(*this, other);
~LTexture();
void render(SDL_Renderer* renderer, int x, int y);
LTexture& operator=(LTexture&& other) noexcept
swap(*this, other);
return *this;
SDL_Texture* mTexture = nullptr;
int mWidth = 0;
int mHeight = 0;
SDL_Rect mButton = ;
LTexture(LTexture const&) = delete;
LTexture& operator=(LTexture const&) = delete;
friend void swap(LTexture& a, LTexture& b) noexcept;
;
LTexture::LTexture(TextureType type, SDL_Renderer* renderer, std::string const& path)
SDL_Surface *surface = IMG_Load(path.c_str());
if (!surface)
std::cout << "Failed to create surface";
mTexture = SDL_CreateTextureFromSurface(gRenderer, surface);
if (!mTexture)
std::cout << "Failed to create texture";
mWidth = surface->w;
mHeight = surface->h;
LTexture::LTexture(TextureType type, SDL_Renderer* renderer, std::string const& text, SDL_Color color, int width)
SDL_Surface* textSurface = TTF_RenderText_Blended_Wrapped(gFont, text.c_str(), color, width);
if (!textSurface)
std::cout << "Failed to create surface";
mTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
if (!mTexture)
std::cout << "Failed to created texture";
mWidth = textSurface->w;
mHeight = textSurface->h;
SDL_FreeSurface(textSurface);
void LTexture::render(SDL_Renderer* renderer, int x, int y)
SDL_Rect destRect = x, y, mWidth, mHeight ;
SDL_RenderCopy(renderer, mTexture, nullptr, &destRect);
//create a rectangle that coincides with texture to check for button presses
mButton = x, y, mWidth, mHeight ;
void swap(LTexture& a, LTexture& b) noexcept
using std::swap;
swap(a.mTexture, b.mTexture);
swap(a.mWidth, b.mWidth);
swap(a.mHeight, b.mHeight);
swap(a.mButton, b.mButton);
LTexture::~LTexture()
if (mTexture)
SDL_DestroyTexture(mTexture);
bool button_is_pressed(SDL_Event const& event, SDL_Rect const& button_rect)
if (event.type == SDL_MOUSEBUTTONDOWN)
auto const& mouse_button_event = event.button;
auto const mouse_position = SDL_Point mouse_button_event.x, mouse_button_event.y ;
return (mouse_button_event.button == SDL_BUTTON_LEFT) && SDL_PointInRect(&mouse_position, &button_rect);
return false;
// compare random number to guess player provided
int compare(int randomNumber, int guess)
if (randomNumber < guess)
return -1;
if (randomNumber > guess)
return 1;
return 0;
bool playAgain_input(GameStates& gameState, LTexture const& yesButton, LTexture const& noButton)
SDL_Event e;
while (SDL_PollEvent(&e) != 0)
button_is_pressed(e, noButton.mButton))
gameState = GameStates::EXIT;
return false;
if (button_is_pressed(e, yesButton.mButton))
gameState = GameStates::MAIN_MENU;
return false;
return true;
bool playAgain_update()
return true;
bool playAgain_render(LTexture& highLowTexture, LTexture& winlose, LTexture& playAgain, LTexture& yesButton, LTexture& noButton)
SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderClear(gRenderer);
highLowTexture.render(gRenderer, 0, 0);
winlose.render(gRenderer, 335, 70);
playAgain.render(gRenderer, 325, 300);
yesButton.render(gRenderer, 300, 350);
noButton.render(gRenderer, 300 + yesButton.mWidth + 10, 350);
SDL_RenderPresent(gRenderer);
return true;
void playAgain(GameStates& gameState, Game game)
SDL_Color const textColor = 0,0,0 ;
auto const textWidth = 250;
auto highLowTexture = LTexture(from_surface, gRenderer, "Resources/HiLo.png");
auto playAgain = LTexture(from_text, gRenderer, "Play Again?", textColor, textWidth);
auto yesButton = LTexture from_surface, gRenderer, "Resources/HiLoYes.png" ;
auto noButton = LTexture from_surface, gRenderer, "Resources/HiLoNo.png" ;
std::string dialogue;
//change dialogue based on if player won or not
if (game.game_was_won)
dialogue = "YOU WON!!! The correct answer was " + std::to_string(game.randomNumber) + ".";
else
dialogue = "You lose. The correct answer was " + std::to_string(game.randomNumber) + ".";
auto winlose = LTexture from_text, gRenderer, dialogue, textColor, textWidth ;
while (playAgain_input(gameState, yesButton, noButton) && playAgain_update() && playAgain_render(highLowTexture, winlose, playAgain, yesButton, noButton))
bool gameLoop_input(GameStates& gameState, std::string& guessInput, int& guess, int& guessCount)
SDL_Event e;
SDL_StartTextInput();
while (SDL_PollEvent(&e) != 0)
if (e.type == SDL_QUIT)
gameState = GameStates::EXIT;
return false;
if (e.type == SDL_TEXTINPUT)
if (e.type == SDL_KEYDOWN)
e.key.keysym.sym == SDLK_KP_ENTER)
//if input is not empty
if (guessInput != " ")
//convert guess to int
guess = stoi(guessInput);
//reset string
guessInput = " ";
++guessCount;
else if (e.key.keysym.sym == SDLK_BACKSPACE && guessInput.length() > 0)
guessInput.pop_back();
SDL_StopTextInput();
return true;
bool gameLoop_update(GameStates& gameState, std::string& dialogue, int guess, int guessCount, Game& game)
if (guessCount == 0)
dialogue = "I'm thinking of a number between " + std::to_string(game.min) + " and " + std::to_string(game.max) + ". You have " + std::to_string(game.numberofGuesses) + " guesses.";
// if player ran out of moves
else if (guessCount == game.numberofGuesses)
game.game_was_won = false;
gameState = GameStates::PLAY_AGAIN;
return false;
else
int cmp = compare(game.randomNumber, guess);
//change dialogue based on comparison
if (cmp > 0)
dialogue = "Your guess was too low.";
else if (cmp < 0)
dialogue = "Your guess was too high.";
else
game.game_was_won = true;
gameState = GameStates::PLAY_AGAIN;
return false;
return true;
bool gameLoop_render(LTexture& highLowTexture, LTexture& guessPrompt, std::string guessInput, std::string dialogue, SDL_Color textColor, int textWidth, int guessCount, Game game)
SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderClear(gRenderer);
highLowTexture.render(gRenderer, 0, 0);
guessPrompt.render(gRenderer, 350, 250);
auto bubbleText = LTexture(from_text, gRenderer, dialogue, textColor, textWidth);
bubbleText.render(gRenderer, 335, 70);
auto guessCounter = LTexture(from_text, gRenderer, "Guesses remaining: " + std::to_string(game.numberofGuesses - guessCount), textColor, textWidth);
guessCounter.render(gRenderer, 350, 200);
auto inputTexture = LTexture(from_text, gRenderer, guessInput, textColor, textWidth);
if (guessInput == "")
inputTexture = LTexture(from_text, gRenderer, " ", textColor, textWidth);
inputTexture.render(gRenderer, 350 + guessPrompt.mWidth, textWidth);
SDL_RenderPresent(gRenderer);
return true;
void gameLoop(GameStates& gameState, Game& game)
std::string guessInput = " ";
std::string dialogue = " ";
SDL_Color const textColor = 0,0,0 ;
auto const textWidth = 250;
auto highLowTexture = LTexture(from_surface, gRenderer, "Resources/HiLo.png");
auto guessPrompt = LTexture(from_text, gRenderer, "Enter a number:", textColor, textWidth);
int guessCount = 0;
int guess = 0;
while (gameLoop_input(gameState, guessInput, guess, guessCount) &&
gameLoop_update(gameState, dialogue, guess, guessCount, game) &&
gameLoop_render(highLowTexture, guessPrompt, guessInput, dialogue, textColor, textWidth, guessCount, game))
bool mainMenu_input(GameStates& gameState, Game& game, LTexture& tenButton, LTexture& hundredButton, LTexture& thousandButton)
SDL_Event e;
while (SDL_PollEvent(&e) != 0)
if (e.type == SDL_QUIT)
gameState = GameStates::EXIT;
return false;
//change game settings based on button
if (button_is_pressed(e, tenButton.mButton))
game.numberofGuesses = 5;
game.max = 10;
game.randomNumber = getRandomNumber(game.min, game.max);
gameState = GameStates::MAIN_LOOP;
//used to make sure game works properly
std::cout << game.randomNumber;
return false;
else if (button_is_pressed(e, hundredButton.mButton))
game.numberofGuesses = 7;
game.max = 100;
game.randomNumber = getRandomNumber(game.min, game.max);
gameState = GameStates::MAIN_LOOP;
std::cout << game.randomNumber;
return false;
else if (button_is_pressed(e, thousandButton.mButton))
game.numberofGuesses = 9;
game.max = 1000;
game.randomNumber = getRandomNumber(game.min, game.max);
gameState = GameStates::MAIN_LOOP;
std::cout << game.randomNumber;
return false;
return true;
bool mainMenu_update()
return true;
bool mainMenu_render(LTexture& menuTexture, LTexture& tenButton, LTexture& hundredButton, LTexture& thousandButton)
SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderClear(gRenderer);
menuTexture.render(gRenderer, 0, 0);
tenButton.render(gRenderer, (SCREEN_WIDTH / 2) - (tenButton.mWidth / 2), 175);
hundredButton.render(gRenderer, (SCREEN_WIDTH / 2) - (tenButton.mWidth / 2), 225);
thousandButton.render(gRenderer, (SCREEN_WIDTH / 2) - (tenButton.mWidth / 2), 275);
SDL_RenderPresent(gRenderer);
return true;
void mainMenu(GameStates& gameState, Game& game)
auto menuTexture = LTexture(from_surface, gRenderer, "Resources/HiLoMenu.png");
auto tenButton = LTexture(from_surface, gRenderer, "Resources/HiLo10.png");
auto hundredButton = LTexture(from_surface, gRenderer, "Resources/HiLo100.png");
auto thousandButton = LTexture(from_surface, gRenderer, "Resources/HiLo1000.png");
while (mainMenu_input(gameState, game, tenButton, hundredButton, thousandButton) &&
mainMenu_update() &&
mainMenu_render(menuTexture, tenButton, hundredButton, thousandButton))
void init()
SDL_RENDERER_PRESENTVSYNC);
if (gRenderer == nullptr)
std::cout << "Failed to create renderer";
gFont = TTF_OpenFont("Resources/opensans.ttf", 20);
if (gFont == nullptr)
std::cout << "Failed to open font";
void close()
if (gFont)
TTF_CloseFont(gFont);
if (gWindow)
SDL_DestroyWindow(gWindow);
if (gRenderer)
SDL_DestroyRenderer(gRenderer);
int main(int argc, char* args)
init();
GameStates gameState = GameStates::MAIN_MENU;
Game game;
while (gameState != GameStates::EXIT)
switch (gameState)
case GameStates::MAIN_MENU:
mainMenu(gameState, game);
break;
case GameStates::MAIN_LOOP:
gameLoop(gameState, game);
break;
case GameStates::PLAY_AGAIN:
playAgain(gameState, game);
break;
close();
return 0;
I know I still have a lot to learn, but any additional feedback would be greatly appreciated.
I also have a few more questions:
I was previously told that my code looks very "C-ish". If it still is, what makes it "C-ish"? I probably just don't know enough about the difference between the two to really tell.
What is the difference between doing something like
sdl sdlinit;
andauto sdlinit = sdl
? Additionally, how do you determine when to use auto and when to specify?
Thanks again for your time.
c++ sdl
asked Aug 1 at 0:18
Nick
161
161
You should flag a moderator and request your accounts be merged
â bruglesco
Aug 1 at 4:02
Regardingauto
usage, have a look at this quite good answer which hopefully makes things a bit clearer.
â yuri
Aug 1 at 6:17
The correct way of using smart ptr for Window & Renderer is :std::unique_ptr<SDL_Window, void(*)(SDL_Window*)> window(SDL_CreateWindow(...), SDL_DestroyWindow);
std::unique_ptr<SDL_Renderer, void(*)(SDL_Renderer*)> renderer(SDL_CreateRenderer(window.get(), ...), SDL_DestroyRenderer);
Then you usewindow.get()
which returnsSDL_Window*
, andrenderer.get()
which returnsSDL_Renderer*
.
â Julien Vernay
Aug 1 at 21:10
add a comment |Â
You should flag a moderator and request your accounts be merged
â bruglesco
Aug 1 at 4:02
Regardingauto
usage, have a look at this quite good answer which hopefully makes things a bit clearer.
â yuri
Aug 1 at 6:17
The correct way of using smart ptr for Window & Renderer is :std::unique_ptr<SDL_Window, void(*)(SDL_Window*)> window(SDL_CreateWindow(...), SDL_DestroyWindow);
std::unique_ptr<SDL_Renderer, void(*)(SDL_Renderer*)> renderer(SDL_CreateRenderer(window.get(), ...), SDL_DestroyRenderer);
Then you usewindow.get()
which returnsSDL_Window*
, andrenderer.get()
which returnsSDL_Renderer*
.
â Julien Vernay
Aug 1 at 21:10
You should flag a moderator and request your accounts be merged
â bruglesco
Aug 1 at 4:02
You should flag a moderator and request your accounts be merged
â bruglesco
Aug 1 at 4:02
Regarding
auto
usage, have a look at this quite good answer which hopefully makes things a bit clearer.â yuri
Aug 1 at 6:17
Regarding
auto
usage, have a look at this quite good answer which hopefully makes things a bit clearer.â yuri
Aug 1 at 6:17
The correct way of using smart ptr for Window & Renderer is :
std::unique_ptr<SDL_Window, void(*)(SDL_Window*)> window(SDL_CreateWindow(...), SDL_DestroyWindow);
std::unique_ptr<SDL_Renderer, void(*)(SDL_Renderer*)> renderer(SDL_CreateRenderer(window.get(), ...), SDL_DestroyRenderer);
Then you use window.get()
which returns SDL_Window*
, and renderer.get()
which returns SDL_Renderer*
.â Julien Vernay
Aug 1 at 21:10
The correct way of using smart ptr for Window & Renderer is :
std::unique_ptr<SDL_Window, void(*)(SDL_Window*)> window(SDL_CreateWindow(...), SDL_DestroyWindow);
std::unique_ptr<SDL_Renderer, void(*)(SDL_Renderer*)> renderer(SDL_CreateRenderer(window.get(), ...), SDL_DestroyRenderer);
Then you use window.get()
which returns SDL_Window*
, and renderer.get()
which returns SDL_Renderer*
.â Julien Vernay
Aug 1 at 21:10
add a comment |Â
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f200703%2fsdl-c-high-low-guessing-game-version-2%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
You should flag a moderator and request your accounts be merged
â bruglesco
Aug 1 at 4:02
Regarding
auto
usage, have a look at this quite good answer which hopefully makes things a bit clearer.â yuri
Aug 1 at 6:17
The correct way of using smart ptr for Window & Renderer is :
std::unique_ptr<SDL_Window, void(*)(SDL_Window*)> window(SDL_CreateWindow(...), SDL_DestroyWindow);
std::unique_ptr<SDL_Renderer, void(*)(SDL_Renderer*)> renderer(SDL_CreateRenderer(window.get(), ...), SDL_DestroyRenderer);
Then you usewindow.get()
which returnsSDL_Window*
, andrenderer.get()
which returnsSDL_Renderer*
.â Julien Vernay
Aug 1 at 21:10