SDL/C++ High-Low Guessing Game (Version 2)

The name of the pictureThe name of the pictureThe name of the pictureClash 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, and TTF_Font. It was suggested that I used a std::unique_ptr, so I made the window a std::unique_ptr, but I was unable to use that window as a parameter for creating the renderer because there was no suitable conversion from a std::unique_ptr to a SDL_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 use struct from_surface_tag from_surface; and struct from_text_tag from_text; to indicate which version of the constructor I was using. The compiler just kept saying that from_text or from_surface were undefined. I realize that there mainly for the reader of the code, so I just made an enum 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; and auto sdlinit = sdl? Additionally, how do you determine when to use auto and when to specify?


Thanks again for your time.







share|improve this question



















  • 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 use window.get() which returns SDL_Window*, and renderer.get() which returns SDL_Renderer*.
    – Julien Vernay
    Aug 1 at 21:10

















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, and TTF_Font. It was suggested that I used a std::unique_ptr, so I made the window a std::unique_ptr, but I was unable to use that window as a parameter for creating the renderer because there was no suitable conversion from a std::unique_ptr to a SDL_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 use struct from_surface_tag from_surface; and struct from_text_tag from_text; to indicate which version of the constructor I was using. The compiler just kept saying that from_text or from_surface were undefined. I realize that there mainly for the reader of the code, so I just made an enum 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; and auto sdlinit = sdl? Additionally, how do you determine when to use auto and when to specify?


Thanks again for your time.







share|improve this question



















  • 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 use window.get() which returns SDL_Window*, and renderer.get() which returns SDL_Renderer*.
    – Julien Vernay
    Aug 1 at 21:10













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, and TTF_Font. It was suggested that I used a std::unique_ptr, so I made the window a std::unique_ptr, but I was unable to use that window as a parameter for creating the renderer because there was no suitable conversion from a std::unique_ptr to a SDL_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 use struct from_surface_tag from_surface; and struct from_text_tag from_text; to indicate which version of the constructor I was using. The compiler just kept saying that from_text or from_surface were undefined. I realize that there mainly for the reader of the code, so I just made an enum 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; and auto sdlinit = sdl? Additionally, how do you determine when to use auto and when to specify?


Thanks again for your time.







share|improve this question











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, and TTF_Font. It was suggested that I used a std::unique_ptr, so I made the window a std::unique_ptr, but I was unable to use that window as a parameter for creating the renderer because there was no suitable conversion from a std::unique_ptr to a SDL_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 use struct from_surface_tag from_surface; and struct from_text_tag from_text; to indicate which version of the constructor I was using. The compiler just kept saying that from_text or from_surface were undefined. I realize that there mainly for the reader of the code, so I just made an enum 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; and auto sdlinit = sdl? Additionally, how do you determine when to use auto and when to specify?


Thanks again for your time.









share|improve this question










share|improve this question




share|improve this question









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










  • 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

















  • 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 use window.get() which returns SDL_Window*, and renderer.get() which returns SDL_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
















active

oldest

votes











Your Answer




StackExchange.ifUsing("editor", function ()
return StackExchange.using("mathjaxEditing", function ()
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
);
);
, "mathjax-editing");

StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);








 

draft saved


draft discarded


















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



































active

oldest

votes













active

oldest

votes









active

oldest

votes






active

oldest

votes










 

draft saved


draft discarded


























 


draft saved


draft discarded














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













































































Popular posts from this blog

Greedy Best First Search implementation in Rust

Function to Return a JSON Like Objects Using VBA Collections and Arrays

C++11 CLH Lock Implementation