9 Commits

31 changed files with 573 additions and 195 deletions

View File

@@ -1,10 +1,10 @@
{
"configurations": [
{
"name": "JMinos",
"name": "jminos",
"cppStandard": "c++20",
"compileCommands": ".vscode/compile_commands.json"
}
],
"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 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 last selected width 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
- 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:
- Quit the game
- Pause
- Retry
- 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 {
QUIT,
PAUSE,
RETRY,
HOLD,
@@ -22,8 +21,20 @@ enum Action {
};
static const std::string ACTION_NAMES[] = { // name for each action
"Quit",
static const Action ACTION_LIST_IN_ORDER[] = { // the list of possible actions in a sorted order
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",
"Retry",
"Hold",

View File

@@ -6,6 +6,9 @@
#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() {
this->piecesList = std::make_shared<PiecesList>(PiecesList());

View File

@@ -4,9 +4,7 @@
#include "Player.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 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
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
/**

View File

@@ -1,20 +1,23 @@
#pragma once
#include "Settings.h"
#include "../Settings.h"
#include <stack>
#include <memory>
#include <SFML/Graphics.hpp>
class AppMenu;
using MenuStack = std::stack<std::shared_ptr<AppMenu>>;
class AppMenu {
protected:
std::shared_ptr<std::stack<AppMenu>> menuStack;
std::shared_ptr<MenuStack> menuStack;
std::shared_ptr<Settings> settings;
std::shared_ptr<sf::RenderWindow> renderWindow;
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),
settings(settings),
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 "AppMenu.h"
#include "InGameAppMenu.h"
#include <stack>
#include <memory>
#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) {
}
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 {
this->renderWindow->clear(sf::Color::Black);
this->renderWindow->display();
}

View File

@@ -9,7 +9,7 @@
class MainAppMenu : public AppMenu {
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();

View File

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

View File

@@ -11,11 +11,11 @@
class GraphApp {
private:
std::shared_ptr<Settings> settings;
std::shared_ptr<std::stack<AppMenu>> menuStack;
std::shared_ptr<sf::RenderWindow> window;
std::shared_ptr<MenuStack> menuStack;
std::shared_ptr<sf::RenderWindow> renderWindow;
public:
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 <map>
#include <vector>
#include <set>
#include <SFML/Graphics.hpp>
using sfKey = sf::Keyboard::Key;
static const int NUMBER_OF_KEYBINDS = 5;
static const int CUSTOMIZABLE_KEYBINDS = NUMBER_OF_KEYBINDS - 1;
class Keybinds {
private:
std::map<Action, std::vector<sfKey>> keybinds;
std::map<Action, std::set<sfKey>> keybinds;
int layoutNumber;
public:
Keybinds();
Keybinds(int layoutNumber);
void loadKeybindsFromFile();
void saveKeybindsToFile() const;
void createDefaultKeybindsFile() const;
void addKey(Action action, sfKey key);
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 <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 int WINDOW_SIZE_MULTIPLIERS[] = {4, 6, 9, 14, 20};
static const int WINDOW_SIZE_LAST_MODE = (sizeof(WINDOW_SIZE_MULTIPLIERS) / sizeof(int)) - 1;
Settings::Settings() {
for (int i = 1; i <= 15; i++) {
for (int i = 1; i <= MAXIMUM_PIECES_SIZE; 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();
}
void Settings::loadSettingsFromFile() {
this->menu.getPiecesList().unselectAll();
this->menu.getPiecesList().selectAllPieces(4);
this->windowSizeMode = 2;
std::ifstream settingsFile("data/config/settings.bin", std::ios::binary);
char byte;
// 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 {
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() {
if (this->chosenKeybinds < NUMBER_OF_KEYBINDS) {
this->chosenKeybinds++;
return true;
}
return false;
}
bool Settings::selectPreviousKeybinds() {
if (this->chosenKeybinds > 0) {
this->chosenKeybinds--;
return true;
}
return false;
}
bool Settings::canModifyCurrentKeybinds() const {
return (this->chosenKeybinds == CUSTOMIZABLE_KEYBINDS);
}
void Settings::setGamemode(Gamemode gamemode) {
this->gamemode = gamemode;
}
bool Settings::widenWindow() {
if (this->windowSizeMode < WINDOW_SIZE_LAST_MODE) {
this->windowSizeMode++;
return true;
}
return false;
}
bool Settings::shortenWindow() {
if (this->windowSizeMode > 0) {
this->windowSizeMode--;
return true;
}
return false;
}
void Settings::setGamemode(Gamemode gamemode) {
this->gamemode = gamemode;
void Settings::selectPieces(PiecesType type, int value) {
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() {
@@ -82,6 +187,10 @@ int Settings::getWindowSizeMultiplier() const {
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]);
}
const std::vector<std::pair<PiecesType, int>>& Settings::getSelectedPieces() const {
return this->selectedPieces;
}

View File

@@ -2,10 +2,16 @@
#include "../Core/Menu.h"
#include "Keybinds.h"
#include "PiecesType.h"
#include <SFML/Graphics.hpp>
#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 {
private:
@@ -14,6 +20,7 @@ class Settings {
int chosenKeybinds;
Gamemode gamemode;
int windowSizeMode;
std::vector<std::pair<PiecesType, int>> selectedPieces;
public:
Settings();
@@ -22,8 +29,6 @@ class Settings {
void saveSettingsToFile() const;
void createDefaultSettingsFile() const;
bool selectNextKeybinds();
bool selectPreviousKeybinds();
@@ -36,6 +41,12 @@ class Settings {
bool shortenWindow();
void selectPieces(PiecesType type, int value);
void unselectPieces(int index);
void confirmSelectedPieces();
Menu& getMenu();
Keybinds& getKeybinds();
@@ -44,5 +55,7 @@ class Settings {
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 "../Core/Menu.h"
#include "GraphApp.h"
#include "../Pieces/PiecesFiles.h"
#include <iostream>
void setToDefaultConfig();
#include <fstream>
void resetConfigFiles();
void resetSettingsFile();
void resetKeybindFile(int layout);
int main() {
std::srand(std::time(NULL));
sf::RenderWindow window(sf::VideoMode({800, 640}), "My window", sf::Style::Titlebar | sf::Style::Close);
window.setPosition(sf::Vector2i(sf::VideoMode::getDesktopMode().size.x / 2 - 400, sf::VideoMode::getDesktopMode().size.y / 2 - 320));
// keep only for dev
PiecesFiles pf;
for (int i = 1; i <= 10; i++) {
pf.savePieces(i);
for (int i = 1; i <= MAXIMUM_PIECES_SIZE; 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;
m.getPiecesList().loadPieces(10);
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();
// before compiling release version
//resetConfigFiles();
sf::Clock clock;
GraphApp UI;
UI.run();
sf::Font font;
if (!font.openFromFile("data/fonts/arial.ttf")) {
std::cout << "aaaaaaaaaaaaaa";
}
sf::Text text(font);
text.setCharacterSize(20);
text.setFillColor(sf::Color::White);
return 0;
}
while (window.isOpen()) {
while (const std::optional event = window.pollEvent()) {
if (event->is<sf::Event::Closed>())
window.close();
}
if (clock.getElapsedTime().asMilliseconds() > 16) {
clock.restart();
window.clear(sf::Color::Black);
std::set<Action> actions;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Left)) {
actions.insert(MOVE_LEFT);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Right)) {
actions.insert(MOVE_RIGHT);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Up)) {
actions.insert(HARD_DROP);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Down)) {
actions.insert(SOFT_DROP);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::A)) {
actions.insert(ROTATE_CCW);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::E)) {
actions.insert(ROTATE_CW);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Z)) {
actions.insert(HOLD);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Tab)) {
actions.insert(ROTATE_0);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Num2)) {
actions.insert(ROTATE_180);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::R)) {
game.reset();
game.start();
}
game.nextFrame(actions);
for (int y = game.getBoard().getBaseHeight() + 5; y >= 0; y--) {
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()));
Block block = (isActivePieceHere || isGhostPieceHere) ? game.getActivePiece()->getBlockType() : 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, (game.getBoard().getBaseHeight() + 10 - y)*20));
window.draw(cell);
}
}
if (game.getNextPieces().size() > 0) {
for (int y = 10; y >= 0; y--) {
for (int x = 0; x <= 10; x++) {
Block block = game.getNextPieces().at(0).getBlockType();
sf::RectangleShape cell(sf::Vector2f(20.f, 20.f));
cell.setPosition(sf::Vector2f((x + 2 + game.getBoard().getWidth())*20, (game.getBoard().getBaseHeight() - y)*20));
if (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));
}
window.draw(cell);
}
}
}
if (game.getHeldPiece() != nullptr) {
for (int y = 10; y >= 0; y--) {
for (int x = 0; x <= 10; x++) {
Block block = game.getHeldPiece()->getBlockType();
sf::RectangleShape cell(sf::Vector2f(20.f, 20.f));
cell.setPosition(sf::Vector2f((x + 12 + game.getBoard().getWidth())*20, (game.getBoard().getBaseHeight() - y)*20));
if (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));
}
window.draw(cell);
}
}
}
text.setPosition(sf::Vector2f(12*20, (game.getBoard().getBaseHeight() - 5)*20));
text.setString(sf::String(std::to_string(game.getClearedLines())));
window.draw(text);
window.display();
}
void resetConfigFiles() {
resetSettingsFile;
for (int i = 0; i < 5; i++) {
resetKeybindFile(i);
}
}
void resetSettingsFile() {
std::ofstream settingsFile("data/config/settings.bin", std::ios::trunc | std::ios::binary);
char byte;
// keybind layout
byte = 0;
settingsFile.write(&byte, 1);
// window size mode
byte = 2;
settingsFile.write(&byte, 1);
// gamemode
byte = SPRINT;
settingsFile.write(&byte, 1);
// board width
byte = 10;
settingsFile.write(&byte, 1);
// board height
byte = 20;
settingsFile.write(&byte, 1);
// piece distribution
byte = 0;
settingsFile.write(&byte, 1);
// selected pieces
byte = ALL_PIECES;
settingsFile.write(&byte, 1);
byte = 4;
settingsFile.write(&byte, 1);
}
void resetKeybindFile(int layout) {
if (layout < 0 || layout > 4) return;
std::ofstream layoutFile("data/config/keybinds/layout" + std::to_string(layout) + ".bin", std::ios::trunc | std::ios::binary);
std::map<Action, sfKey> keybinds;
if (layout != 4) {
keybinds.insert({PAUSE, sfKey::P});
keybinds.insert({RETRY, sfKey::R});
}
if (layout == 0) {
keybinds.insert({MOVE_LEFT, sfKey::Left});
keybinds.insert({MOVE_RIGHT, sfKey::Right});
keybinds.insert({SOFT_DROP, sfKey::Down});
keybinds.insert({HARD_DROP, sfKey::Space});
keybinds.insert({ROTATE_CW, sfKey::Up});
keybinds.insert({ROTATE_CCW, sfKey::Z});
keybinds.insert({ROTATE_180, sfKey::X});
keybinds.insert({ROTATE_0, sfKey::LShift});
keybinds.insert({HOLD, sfKey::C});
}
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});
keybinds.insert({ROTATE_CW, sfKey::M});
keybinds.insert({ROTATE_CCW, sfKey::Comma});
keybinds.insert({ROTATE_180, sfKey::J});
keybinds.insert({ROTATE_0, sfKey::K});
keybinds.insert({HOLD, sfKey::LShift});
}
if (layout == 2) {
keybinds.insert({MOVE_LEFT, sfKey::A});
keybinds.insert({MOVE_RIGHT, sfKey::D});
keybinds.insert({SOFT_DROP, sfKey::W});
keybinds.insert({HARD_DROP, sfKey::S});
keybinds.insert({ROTATE_CW, sfKey::Left});
keybinds.insert({ROTATE_CCW, sfKey::Right});
keybinds.insert({ROTATE_180, sfKey::Up});
keybinds.insert({ROTATE_0, sfKey::Down});
keybinds.insert({HOLD, sfKey::RShift});
}
if (layout == 3) {
keybinds.insert({MOVE_LEFT, sfKey::Left});
keybinds.insert({MOVE_RIGHT, sfKey::Right});
keybinds.insert({SOFT_DROP, sfKey::Down});
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() {
this->keybinds.clear();
this->keybinds.insert({"quit", QUIT});
this->keybinds.insert({"pause", PAUSE});
this->keybinds.insert({"retry", RETRY});
this->keybinds.insert({"h", HOLD});
@@ -171,15 +170,21 @@ void TextApp::startGame() const {
std::set<Action> playerActions;
std::set<Action> lastFrameActions;
std::set<Action> metaActions;
bool retrying = false;
for (std::string action : actions) {
try {
Action playerAction = this->keybinds.at(action);
if (playerAction == PAUSE || playerAction == RETRY || playerAction == quit) {
metaActions.insert(playerAction);
}
else {
if (playerAction == SOFT_DROP || playerAction == MOVE_LEFT || playerAction == MOVE_RIGHT) {
if (action == "quit") {
quit = true;
}
else {
try {
Action playerAction = this->keybinds.at(action);
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);
lastFrameActions.insert(playerAction);
}
@@ -190,19 +195,12 @@ void TextApp::startGame() const {
playerActions.insert(playerAction);
}
}
catch (std::exception ignored) {}
}
catch (std::exception ignored) {}
}
if (metaActions.contains(PAUSE)) {
paused = (!paused);
}
if (!paused) {
if (metaActions.contains(QUIT)) {
quit = true;
}
else if (metaActions.contains(RETRY)) {
if (!paused && !quit) {
if (retrying) {
game.reset();
game.start();
}