9 Commits

31 changed files with 573 additions and 195 deletions

View File

@@ -1,10 +1,10 @@
{ {
"configurations": [ "configurations": [
{ {
"name": "JMinos", "name": "jminos",
"cppStandard": "c++20", "cppStandard": "c++20",
"compileCommands": ".vscode/compile_commands.json" "compileCommands": ".vscode/compile_commands.json"
} }
], ],
"version": 4 "version": 4
} }

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -38,10 +38,10 @@ _Repeat for every avaible actions._
The settings file has the following format: The settings file has the following format:
- The number of the chosen keybinds (from 0 to 4), stored with 1 byte - The number of the chosen keybinds (from 0 to 4), stored with 1 byte
- The size multiplier of the window, stored with 1 byte - The window size mode, stored with 1 byte
- The number of the last selected gamemode (converted from an Enum), stored with 1 byte - The number of the last selected gamemode (converted from an Enum), stored with 1 byte
- The last selected width of the board, stored with 1 byte - The last selected width of the board, stored with 1 byte
- The last selected height of the board, stored with 1 byte - The last selected height of the board, stored with 1 byte
- The uniformity mode (0 for default distribution, 1 for uniformous distribution, 2 for custom distribution), stored with 1 byte - The uniformity mode (0 for default distribution, 1 for uniformous distribution, 2 for custom distribution), stored with 1 byte
- If custom distribution is set, store the proportion of each size (15x1 byte total) - If custom distribution is set, store the proportion of each size (15x1 byte total)
- Every selected pieces, using 1 byte for the type of selection (once again converted from an Enum) and 1 byte for the actual value - Every selected pieces, using 1 byte for the type of selection (once again converted from an Enum) and 1 byte for the actual value

View File

@@ -7,7 +7,6 @@ We will only talk about pieces and not polyominoes. In this project, pieces are
Each frame, the UI will translate the user's input into a series of action to apply to the game. The list of action is the following: Each frame, the UI will translate the user's input into a series of action to apply to the game. The list of action is the following:
- Quit the game
- Pause - Pause
- Retry - Retry
- Hold - Hold

View File

