patterncppMinor
Simple Snake Game
Viewed 0 times
gamesimplesnake
Problem
I was working on this game for while and I have made it for education purposes by using SFML. The game works fine but I would like to know how I can improve it.
```
#include
#include
#include
#include
#include
#include
#include
#include
namespace
{
const sf::Vector2f WindowSize(640, 480);
constexpr auto BlockSize = 16.f;
constexpr auto SnakeSpeed = 5.f;
const auto TimeStep = sf::seconds(1 / SnakeSpeed);
auto randomEngine()
{
std::array seed_data;
thread_local std::random_device source;
std::generate(std::begin(seed_data), std::end(seed_data), std::ref(source));
std::seed_seq seeds(std::begin(seed_data), std::end(seed_data));
thread_local std::mt19937 seeded_engine(seeds);
return seeded_engine;
}
auto random(const std::uniform_real_distribution& dist)
{
static auto& RandomEngine = randomEngine();
return dist(RandomEngine);
}
}
class Snake : public sf::Drawable, sf::NonCopyable
{
public:
enum Direction
{
None,
Up,
Down,
Left,
Right
};
private:
using SnakeContainer = std::vector;
public:
explicit Snake(const sf::Font& font)
{
reset();
mLivesText.setFont(font);
mLivesText.setStyle(sf::Text::Bold);
mLivesText.setCharacterSize(30);
mLivesText.setColor(sf::Color::White);
mLivesText.setPosition(WindowSize.x - 160.f, 0.f);
}
void reset()
{
mSnakeBody.clear();
sf::RectangleShape shape({ BlockSize - 1, BlockSize - 1 });
shape.setPosition(70 + BlockSize, 70 + 3 * BlockSize);
shape.setFillColor(sf::Color(211, 211, 211));
mSnakeBody.push_back(shape);
shape.setPosition(70 + BlockSize, 70 + 2 * BlockSize);
mSnakeBody.push_back(shape);
shape.setPosition(70 + BlockSize, 70 + BlockSize);
mSnakeBody.push_back(shape);
mDirection = Direction::None;
mLives
```
#include
#include
#include
#include
#include
#include
#include
#include
namespace
{
const sf::Vector2f WindowSize(640, 480);
constexpr auto BlockSize = 16.f;
constexpr auto SnakeSpeed = 5.f;
const auto TimeStep = sf::seconds(1 / SnakeSpeed);
auto randomEngine()
{
std::array seed_data;
thread_local std::random_device source;
std::generate(std::begin(seed_data), std::end(seed_data), std::ref(source));
std::seed_seq seeds(std::begin(seed_data), std::end(seed_data));
thread_local std::mt19937 seeded_engine(seeds);
return seeded_engine;
}
auto random(const std::uniform_real_distribution& dist)
{
static auto& RandomEngine = randomEngine();
return dist(RandomEngine);
}
}
class Snake : public sf::Drawable, sf::NonCopyable
{
public:
enum Direction
{
None,
Up,
Down,
Left,
Right
};
private:
using SnakeContainer = std::vector;
public:
explicit Snake(const sf::Font& font)
{
reset();
mLivesText.setFont(font);
mLivesText.setStyle(sf::Text::Bold);
mLivesText.setCharacterSize(30);
mLivesText.setColor(sf::Color::White);
mLivesText.setPosition(WindowSize.x - 160.f, 0.f);
}
void reset()
{
mSnakeBody.clear();
sf::RectangleShape shape({ BlockSize - 1, BlockSize - 1 });
shape.setPosition(70 + BlockSize, 70 + 3 * BlockSize);
shape.setFillColor(sf::Color(211, 211, 211));
mSnakeBody.push_back(shape);
shape.setPosition(70 + BlockSize, 70 + 2 * BlockSize);
mSnakeBody.push_back(shape);
shape.setPosition(70 + BlockSize, 70 + BlockSize);
mSnakeBody.push_back(shape);
mDirection = Direction::None;
mLives
Solution
I don't know SFML at all, so very partial review.
There are two portability bugs here:
This
If threads are involved, you need to change the
The order in which you declared your variables is the order in which they will be initialized at runtime. But the order you have them in the constructor's initializer list is different. This can lead to subtle bugs when initialization of some members depends on others. You should make both orders match.
auto random(const std::uniform_real_distribution& dist)
{
static auto& RandomEngine = randomEngine();
return dist(RandomEngine);
}There are two portability bugs here:
randomEngine()returns a temporary, butauto&will deduce a non-const reference type here - that's an error (MSVC has an extension that accepts this though, unfortunately). But you don't need a reference here though, just a plain static object, so drop the&
- the distribution's
operator()(Generator &)member is not const according to the standard. You should remove theconstfrom parameter for this to be portable.
auto randomEngine()
{
// ...
thread_local std::mt19937 seeded_engine(seeds);
// ...
}This
thread_local doesn't make sense here, at least not with your random() function's usage. (Even without that it's fishy, your seed manipulations would be executed on every call, but the actual engine would be constructed only once and copied out of the function.) Remove it.If threads are involved, you need to change the
static to thread_local in random, you'll get data races in there otherwise.explicit World(const sf::Font &font)
: mSnake(font), mBorders(4),
mDistX(2 * BlockSize, WindowSize.x - 2 * BlockSize),
mDistY(3 * BlockSize, WindowSize.y - 2 * BlockSize), mScore() {...}
// ...
std::size_t mScore;
// ...
DistType mDistX;
DistType mDistY;The order in which you declared your variables is the order in which they will be initialized at runtime. But the order you have them in the constructor's initializer list is different. This can lead to subtle bugs when initialization of some members depends on others. You should make both orders match.
Code Snippets
auto random(const std::uniform_real_distribution<float>& dist)
{
static auto& RandomEngine = randomEngine();
return dist(RandomEngine);
}auto randomEngine()
{
// ...
thread_local std::mt19937 seeded_engine(seeds);
// ...
}explicit World(const sf::Font &font)
: mSnake(font), mBorders(4),
mDistX(2 * BlockSize, WindowSize.x - 2 * BlockSize),
mDistY(3 * BlockSize, WindowSize.y - 2 * BlockSize), mScore() {...}
// ...
std::size_t mScore;
// ...
DistType mDistX;
DistType mDistY;Context
StackExchange Code Review Q#115544, answer score: 7
Revisions (0)
No revisions yet.