Basic category layout
This commit is contained in:
parent
59960de2bb
commit
12b5283a71
@ -1,7 +1,7 @@
|
||||
project(
|
||||
'jujube',
|
||||
'cpp',
|
||||
default_options : ['cpp_std=c++17'],
|
||||
default_options : ['cpp_std=c++20'],
|
||||
version : '0.1.0-alpha',
|
||||
)
|
||||
|
||||
@ -23,6 +23,8 @@ sources = [
|
||||
'src/Data/SongList.hpp',
|
||||
'src/Data/SongList.cpp',
|
||||
# 'src/Screens/Gameplay.hpp',
|
||||
'src/Screens/MusicSelect/ButtonHighlight.hpp',
|
||||
'src/Screens/MusicSelect/ButtonHighlight.cpp',
|
||||
'src/Screens/MusicSelect/MusicSelect.hpp',
|
||||
'src/Screens/MusicSelect/MusicSelect.cpp',
|
||||
'src/Screens/MusicSelect/Panel.hpp',
|
||||
@ -34,6 +36,9 @@ sources = [
|
||||
# 'src/Screens/Result.hpp',
|
||||
'src/Resources/CoverAtlas.hpp',
|
||||
'src/Resources/CoverAtlas.cpp',
|
||||
'src/Toolkit/QuickRNG.hpp',
|
||||
'src/Toolkit/QuickRNG.cpp',
|
||||
'src/Toolkit/AffineTransform.hpp',
|
||||
]
|
||||
|
||||
executable(
|
||||
|
@ -1,10 +1,35 @@
|
||||
#include "KeyMapping.hpp"
|
||||
|
||||
ButtonCoords toCoord(Button panel) {
|
||||
auto num = static_cast<int>(panel);
|
||||
ButtonCoords toCoords(Button button) {
|
||||
auto num = static_cast<unsigned int>(button);
|
||||
return {num % 4, num / 4};
|
||||
}
|
||||
|
||||
unsigned int toIndex(Button button) {
|
||||
return static_cast<unsigned int>(button);
|
||||
}
|
||||
|
||||
std::optional<Button> fromCoords(ButtonCoords button_coords) {
|
||||
if (
|
||||
button_coords.x >= 0 and
|
||||
button_coords.x < 4 and
|
||||
button_coords.y >= 0 and
|
||||
button_coords.y < 4
|
||||
) {
|
||||
return static_cast<Button>(button_coords.x + 4*button_coords.y);
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<Button> fromIndex(unsigned int index) {
|
||||
if (index >= 0 and index < 16) {
|
||||
return static_cast<Button>(index);
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
KeyMapping::KeyMapping() {
|
||||
m_key_to_button[sf::Keyboard::Num1] = Button::B1;
|
||||
m_key_to_button[sf::Keyboard::Num2] = Button::B2;
|
||||
@ -28,27 +53,27 @@ KeyMapping::KeyMapping() {
|
||||
}
|
||||
}
|
||||
|
||||
void KeyMapping::setPanelToKey(const Button& panel, const sf::Keyboard::Key& key) {
|
||||
void KeyMapping::setPanelToKey(const Button& button, const sf::Keyboard::Key& key) {
|
||||
if (m_key_to_button.find(key) != m_key_to_button.end()) {
|
||||
m_button_to_key.erase(m_key_to_button[key]);
|
||||
m_key_to_button.erase(key);
|
||||
}
|
||||
m_button_to_key[panel] = key;
|
||||
m_key_to_button[key] = panel;
|
||||
m_button_to_key[button] = key;
|
||||
m_key_to_button[key] = button;
|
||||
}
|
||||
|
||||
std::optional<Button> KeyMapping::key_to_button(const sf::Keyboard::Key& key) {
|
||||
try {
|
||||
return m_key_to_button.at(key);
|
||||
} catch(const std::exception& e) {
|
||||
if (m_key_to_button.find(key) == m_key_to_button.end()) {
|
||||
return {};
|
||||
} else {
|
||||
return m_key_to_button.at(key);
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<sf::Keyboard::Key> KeyMapping::button_to_key(const Button& panel) {
|
||||
try {
|
||||
return m_button_to_key.at(panel);
|
||||
} catch(const std::exception& e) {
|
||||
std::optional<sf::Keyboard::Key> KeyMapping::button_to_key(const Button& button) {
|
||||
if (m_button_to_key.find(button) == m_button_to_key.end()) {
|
||||
return {};
|
||||
} else {
|
||||
return m_button_to_key.at(button);
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,10 @@ struct ButtonCoords {
|
||||
unsigned int y;
|
||||
};
|
||||
|
||||
ButtonCoords toCoord(Button button);
|
||||
ButtonCoords toCoords(Button button);
|
||||
unsigned int toIndex(Button button);
|
||||
std::optional<Button> fromCoords(ButtonCoords button_coords);
|
||||
std::optional<Button> fromIndex(unsigned int index);
|
||||
|
||||
class KeyMapping {
|
||||
public:
|
||||
|
35
src/Screens/MusicSelect/ButtonHighlight.cpp
Normal file
35
src/Screens/MusicSelect/ButtonHighlight.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
#include "ButtonHighlight.hpp"
|
||||
|
||||
MusicSelect::ButtonHighlight::ButtonHighlight(unsigned int t_panel_size) :
|
||||
panel_size(t_panel_size),
|
||||
highlight({static_cast<float>(t_panel_size-3), static_cast<float>(t_panel_size-3)}),
|
||||
time_to_alpha(0.f, 0.25f, 255.f, 0.f)
|
||||
{
|
||||
highlight.setFillColor(sf::Color::Transparent);
|
||||
highlight.setOutlineThickness(1.f);
|
||||
highlight.setOrigin(highlight.getSize().x / 2.f, highlight.getSize().y / 2.f);
|
||||
}
|
||||
|
||||
void MusicSelect::ButtonHighlight::button_pressed(Button button) {
|
||||
button_presses_history[button].restart();
|
||||
}
|
||||
|
||||
void MusicSelect::ButtonHighlight::draw(sf::RenderTarget& target, sf::RenderStates states) const {
|
||||
auto it = button_presses_history.begin();
|
||||
while (it != button_presses_history.end()) {
|
||||
auto elapsed = it->second.getElapsedTime();
|
||||
auto coords = toCoords(it->first);
|
||||
if (elapsed > sf::milliseconds(250)) {
|
||||
it = button_presses_history.erase(it);
|
||||
} else {
|
||||
auto alpha = time_to_alpha.transform(elapsed.asSeconds());
|
||||
highlight.setOutlineColor(sf::Color(255,255,0,static_cast<unsigned int>(alpha)));
|
||||
highlight.setPosition({
|
||||
static_cast<float>(coords.x * panel_size) + panel_size/2.f,
|
||||
static_cast<float>(coords.y * panel_size) + panel_size/2.f
|
||||
});
|
||||
target.draw(highlight, states);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
23
src/Screens/MusicSelect/ButtonHighlight.hpp
Normal file
23
src/Screens/MusicSelect/ButtonHighlight.hpp
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <SFML/System.hpp>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
#include "../../Data/KeyMapping.hpp"
|
||||
#include "../../Toolkit/AffineTransform.hpp"
|
||||
|
||||
namespace MusicSelect {
|
||||
class ButtonHighlight : public sf::Drawable {
|
||||
public:
|
||||
explicit ButtonHighlight(unsigned int t_panel_size);
|
||||
void button_pressed(Button button);
|
||||
private:
|
||||
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
|
||||
unsigned int panel_size;
|
||||
mutable sf::RectangleShape highlight;
|
||||
mutable std::map<Button, sf::Clock> button_presses_history;
|
||||
Toolkit::AffineTransform<float> time_to_alpha;
|
||||
};
|
||||
}
|
@ -6,7 +6,8 @@
|
||||
|
||||
MusicSelect::Screen::Screen(const Data::SongList& t_song_list) :
|
||||
song_list(t_song_list),
|
||||
ribbon(MusicSelect::Ribbon::test_sort())
|
||||
ribbon(MusicSelect::Ribbon::test2_sort()),
|
||||
button_highlight(panel_size)
|
||||
{
|
||||
for (const auto& song : song_list.songs) {
|
||||
if (song.cover) {
|
||||
@ -21,7 +22,7 @@ MusicSelect::Screen::Screen(const Data::SongList& t_song_list) :
|
||||
|
||||
void MusicSelect::Screen::select_chart(sf::RenderWindow& window) {
|
||||
|
||||
window.create(sf::VideoMode(600,600), "jujube", sf::Style::None);
|
||||
window.create(sf::VideoMode(panel_size*4, panel_size*4), "jujube", sf::Style::Titlebar);
|
||||
window.setFramerateLimit(60);
|
||||
bool chart_selected = false;
|
||||
while (not chart_selected) {
|
||||
@ -29,13 +30,16 @@ void MusicSelect::Screen::select_chart(sf::RenderWindow& window) {
|
||||
while (window.pollEvent(event)) {
|
||||
switch (event.type) {
|
||||
case sf::Event::KeyPressed:
|
||||
handle_key(event.key);
|
||||
handle_key_press(event.key);
|
||||
break;
|
||||
case sf::Event::MouseButtonPressed:
|
||||
handle_mouse_click(event.mouseButton);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
// drawing the ribbon
|
||||
|
||||
// draw the ribbon
|
||||
for (size_t panel = 0; panel < 12; panel++) {
|
||||
ribbon.at(panel)->draw(
|
||||
resources,
|
||||
@ -48,10 +52,43 @@ void MusicSelect::Screen::select_chart(sf::RenderWindow& window) {
|
||||
)
|
||||
);
|
||||
}
|
||||
window.draw(button_highlight);
|
||||
window.display();
|
||||
window.clear(sf::Color::Black);
|
||||
}
|
||||
}
|
||||
|
||||
void MusicSelect::Screen::handle_key(const sf::Event::KeyEvent& key_event) {
|
||||
void MusicSelect::Screen::handle_key_press(const sf::Event::KeyEvent& key_event) {
|
||||
auto button = key_mapping.key_to_button(key_event.code);
|
||||
if (button) {
|
||||
press_button(*button);
|
||||
}
|
||||
}
|
||||
|
||||
void MusicSelect::Screen::handle_mouse_click(const sf::Event::MouseButtonEvent& mouse_button_event) {
|
||||
if (mouse_button_event.button == sf::Mouse::Left) {
|
||||
int clicked_panel_index = (mouse_button_event.x / panel_size) + 4 * (mouse_button_event.y / panel_size);
|
||||
auto button = fromIndex(clicked_panel_index);
|
||||
if (button) {
|
||||
press_button(*button);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MusicSelect::Screen::press_button(const Button& button) {
|
||||
button_highlight.button_pressed(button);
|
||||
auto index = toIndex(button);
|
||||
if (index < 12) {
|
||||
ribbon.at(index)->click(*this);
|
||||
} else {
|
||||
switch (button) {
|
||||
case Button::B13:
|
||||
ribbon.move_left();
|
||||
break;
|
||||
case Button::B14:
|
||||
ribbon.move_right();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,10 @@
|
||||
#include "../../Data/SongList.hpp"
|
||||
#include "../../Data/Chart.hpp"
|
||||
#include "../../Data/KeyMapping.hpp"
|
||||
#include "../../Toolkit/AffineTransform.hpp"
|
||||
#include "Ribbon.hpp"
|
||||
#include "Resources.hpp"
|
||||
#include "ButtonHighlight.hpp"
|
||||
|
||||
namespace MusicSelect {
|
||||
|
||||
@ -22,6 +24,7 @@ namespace MusicSelect {
|
||||
private:
|
||||
// Data
|
||||
const Data::SongList& song_list;
|
||||
unsigned int panel_size = 150;
|
||||
|
||||
// Resources
|
||||
Resources resources;
|
||||
@ -29,8 +32,14 @@ namespace MusicSelect {
|
||||
// State
|
||||
Ribbon ribbon;
|
||||
std::optional<std::reference_wrapper<SongPanel>> selected_panel;
|
||||
ButtonHighlight button_highlight;
|
||||
|
||||
KeyMapping key_mapping;
|
||||
void handle_key(const sf::Event::KeyEvent& key_event);
|
||||
// converts a key press into a button press
|
||||
void handle_key_press(const sf::Event::KeyEvent& key_event);
|
||||
// converts a mouse click into a button press
|
||||
void handle_mouse_click(const sf::Event::MouseButtonEvent& mouse_button_event);
|
||||
// chooses what happens for each button
|
||||
void press_button(const Button& button);
|
||||
};
|
||||
}
|
||||
|
@ -4,6 +4,14 @@
|
||||
|
||||
#include "MusicSelect.hpp"
|
||||
|
||||
void MusicSelect::ColorPanel::draw(Resources& resources, sf::RenderTarget& target, sf::FloatRect area) {
|
||||
sf::RectangleShape panel{{area.width*0.9f, area.height*0.9f}};
|
||||
panel.setFillColor(this->color);
|
||||
panel.setOrigin(panel.getSize().x / 2.f, panel.getSize().y / 2.f);
|
||||
panel.setPosition(area.left+area.width/2.f, area.top+area.height/2.f);
|
||||
target.draw(panel);
|
||||
}
|
||||
|
||||
void MusicSelect::CategoryPanel::click(Screen& screen) {
|
||||
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ namespace MusicSelect {
|
||||
class Screen;
|
||||
|
||||
// A Panel holds anything that can go under a button on the moving part
|
||||
// of the music select screen, be it nothing, a sort indicator, or a song
|
||||
// of the music select screen, be it nothing, a category indicator, or a song
|
||||
class Panel {
|
||||
public:
|
||||
// What happens when you click on the panel
|
||||
@ -27,6 +27,15 @@ namespace MusicSelect {
|
||||
void draw(Resources& resources, sf::RenderTarget& target, sf::FloatRect area) override {return;};
|
||||
};
|
||||
|
||||
class ColorPanel final : public Panel {
|
||||
public:
|
||||
explicit ColorPanel(const sf::Color& t_color) : color(t_color) {};
|
||||
void click(Screen& screen) override {return;};
|
||||
void draw(Resources& resources, sf::RenderTarget& target, sf::FloatRect area) override;
|
||||
private:
|
||||
const sf::Color color;
|
||||
};
|
||||
|
||||
class CategoryPanel final : public Panel {
|
||||
public:
|
||||
explicit CategoryPanel(const std::string& t_label) : label(t_label) {};
|
||||
|
@ -1,9 +1,11 @@
|
||||
#include "Ribbon.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "Panel.hpp"
|
||||
#include "../../Toolkit/QuickRNG.hpp"
|
||||
|
||||
MusicSelect::Ribbon MusicSelect::Ribbon::title_sort(const Data::SongList& song_list) {
|
||||
std::map<char,std::vector<Data::Song>> categories;
|
||||
@ -23,18 +25,18 @@ MusicSelect::Ribbon MusicSelect::Ribbon::title_sort(const Data::SongList& song_l
|
||||
}
|
||||
Ribbon ribbon;
|
||||
for (auto& [letter, songs] : categories) {
|
||||
std::vector<std::unique_ptr<Panel>> panels;
|
||||
std::vector<std::shared_ptr<Panel>> panels;
|
||||
panels.emplace_back(
|
||||
std::make_unique<CategoryPanel>(
|
||||
std::make_shared<CategoryPanel>(
|
||||
std::string(1, letter)
|
||||
)
|
||||
);
|
||||
std::sort(songs.begin(), songs.end(), Data::Song::sort_by_title);
|
||||
for (const auto& song : songs) {
|
||||
panels.push_back(std::make_unique<SongPanel>(song));
|
||||
panels.push_back(std::make_shared<SongPanel>(song));
|
||||
}
|
||||
while (panels.size() % 3 != 0) {
|
||||
panels.push_back(std::make_unique<EmptyPanel>());
|
||||
panels.push_back(std::make_shared<EmptyPanel>());
|
||||
}
|
||||
for (size_t i = 0; i < panels.size(); i += 3) {
|
||||
ribbon.layout.emplace_back();
|
||||
@ -50,27 +52,86 @@ MusicSelect::Ribbon MusicSelect::Ribbon::test_sort() {
|
||||
Ribbon ribbon;
|
||||
ribbon.layout.push_back(
|
||||
{
|
||||
std::make_unique<EmptyPanel>(),
|
||||
std::make_unique<CategoryPanel>("A"),
|
||||
std::make_unique<CategoryPanel>("truc")
|
||||
std::make_shared<EmptyPanel>(),
|
||||
std::make_shared<CategoryPanel>("A"),
|
||||
std::make_shared<CategoryPanel>("truc")
|
||||
}
|
||||
);
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
ribbon.layout.push_back(
|
||||
{
|
||||
std::make_unique<EmptyPanel>(),
|
||||
std::make_unique<EmptyPanel>(),
|
||||
std::make_unique<EmptyPanel>()
|
||||
std::make_shared<EmptyPanel>(),
|
||||
std::make_shared<EmptyPanel>(),
|
||||
std::make_shared<EmptyPanel>()
|
||||
}
|
||||
);
|
||||
}
|
||||
return ribbon;
|
||||
}
|
||||
|
||||
const std::unique_ptr<MusicSelect::Panel>& MusicSelect::Ribbon::at(unsigned int button_index) const {
|
||||
MusicSelect::Ribbon MusicSelect::Ribbon::test2_sort() {
|
||||
std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
std::map<std::string, std::list<std::shared_ptr<Panel>>> categories;
|
||||
Toolkit::UniformIntRNG category_size_generator{1,10};
|
||||
Toolkit::UniformIntRNG panel_hue_generator{0,255};
|
||||
for (auto &&letter : alphabet) {
|
||||
auto category_size = category_size_generator.generate();
|
||||
for (int i = 0; i < category_size; i++) {
|
||||
categories[std::string(1, letter)].push_back(
|
||||
std::make_shared<MusicSelect::ColorPanel>(
|
||||
sf::Color(
|
||||
panel_hue_generator.generate(),
|
||||
panel_hue_generator.generate(),
|
||||
panel_hue_generator.generate()
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
return Ribbon::layout_from_map(categories);
|
||||
}
|
||||
|
||||
const std::shared_ptr<MusicSelect::Panel>& MusicSelect::Ribbon::at(unsigned int button_index) const {
|
||||
return (
|
||||
layout
|
||||
.at((position + (button_index % 4)) % layout.size())
|
||||
.at(button_index / 4)
|
||||
);
|
||||
}
|
||||
|
||||
MusicSelect::Ribbon MusicSelect::Ribbon::layout_from_map(const std::map<std::string, std::list<std::shared_ptr<MusicSelect::Panel>>>& categories) {
|
||||
Ribbon ribbon;
|
||||
for (auto &&[category, panels] : categories) {
|
||||
if (not panels.empty()) {
|
||||
std::vector<std::shared_ptr<Panel>> current_column;
|
||||
current_column.push_back(std::make_shared<CategoryPanel>(category));
|
||||
for (auto &&panel : panels) {
|
||||
if (current_column.size() == 3) {
|
||||
ribbon.layout.push_back({current_column[0], current_column[1], current_column[2]});
|
||||
current_column.clear();
|
||||
} else {
|
||||
current_column.push_back(std::move(panel));
|
||||
}
|
||||
}
|
||||
if (not current_column.empty()) {
|
||||
while (current_column.size() < 3) {
|
||||
current_column.push_back(std::make_shared<EmptyPanel>());
|
||||
}
|
||||
ribbon.layout.push_back({current_column[0], current_column[1], current_column[2]});
|
||||
}
|
||||
}
|
||||
}
|
||||
return ribbon;
|
||||
}
|
||||
|
||||
void MusicSelect::Ribbon::move_right() {
|
||||
position = (position + 1) % layout.size();
|
||||
}
|
||||
|
||||
void MusicSelect::Ribbon::move_left() {
|
||||
if (position == 0) {
|
||||
position = layout.size() - 1;
|
||||
} else {
|
||||
position--;
|
||||
}
|
||||
}
|
||||
|
@ -11,10 +11,14 @@ namespace MusicSelect {
|
||||
Ribbon() = default;
|
||||
static Ribbon title_sort(const Data::SongList& song_list);
|
||||
static Ribbon test_sort();
|
||||
static Ribbon test2_sort();
|
||||
const auto& get_layout() {return layout;};
|
||||
const std::unique_ptr<MusicSelect::Panel>& at(unsigned int button_index) const;
|
||||
const std::shared_ptr<MusicSelect::Panel>& at(unsigned int button_index) const;
|
||||
void move_right();
|
||||
void move_left();
|
||||
private:
|
||||
std::vector<std::array<std::unique_ptr<Panel>,3>> layout;
|
||||
static Ribbon layout_from_map(const std::map<std::string,std::list<std::shared_ptr<Panel>>>& categories);
|
||||
std::vector<std::array<std::shared_ptr<Panel>,3>> layout;
|
||||
unsigned int position = 0;
|
||||
};
|
||||
}
|
40
src/Toolkit/AffineTransform.hpp
Normal file
40
src/Toolkit/AffineTransform.hpp
Normal file
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
namespace Toolkit {
|
||||
template<typename T>
|
||||
class AffineTransform {
|
||||
public:
|
||||
AffineTransform(T low_input, T high_input, T low_output, T high_output):
|
||||
m_low_input(low_input),
|
||||
m_high_input(high_input),
|
||||
m_low_output(low_output),
|
||||
m_high_output(high_output)
|
||||
{
|
||||
if (low_input == high_input) {
|
||||
throw std::invalid_argument("low and high input values for affine transform must be different !");
|
||||
}
|
||||
m_a = (high_output-low_output)/(high_input-low_input);
|
||||
m_b = (high_input*low_output - high_output*low_input)/(high_input-low_input);
|
||||
};
|
||||
T transform(T val) const {return m_a*val + m_b;};
|
||||
T clampedTransform(T val) const { return transform(std::clamp(val,m_low_input,m_high_input));};
|
||||
T backwards_transform(T val) const {
|
||||
// if we're too close to zero
|
||||
if (std::abs(m_a) < 10e-10) {
|
||||
throw std::runtime_error("Can't apply backwards transformation, coefficient is too close to zero");
|
||||
} else {
|
||||
return (val-m_b)/m_a;
|
||||
}
|
||||
};
|
||||
void setB(T b) {
|
||||
m_b = b;
|
||||
}
|
||||
private:
|
||||
T m_a;
|
||||
T m_b;
|
||||
T m_low_input;
|
||||
T m_high_input;
|
||||
T m_low_output;
|
||||
T m_high_output;
|
||||
};
|
||||
}
|
11
src/Toolkit/QuickRNG.cpp
Normal file
11
src/Toolkit/QuickRNG.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
#include "QuickRNG.hpp"
|
||||
|
||||
|
||||
Toolkit::UniformIntRNG::UniformIntRNG(int min, int max) : m_distribution(min, max) {
|
||||
std::random_device rd;
|
||||
m_generator = std::mt19937{rd()};
|
||||
}
|
||||
|
||||
int Toolkit::UniformIntRNG::generate() {
|
||||
return m_distribution(m_generator);
|
||||
}
|
14
src/Toolkit/QuickRNG.hpp
Normal file
14
src/Toolkit/QuickRNG.hpp
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <random>
|
||||
|
||||
namespace Toolkit {
|
||||
class UniformIntRNG {
|
||||
public:
|
||||
UniformIntRNG(int min, int max);
|
||||
int generate();
|
||||
private:
|
||||
std::mt19937 m_generator;
|
||||
std::uniform_int_distribution<> m_distribution;
|
||||
};
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user