@@ -4,10 +4,9 @@
/** /**
* The list of actions that can be taken by the player * The list of in-game actions that can be taken by the player
*/ */
enum Action { enum Action {
QUIT,
PAUSE, PAUSE,
RETRY, RETRY,
HOLD, HOLD,
@@ -22,8 +21,20 @@ enum Action {
}; };
static const std::string ACTION_NAMES[] = { // name for each action static const Action ACTION_LIST_IN_ORDER[] = { // the list of possible actions in a sorted order
"Quit", MOVE_LEFT,
MOVE_RIGHT,
SOFT_DROP,
HARD_DROP,
ROTATE_CW,
ROTATE_CCW,
ROTATE_180,
ROTATE_0,
HOLD,
PAUSE,
RETRY
};
static const std::string ACTION_NAMES[] = { // name representation for each actions
"Pause", "Pause",
"Retry", "Retry",
"Hold", "Hold",

View File

@@ -6,6 +6,9 @@
#include <memory> #include <memory>
static const int DEFAULT_BOARD_WIDTH = 10; // the default width of the board when starting the menu
static const int DEFAULT_BOARD_HEIGHT = 20; // the default height of the board when starting the menu
Menu::Menu() { Menu::Menu() {
this->piecesList = std::make_shared<PiecesList>(PiecesList()); this->piecesList = std::make_shared<PiecesList>(PiecesList());

View File

@@ -4,9 +4,7 @@
#include "Player.h" #include "Player.h"
#include "Game.h" #include "Game.h"
static const int FRAMES_PER_SECOND = 60; // the number of frames per second, all the values in the app were choosen with this number in mind static const int FRAMES_PER_SECOND = 60; // the number of frames per second, all the values in the app were choosen with this number in mind
static const int DEFAULT_BOARD_WIDTH = 10; // the default width of the board when starting the menu
static const int DEFAULT_BOARD_HEIGHT = 20; // the default height of the board when starting the menu
/** /**

View File

@@ -1,20 +1,23 @@
#pragma once #pragma once
#include "Settings.h" #include "../Settings.h"
#include <stack> #include <stack>
#include <memory> #include <memory>
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
class AppMenu;
using MenuStack = std::stack<std::shared_ptr<AppMenu>>;
class AppMenu { class AppMenu {
protected: protected:
std::shared_ptr<std::stack<AppMenu>> menuStack; std::shared_ptr<MenuStack> menuStack;
std::shared_ptr<Settings> settings; std::shared_ptr<Settings> settings;
std::shared_ptr<sf::RenderWindow> renderWindow; std::shared_ptr<sf::RenderWindow> renderWindow;
public: public:
AppMenu(std::shared_ptr<std::stack<AppMenu>> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow) : AppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow) :
menuStack(menuStack), menuStack(menuStack),
settings(settings), settings(settings),
renderWindow(renderWindow) renderWindow(renderWindow)

View File

@@ -0,0 +1,96 @@
#include "InGameAppMenu.h"
#include "AppMenu.h"
#include <stack>
#include <memory>
#include <SFML/Graphics.hpp>
InGameAppMenu::InGameAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow) :
AppMenu(menuStack, settings, renderWindow),
game(this->settings->getMenu().startGame(this->settings->getGamemode()))
{
this->paused = false;
}
void InGameAppMenu::computeFrame() {
std::set<Action> actions;
for (Action action : ACTION_LIST_IN_ORDER) {
for (sfKey key : this->settings->getKeybinds().getKeybinds(action)) {
if (sf::Keyboard::isKeyPressed(key)) {
actions.insert(action);
}
}
}
if (actions.contains(RETRY)) {
this->game.reset();
this->game.start();
}
if (actions.contains(PAUSE)) {
this->paused = (!this->paused);
}
if (!paused) {
this->game.nextFrame(actions);
}
if (sf::Keyboard::isKeyPressed(sfKey::Escape)) {
this->menuStack->pop();
}
}
void InGameAppMenu::drawFrame() const {
this->renderWindow->clear(sf::Color::Black);
for (int y = this->game.getBoard().getBaseHeight() + 5; y >= 0; y--) {
for (int x = 0; x < this->game.getBoard().getWidth(); x++) {
bool isActivePieceHere = (this->game.getActivePiece() != nullptr) && (this->game.getActivePiece()->getPositions().contains(Position{x, y} - this->game.getActivePiecePosition()));
bool isGhostPieceHere = (this->game.getActivePiece() != nullptr) && (this->game.getActivePiece()->getPositions().contains(Position{x, y} - this->game.ghostPiecePosition()));
Block block = (isActivePieceHere || isGhostPieceHere) ? this->game.getActivePiece()->getBlockType() : this->game.getBoard().getBlock(Position{x, y});
sf::RectangleShape cell(sf::Vector2f(20.f, 20.f));
cell.setFillColor(sf::Color(BLOCKS_COLOR[block].red, BLOCKS_COLOR[block].green, BLOCKS_COLOR[block].blue, (isGhostPieceHere && !isActivePieceHere) ? 150 : 255));
cell.setPosition(sf::Vector2f(x*20, (this->game.getBoard().getBaseHeight() + 10 - y)*20));
this->renderWindow->draw(cell);
}
}
if (this->game.getNextPieces().size() > 0) {
for (int y = 10; y >= 0; y--) {
for (int x = 0; x <= 10; x++) {
Block block = this->game.getNextPieces().at(0).getBlockType();
sf::RectangleShape cell(sf::Vector2f(20.f, 20.f));
cell.setPosition(sf::Vector2f((x + 2 + this->game.getBoard().getWidth())*20, (this->game.getBoard().getBaseHeight() - y)*20));
if (this->game.getNextPieces().at(0).getPositions().contains(Position({x, y}))) {
cell.setFillColor(sf::Color(BLOCKS_COLOR[block].red, BLOCKS_COLOR[block].green, BLOCKS_COLOR[block].blue));
}
else {
cell.setFillColor(sf::Color(0, 0, 0));
}
this->renderWindow->draw(cell);
}
}
}
if (this->game.getHeldPiece() != nullptr) {
for (int y = 10; y >= 0; y--) {
for (int x = 0; x <= 10; x++) {
Block block = this->game.getHeldPiece()->getBlockType();
sf::RectangleShape cell(sf::Vector2f(20.f, 20.f));
cell.setPosition(sf::Vector2f((x + 12 + this->game.getBoard().getWidth())*20, (this->game.getBoard().getBaseHeight() - y)*20));
if (this->game.getHeldPiece()->getPositions().contains(Position({x, y}))) {
cell.setFillColor(sf::Color(BLOCKS_COLOR[block].red, BLOCKS_COLOR[block].green, BLOCKS_COLOR[block].blue));
}
else {
cell.setFillColor(sf::Color(0, 0, 0));
}
this->renderWindow->draw(cell);
}
}
}
this->renderWindow->display();
}

View File

@@ -0,0 +1,21 @@
#pragma once
#include "AppMenu.h"
#include <stack>
#include <memory>
#include <SFML/Graphics.hpp>
class InGameAppMenu : public AppMenu {
private:
Game game;
bool paused;
public:
InGameAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow);
void computeFrame();
void drawFrame() const;
};

View File

@@ -1,21 +1,29 @@
#include "MainAppMenu.h" #include "MainAppMenu.h"
#include "AppMenu.h" #include "AppMenu.h"
#include "InGameAppMenu.h"
#include <stack> #include <stack>
#include <memory> #include <memory>
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
MainAppMenu::MainAppMenu(std::shared_ptr<std::stack<AppMenu>> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow) : MainAppMenu::MainAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow) :
AppMenu(menuStack, settings, renderWindow) { AppMenu(menuStack, settings, renderWindow) {
} }
void MainAppMenu::computeFrame() { void MainAppMenu::computeFrame() {
if (sf::Keyboard::isKeyPressed(sfKey::Enter)) {
this->menuStack->push(std::make_shared<InGameAppMenu>(this->menuStack, this->settings, this->renderWindow));
}
else if (sf::Keyboard::isKeyPressed(sfKey::Escape)) {
this->menuStack->pop();
}
} }
void MainAppMenu::drawFrame() const { void MainAppMenu::drawFrame() const {
this->renderWindow->clear(sf::Color::Black);
this->renderWindow->display();
} }

View File

@@ -9,7 +9,7 @@
class MainAppMenu : public AppMenu { class MainAppMenu : public AppMenu {
public: public:
MainAppMenu(std::shared_ptr<std::stack<AppMenu>> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow); MainAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow);
void computeFrame(); void computeFrame();

View File

@@ -8,24 +8,24 @@
#include <memory> #include <memory>
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
static const double TIME_BETWEEN_FRAMES = (1000.f / 60.f); static const double TIME_BETWEEN_FRAMES = (1000.f / FRAMES_PER_SECOND);
GraphApp::GraphApp() { GraphApp::GraphApp() {
this->settings = std::make_shared<Settings>(); this->settings = std::make_shared<Settings>();
this->menuStack = std::make_shared<std::stack<AppMenu>>(); this->menuStack = std::make_shared<MenuStack>();
this->window = std::make_shared<sf::RenderWindow>(); this->renderWindow = std::make_shared<sf::RenderWindow>();
} }
void GraphApp::startApp() { void GraphApp::run() {
changeVideoMode(*this->window, this->settings->getVideoMode()); changeVideoMode(*this->renderWindow, this->settings->getVideoMode());
this->menuStack->push(MainAppMenu(this->menuStack, this->settings, this->window)); this->menuStack->push(std::make_shared<MainAppMenu>(this->menuStack, this->settings, this->renderWindow));
bool quit = false; bool quit = false;
double timeAtNextFrame = 0; double timeAtNextFrame = 0;
sf::Clock clock; sf::Clock clock;
while (!quit) { while (!quit) {
while (const std::optional event = this->window->pollEvent()) { while (const std::optional event = this->renderWindow->pollEvent()) {
if (event->is<sf::Event::Closed>()) { if (event->is<sf::Event::Closed>()) {
quit = true; quit = true;
} }
@@ -34,16 +34,16 @@ void GraphApp::startApp() {
if (!quit) { if (!quit) {
if (clock.getElapsedTime().asMilliseconds() > timeAtNextFrame) { if (clock.getElapsedTime().asMilliseconds() > timeAtNextFrame) {
timeAtNextFrame += TIME_BETWEEN_FRAMES; timeAtNextFrame += TIME_BETWEEN_FRAMES;
this->menuStack->top().computeFrame(); this->menuStack->top()->computeFrame();
if (this->menuStack->empty()) { if (this->menuStack->empty()) {
quit = true; quit = true;
} }
else { else {
this->menuStack->top().drawFrame(); this->menuStack->top()->drawFrame();
} }
} }
} }
} }
window->close(); renderWindow->close();
} }

View File

@@ -11,11 +11,11 @@
class GraphApp { class GraphApp {
private: private:
std::shared_ptr<Settings> settings; std::shared_ptr<Settings> settings;
std::shared_ptr<std::stack<AppMenu>> menuStack; std::shared_ptr<MenuStack> menuStack;
std::shared_ptr<sf::RenderWindow> window; std::shared_ptr<sf::RenderWindow> renderWindow;
public: public:
GraphApp(); GraphApp();
void startApp(); void run();
}; };

View File

@@ -0,0 +1,81 @@
#include "Keybinds.h"
#include "../Core/Action.h"
#include <map>
#include <set>
#include <fstream>
#include <SFML/Graphics.hpp>
Keybinds::Keybinds(int layoutNumber) :
layoutNumber(layoutNumber) {
for (Action action : ACTION_LIST_IN_ORDER) {
this->keybinds.insert({action, std::set<sfKey>()});
}
this->loadKeybindsFromFile();
}
void Keybinds::loadKeybindsFromFile() {
std::ifstream layoutFile("data/config/keybinds/layout" + std::to_string(this->layoutNumber) + ".bin", std::ios::binary);
for (Action action : ACTION_LIST_IN_ORDER) {
this->keybinds.at(action).clear();
}
char byte;
while (layoutFile.get(&byte, 1)) {
Action action = Action(byte);
do {
layoutFile.get(&byte, 1);
if (byte != 0xFF) {
this->keybinds.at(action).insert(sfKey(byte));
}
} while (byte != 0xFF);
}
}
void Keybinds::saveKeybindsToFile() const {
std::ofstream layoutFile("data/config/keybinds/layout" + std::to_string(this->layoutNumber) + ".bin", std::ios::trunc | std::ios::binary);
char byte;
for (Action action : ACTION_LIST_IN_ORDER) {
byte = action;
layoutFile.write(&byte, 1);
for (sfKey key : this->keybinds.at(action)) {
byte = (int) key;
layoutFile.write(&byte, 1);
}
byte = 0xFF;
layoutFile.write(&byte, 1);
}
}
void Keybinds::addKey(Action action, sfKey key) {
this->keybinds.at(action).insert(key);
}
void Keybinds::clearKeys(Action action) {
this->keybinds.at(action).clear();
}
const std::set<Action> Keybinds::getActions(sfKey key) const {
std::set<Action> actions;
for (const auto& [action, keys] : this->keybinds) {
if (keys.contains(key)) {
actions.insert(action);
}
}
return actions;
}
const std::set<sfKey>& Keybinds::getKeybinds(Action action) const {
return this->keybinds.at(action);
}

View File

@@ -3,30 +3,32 @@
#include "../Core/Action.h" #include "../Core/Action.h"
#include <map> #include <map>
#include <vector> #include <set>
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
using sfKey = sf::Keyboard::Key; using sfKey = sf::Keyboard::Key;
static const int NUMBER_OF_KEYBINDS = 5;
static const int CUSTOMIZABLE_KEYBINDS = NUMBER_OF_KEYBINDS - 1;
class Keybinds { class Keybinds {
private: private:
std::map<Action, std::vector<sfKey>> keybinds; std::map<Action, std::set<sfKey>> keybinds;
int layoutNumber;
public: public:
Keybinds(); Keybinds(int layoutNumber);
void loadKeybindsFromFile(); void loadKeybindsFromFile();
void saveKeybindsToFile() const; void saveKeybindsToFile() const;
void createDefaultKeybindsFile() const;
void addKey(Action action, sfKey key); void addKey(Action action, sfKey key);
void clearKeys(Action action); void clearKeys(Action action);
const std::vector<Action>& getActions(sfKey key) const; const std::set<Action> getActions(sfKey key) const;
const std::vector<sfKey>& getKeybinds(Action action) const; const std::set<sfKey>& getKeybinds(Action action) const;
}; };

View File

@@ -0,0 +1,21 @@
#pragma once
enum PiecesType {
CONVEX_PIECES,
HOLELESS_PIECES,
OTHER_PIECES,
ALL_PIECES,
SINGLE_PIECE
};
inline int getSizeOfPieces(PiecesType type) {
if (type < SINGLE_PIECE) return 0;
else return (type - SINGLE_PIECE + 1);
}
inline PiecesType createSinglePieceType(int size) {
return PiecesType(SINGLE_PIECE + size - 1);
}

View File

@@ -4,66 +4,171 @@
#include "Keybinds.h" #include "Keybinds.h"
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
#include <fstream>
static const int NUMBER_OF_KEYBINDS = 5;
static const int CUSTOMIZABLE_KEYBINDS = NUMBER_OF_KEYBINDS - 1;
static const sf::Vector2u BASE_WINDOW_SIZE = {80, 50}; static const sf::Vector2u BASE_WINDOW_SIZE = {80, 50};
static const int WINDOW_SIZE_MULTIPLIERS[] = {4, 6, 9, 14, 20}; static const int WINDOW_SIZE_MULTIPLIERS[] = {4, 6, 9, 14, 20};
static const int WINDOW_SIZE_LAST_MODE = (sizeof(WINDOW_SIZE_MULTIPLIERS) / sizeof(int)) - 1; static const int WINDOW_SIZE_LAST_MODE = (sizeof(WINDOW_SIZE_MULTIPLIERS) / sizeof(int)) - 1;
Settings::Settings() { Settings::Settings() {
for (int i = 1; i <= 15; i++) { for (int i = 1; i <= MAXIMUM_PIECES_SIZE; i++) {
this->menu.getPiecesList().loadPieces(i); this->menu.getPiecesList().loadPieces(i);
} }
this->keybinds.reserve(NUMBER_OF_KEYBINDS);
for (int i = 0; i < NUMBER_OF_KEYBINDS; i++) {
this->keybinds.emplace_back(i);
}
this->loadSettingsFromFile(); this->loadSettingsFromFile();
} }
void Settings::loadSettingsFromFile() { void Settings::loadSettingsFromFile() {
this->menu.getPiecesList().unselectAll(); std::ifstream settingsFile("data/config/settings.bin", std::ios::binary);
this->menu.getPiecesList().selectAllPieces(4); char byte;
this->windowSizeMode = 2;
// keybind layout
settingsFile.get(&byte, 1);
this->chosenKeybinds = byte;
// window size mode
settingsFile.get(&byte, 1);
this->windowSizeMode = byte;
// gamemode
settingsFile.get(&byte, 1);
this->gamemode = Gamemode(byte);
// board width
settingsFile.get(&byte, 1);
this->menu.setBoardWidth(byte);
// board height
settingsFile.get(&byte, 1);
this->menu.setBoardHeight(byte);
// piece distribution
settingsFile.get(&byte, 1);
//TODO
// selected pieces
char pieceType;
char pieceValue;
this->selectedPieces.clear();
while (settingsFile.get(&pieceType, 1)) {
settingsFile.get(&pieceValue, 1);
this->selectedPieces.push_back({PiecesType(pieceType), pieceValue});
}
} }
void Settings::saveSettingsToFile() const { void Settings::saveSettingsToFile() const {
std::ofstream settingsFile("data/config/settings.bin", std::ios::trunc | std::ios::binary);
char byte;
} // keybind layout
byte = this->chosenKeybinds;
settingsFile.write(&byte, 1);
void Settings::createDefaultSettingsFile() const { // window size mode
byte = this->windowSizeMode;
settingsFile.write(&byte, 1);
// gamemode
byte = this->gamemode;
settingsFile.write(&byte, 1);
// board width
byte = this->menu.getBoardWidth();
settingsFile.write(&byte, 1);
// board height
byte = this->menu.getBoardHeight();
settingsFile.write(&byte, 1);
// piece distribution
//TODO
settingsFile.write(&byte, 1);
// selected pieces
for (const auto& [type, value] : this->selectedPieces) {
byte = type;
settingsFile.write(&byte, 1);
byte = value;
settingsFile.write(&byte, 1);
}
} }
bool Settings::selectNextKeybinds() { bool Settings::selectNextKeybinds() {
if (this->chosenKeybinds < NUMBER_OF_KEYBINDS) { if (this->chosenKeybinds < NUMBER_OF_KEYBINDS) {
this->chosenKeybinds++; this->chosenKeybinds++;
return true;
} }
return false;
} }
bool Settings::selectPreviousKeybinds() { bool Settings::selectPreviousKeybinds() {
if (this->chosenKeybinds > 0) { if (this->chosenKeybinds > 0) {
this->chosenKeybinds--; this->chosenKeybinds--;
return true;
} }
return false;
} }
bool Settings::canModifyCurrentKeybinds() const { bool Settings::canModifyCurrentKeybinds() const {
return (this->chosenKeybinds == CUSTOMIZABLE_KEYBINDS); return (this->chosenKeybinds == CUSTOMIZABLE_KEYBINDS);
} }
void Settings::setGamemode(Gamemode gamemode) {
this->gamemode = gamemode;
}
bool Settings::widenWindow() { bool Settings::widenWindow() {
if (this->windowSizeMode < WINDOW_SIZE_LAST_MODE) { if (this->windowSizeMode < WINDOW_SIZE_LAST_MODE) {
this->windowSizeMode++; this->windowSizeMode++;
return true;
} }
return false;
} }
bool Settings::shortenWindow() { bool Settings::shortenWindow() {
if (this->windowSizeMode > 0) { if (this->windowSizeMode > 0) {
this->windowSizeMode--; this->windowSizeMode--;
return true;
} }
return false;
} }
void Settings::setGamemode(Gamemode gamemode) { void Settings::selectPieces(PiecesType type, int value) {
this->gamemode = gamemode; this->selectedPieces.emplace_back(type, value);
}
void Settings::unselectPieces(int index) {
if (index >= this->selectedPieces.size()) return;
this->selectedPieces.erase(this->selectedPieces.begin() + index);
}
void Settings::confirmSelectedPieces() {
this->menu.getPiecesList().unselectAll();
for (const auto& [type, value] : this->selectedPieces) {
int size = getSizeOfPieces(type);
if (size == 0) {
switch (type) {
case CONVEX_PIECES : {this->menu.getPiecesList().selectConvexPieces(value); break;}
case HOLELESS_PIECES : {this->menu.getPiecesList().selectHolelessPieces(value); break;}
case OTHER_PIECES : {this->menu.getPiecesList().selectOtherPieces(value); break;}
case ALL_PIECES : {this->menu.getPiecesList().selectAllPieces(value); break;}
}
}
else {
if (size > MAXIMUM_PIECES_SIZE) return;
this->menu.getPiecesList().selectPiece(size, value);
}
}
} }
Menu& Settings::getMenu() { Menu& Settings::getMenu() {
@@ -82,6 +187,10 @@ int Settings::getWindowSizeMultiplier() const {
return WINDOW_SIZE_MULTIPLIERS[this->windowSizeMode]; return WINDOW_SIZE_MULTIPLIERS[this->windowSizeMode];
} }
const sf::VideoMode& Settings::getVideoMode() const { const sf::VideoMode Settings::getVideoMode() const {
return sf::VideoMode(BASE_WINDOW_SIZE * (unsigned int) WINDOW_SIZE_MULTIPLIERS[this->windowSizeMode]); return sf::VideoMode(BASE_WINDOW_SIZE * (unsigned int) WINDOW_SIZE_MULTIPLIERS[this->windowSizeMode]);
} }
const std::vector<std::pair<PiecesType, int>>& Settings::getSelectedPieces() const {
return this->selectedPieces;
}

View File

@@ -2,10 +2,16 @@
#include "../Core/Menu.h" #include "../Core/Menu.h"
#include "Keybinds.h" #include "Keybinds.h"
#include "PiecesType.h"
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
#include <vector> #include <vector>
static const int MAXIMUM_BOARD_WIDTH = 40;
static const int MAXIMUM_BOARD_HEIGHT = 40;
static const int MAXIMUM_PIECES_SIZE = 10;
class Settings { class Settings {
private: private:
@@ -14,6 +20,7 @@ class Settings {
int chosenKeybinds; int chosenKeybinds;
Gamemode gamemode; Gamemode gamemode;
int windowSizeMode; int windowSizeMode;
std::vector<std::pair<PiecesType, int>> selectedPieces;
public: public:
Settings(); Settings();
@@ -22,8 +29,6 @@ class Settings {
void saveSettingsToFile() const; void saveSettingsToFile() const;
void createDefaultSettingsFile() const;
bool selectNextKeybinds(); bool selectNextKeybinds();
bool selectPreviousKeybinds(); bool selectPreviousKeybinds();
@@ -36,6 +41,12 @@ class Settings {
bool shortenWindow(); bool shortenWindow();
void selectPieces(PiecesType type, int value);
void unselectPieces(int index);
void confirmSelectedPieces();
Menu& getMenu(); Menu& getMenu();
Keybinds& getKeybinds(); Keybinds& getKeybinds();
@@ -44,5 +55,7 @@ class Settings {
int getWindowSizeMultiplier() const; int getWindowSizeMultiplier() const;
const sf::VideoMode& getVideoMode() const; const sf::VideoMode getVideoMode() const;
const std::vector<std::pair<PiecesType, int>>& getSelectedPieces() const;
}; };

View File

@@ -1,138 +1,153 @@
#include <SFML/Graphics.hpp> #include "GraphApp.h"
#include "../Core/Menu.h"
#include "../Pieces/PiecesFiles.h" #include "../Pieces/PiecesFiles.h"
#include <iostream>
void setToDefaultConfig(); #include <fstream>
void resetConfigFiles();
void resetSettingsFile();
void resetKeybindFile(int layout);
int main() { int main() {
std::srand(std::time(NULL)); std::srand(std::time(NULL));
sf::RenderWindow window(sf::VideoMode({800, 640}), "My window", sf::Style::Titlebar | sf::Style::Close); // keep only for dev
window.setPosition(sf::Vector2i(sf::VideoMode::getDesktopMode().size.x / 2 - 400, sf::VideoMode::getDesktopMode().size.y / 2 - 320));
PiecesFiles pf; PiecesFiles pf;
for (int i = 1; i <= 10; i++) { for (int i = 1; i <= MAXIMUM_PIECES_SIZE; i++) {
pf.savePieces(i); if (!std::filesystem::exists("data/pieces/" + std::to_string(i) + "minos.bin")) {
std::cout << "pieces files for size " << i << " not found, generating..." << std::endl;
pf.savePieces(i);
}
}
if (!std::filesystem::exists("data/config/settings.bin")) {
resetSettingsFile();
}
for (int i = 0; i < 5; i++) {
if (!std::filesystem::exists("data/config/keybinds/layout" + std::to_string(i) + ".bin")) {
resetKeybindFile(i);
}
} }
Menu m; // before compiling release version
m.getPiecesList().loadPieces(10); //resetConfigFiles();
m.getPiecesList().selectAllPieces(4);
m.setBoardWidth(10);
m.getPlayerControls().setDAS(6);
m.getPlayerControls().setARR(0);
m.getPlayerControls().setSDR(0);
Game game = m.startGame(SPRINT);
game.start();
sf::Clock clock; GraphApp UI;
UI.run();
sf::Font font; return 0;
if (!font.openFromFile("data/fonts/arial.ttf")) { }
std::cout << "aaaaaaaaaaaaaa";
}
sf::Text text(font);
text.setCharacterSize(20);
text.setFillColor(sf::Color::White);
while (window.isOpen()) {
while (const std::optional event = window.pollEvent()) {
if (event->is<sf::Event::Closed>())
window.close();
}
if (clock.getElapsedTime().asMilliseconds() > 16) { void resetConfigFiles() {
clock.restart(); resetSettingsFile;
for (int i = 0; i < 5; i++) {
window.clear(sf::Color::Black); resetKeybindFile(i);
}
std::set<Action> actions; }
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Left)) {
actions.insert(MOVE_LEFT); void resetSettingsFile() {
} std::ofstream settingsFile("data/config/settings.bin", std::ios::trunc | std::ios::binary);
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Right)) { char byte;
actions.insert(MOVE_RIGHT);
} // keybind layout
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Up)) { byte = 0;
actions.insert(HARD_DROP); settingsFile.write(&byte, 1);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Down)) { // window size mode
actions.insert(SOFT_DROP); byte = 2;
} settingsFile.write(&byte, 1);
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::A)) {
actions.insert(ROTATE_CCW); // gamemode
} byte = SPRINT;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::E)) { settingsFile.write(&byte, 1);
actions.insert(ROTATE_CW);
} // board width
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Z)) { byte = 10;
actions.insert(HOLD); settingsFile.write(&byte, 1);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Tab)) { // board height
actions.insert(ROTATE_0); byte = 20;
} settingsFile.write(&byte, 1);
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Num2)) {
actions.insert(ROTATE_180); // piece distribution
} byte = 0;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::R)) { settingsFile.write(&byte, 1);
game.reset();
game.start(); // selected pieces
} byte = ALL_PIECES;
game.nextFrame(actions); settingsFile.write(&byte, 1);
byte = 4;
for (int y = game.getBoard().getBaseHeight() + 5; y >= 0; y--) { settingsFile.write(&byte, 1);
for (int x = 0; x < game.getBoard().getWidth(); x++) { }
bool isActivePieceHere = (game.getActivePiece() != nullptr) && (game.getActivePiece()->getPositions().contains(Position{x, y} - game.getActivePiecePosition()));
bool isGhostPieceHere = (game.getActivePiece() != nullptr) && (game.getActivePiece()->getPositions().contains(Position{x, y} - game.ghostPiecePosition())); void resetKeybindFile(int layout) {
Block block = (isActivePieceHere || isGhostPieceHere) ? game.getActivePiece()->getBlockType() : game.getBoard().getBlock(Position{x, y}); if (layout < 0 || layout > 4) return;
sf::RectangleShape cell(sf::Vector2f(20.f, 20.f)); std::ofstream layoutFile("data/config/keybinds/layout" + std::to_string(layout) + ".bin", std::ios::trunc | std::ios::binary);
cell.setFillColor(sf::Color(BLOCKS_COLOR[block].red, BLOCKS_COLOR[block].green, BLOCKS_COLOR[block].blue, (isGhostPieceHere && !isActivePieceHere) ? 150 : 255)); std::map<Action, sfKey> keybinds;
cell.setPosition(sf::Vector2f(x*20, (game.getBoard().getBaseHeight() + 10 - y)*20));
window.draw(cell); if (layout != 4) {
} keybinds.insert({PAUSE, sfKey::P});
} keybinds.insert({RETRY, sfKey::R});
}
if (game.getNextPieces().size() > 0) {
for (int y = 10; y >= 0; y--) { if (layout == 0) {
for (int x = 0; x <= 10; x++) { keybinds.insert({MOVE_LEFT, sfKey::Left});
Block block = game.getNextPieces().at(0).getBlockType(); keybinds.insert({MOVE_RIGHT, sfKey::Right});
sf::RectangleShape cell(sf::Vector2f(20.f, 20.f)); keybinds.insert({SOFT_DROP, sfKey::Down});
cell.setPosition(sf::Vector2f((x + 2 + game.getBoard().getWidth())*20, (game.getBoard().getBaseHeight() - y)*20)); keybinds.insert({HARD_DROP, sfKey::Space});
if (game.getNextPieces().at(0).getPositions().contains(Position({x, y}))) { keybinds.insert({ROTATE_CW, sfKey::Up});
cell.setFillColor(sf::Color(BLOCKS_COLOR[block].red, BLOCKS_COLOR[block].green, BLOCKS_COLOR[block].blue)); keybinds.insert({ROTATE_CCW, sfKey::Z});
} keybinds.insert({ROTATE_180, sfKey::X});
else { keybinds.insert({ROTATE_0, sfKey::LShift});
cell.setFillColor(sf::Color(0, 0, 0)); keybinds.insert({HOLD, sfKey::C});
} }
window.draw(cell); if (layout == 1) {
} keybinds.insert({MOVE_LEFT, sfKey::Z});
} keybinds.insert({MOVE_RIGHT, sfKey::C});
} keybinds.insert({SOFT_DROP, sfKey::X});
keybinds.insert({HARD_DROP, sfKey::S});
if (game.getHeldPiece() != nullptr) { keybinds.insert({ROTATE_CW, sfKey::M});
for (int y = 10; y >= 0; y--) { keybinds.insert({ROTATE_CCW, sfKey::Comma});
for (int x = 0; x <= 10; x++) { keybinds.insert({ROTATE_180, sfKey::J});
Block block = game.getHeldPiece()->getBlockType(); keybinds.insert({ROTATE_0, sfKey::K});
sf::RectangleShape cell(sf::Vector2f(20.f, 20.f)); keybinds.insert({HOLD, sfKey::LShift});
cell.setPosition(sf::Vector2f((x + 12 + game.getBoard().getWidth())*20, (game.getBoard().getBaseHeight() - y)*20)); }
if (game.getHeldPiece()->getPositions().contains(Position({x, y}))) { if (layout == 2) {
cell.setFillColor(sf::Color(BLOCKS_COLOR[block].red, BLOCKS_COLOR[block].green, BLOCKS_COLOR[block].blue)); keybinds.insert({MOVE_LEFT, sfKey::A});
} keybinds.insert({MOVE_RIGHT, sfKey::D});
else { keybinds.insert({SOFT_DROP, sfKey::W});
cell.setFillColor(sf::Color(0, 0, 0)); keybinds.insert({HARD_DROP, sfKey::S});
} keybinds.insert({ROTATE_CW, sfKey::Left});
window.draw(cell); keybinds.insert({ROTATE_CCW, sfKey::Right});
} keybinds.insert({ROTATE_180, sfKey::Up});
} keybinds.insert({ROTATE_0, sfKey::Down});
} keybinds.insert({HOLD, sfKey::RShift});
}
text.setPosition(sf::Vector2f(12*20, (game.getBoard().getBaseHeight() - 5)*20)); if (layout == 3) {
text.setString(sf::String(std::to_string(game.getClearedLines()))); keybinds.insert({MOVE_LEFT, sfKey::Left});
window.draw(text); keybinds.insert({MOVE_RIGHT, sfKey::Right});
keybinds.insert({SOFT_DROP, sfKey::Down});
window.display(); keybinds.insert({HARD_DROP, sfKey::Up});
} keybinds.insert({ROTATE_CW, sfKey::E});
keybinds.insert({ROTATE_CCW, sfKey::A});
keybinds.insert({ROTATE_180, sfKey::Num2});
keybinds.insert({ROTATE_0, sfKey::Tab});
keybinds.insert({HOLD, sfKey::Z});
}
char byte;
for (Action action : ACTION_LIST_IN_ORDER) {
byte = action;
layoutFile.write(&byte, 1);
if (keybinds.contains(action)) {
byte = (int) keybinds.at(action);
layoutFile.write(&byte, 1);
}
byte = 0xFF;
layoutFile.write(&byte, 1);
} }
} }

View File

@@ -136,7 +136,6 @@ void TextApp::seeKeybinds() const {
void TextApp::defaultKeybinds() { void TextApp::defaultKeybinds() {
this->keybinds.clear(); this->keybinds.clear();
this->keybinds.insert({"quit", QUIT});
this->keybinds.insert({"pause", PAUSE}); this->keybinds.insert({"pause", PAUSE});
this->keybinds.insert({"retry", RETRY}); this->keybinds.insert({"retry", RETRY});
this->keybinds.insert({"h", HOLD}); this->keybinds.insert({"h", HOLD});
@@ -171,15 +170,21 @@ void TextApp::startGame() const {
std::set<Action> playerActions; std::set<Action> playerActions;
std::set<Action> lastFrameActions; std::set<Action> lastFrameActions;
std::set<Action> metaActions; bool retrying = false;
for (std::string action : actions) { for (std::string action : actions) {
try { if (action == "quit") {
Action playerAction = this->keybinds.at(action); quit = true;
if (playerAction == PAUSE || playerAction == RETRY || playerAction == quit) { }
metaActions.insert(playerAction); else {
} try {
else { Action playerAction = this->keybinds.at(action);
if (playerAction == SOFT_DROP || playerAction == MOVE_LEFT || playerAction == MOVE_RIGHT) { if (playerAction == RETRY) {
retrying = true;
}
else if (playerAction == PAUSE) {
paused = (!paused);
}
else if (playerAction == SOFT_DROP || playerAction == MOVE_LEFT || playerAction == MOVE_RIGHT) {
playerActions.insert(playerAction); playerActions.insert(playerAction);
lastFrameActions.insert(playerAction); lastFrameActions.insert(playerAction);
} }
@@ -190,19 +195,12 @@ void TextApp::startGame() const {
playerActions.insert(playerAction); playerActions.insert(playerAction);
} }
} }
catch (std::exception ignored) {}
} }
catch (std::exception ignored) {}
} }
if (metaActions.contains(PAUSE)) { if (!paused && !quit) {
paused = (!paused); if (retrying) {
}
if (!paused) {
if (metaActions.contains(QUIT)) {
quit = true;
}
else if (metaActions.contains(RETRY)) {
game.reset(); game.reset();
game.start(); game.start();
} }