Compare commits
13 Commits
v0.2
...
1a95765877
| Author | SHA1 | Date | |
|---|---|---|---|
| 1a95765877 | |||
| 6bff555cbc | |||
| f4b58fb67e | |||
| 0271b56542 | |||
| 5d73e751d7 | |||
| 314b7a8488 | |||
| 7151be0b1a | |||
| d124205a71 | |||
| 87920548e5 | |||
| 57620c70a2 | |||
| 3dac18c821 | |||
| 3538403f40 | |||
| ec40495328 |
@@ -25,7 +25,6 @@ If you want to know more details about the generation and classification of poly
|
||||
- ULTRA : scores as much as possible in only 2 minutes!
|
||||
- MASTER : clear 200 lines at levels higher than maximum gravity!
|
||||
- ZEN : practice indefinitely in this mode with no gravity!
|
||||
- ??? : still to do
|
||||
|
||||
## Manual build
|
||||
|
||||
|
||||
@@ -47,5 +47,8 @@ The settings file has the following format:
|
||||
- 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
|
||||
- For each size, store the custom proportion (from 0 to 10) (15x1 byte total)
|
||||
- Every selected pieces
|
||||
- For every groupe of piece (ALL, CONVEX, HOLELESS, OTHER), use 1 byte for the type (once again converted from an Enum) and 1 byte for the size
|
||||
- For every single piece, use 1 byte for (the size + encoding that it is a single piece),
|
||||
and 3 bytes to store the number of the piece (allows number up to 16M, size 15 has 6M pieces).
|
||||
|
||||
@@ -106,3 +106,17 @@ Grade is an alternate system to line clears.
|
||||
|
||||
The only exception occurs when the total ends in '99', a line must be cleared to progress.
|
||||
When this line is cleared, the point of the piece is also counted towards the total.
|
||||
|
||||
## Pieces distribution
|
||||
|
||||
A bag is an object which contains a set of pieces.
|
||||
The principle of a bag generator is to put every available pieces into a bag and take them out one by one until the bag is empty, to then start with a new full bag.
|
||||
It's a way to have equal distribution of pieces while still allowing for a random order of pieces.
|
||||
|
||||
The game has 3 modes of pieces distribution:
|
||||
|
||||
1. Default. The simplest of them, all selected pieces are put in a single bag.
|
||||
2. Uniformous. The pieces are now separated by size and put in different bags. Each size will now appear as often as any other.
|
||||
3. Custom. The pieces are once again separated by size, but now the player specifies how likely each size is to appear.
|
||||
|
||||
Both system 2 and 3 uses a system analogous to a bag to determine which size of piece to take next.
|
||||
|
||||
@@ -7,26 +7,54 @@
|
||||
#include <utility>
|
||||
#include <cstdlib>
|
||||
|
||||
static const double SMALLEST_CONSIDERED_PROPORTION = 0.01; // the smallest a proportion can get before it is considered equal to 0
|
||||
|
||||
|
||||
Bag::Bag(const std::shared_ptr<PiecesList>& piecesList) :
|
||||
piecesList(piecesList) {
|
||||
|
||||
this->currentBag = this->piecesList->getSelectedPieces();
|
||||
this->nextBag.clear();
|
||||
|
||||
this->highestSize = this->piecesList->getHighestLoadedSize();
|
||||
this->selectedPieces = this->piecesList->getSelectedPieces();
|
||||
this->distributionMode = this->piecesList->getDistributionMode();
|
||||
this->propotionsPerSize = this->piecesList->getProportionsPerSize();
|
||||
|
||||
this->currentBags.clear();
|
||||
this->nextBags.clear();
|
||||
this->sizesBag.clear();
|
||||
this->sizesProgression.clear();
|
||||
|
||||
if (this->distributionMode == DEFAULT) {
|
||||
this->currentBags.push_back(this->selectedPieces);
|
||||
this->nextBags.push_back({});
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i <= this->highestSize; i++) {
|
||||
this->currentBags.push_back(PieceBag());
|
||||
this->nextBags.push_back(PieceBag());
|
||||
this->sizesProgression.push_back(0);
|
||||
}
|
||||
|
||||
for (const auto& piece : this->selectedPieces) {
|
||||
int pieceSize = this->piecesList->lookAtPiece(piece).getPositions().size();
|
||||
this->currentBags.at(pieceSize).push_back(piece);
|
||||
}
|
||||
}
|
||||
|
||||
this->prepareNext();
|
||||
}
|
||||
|
||||
void Bag::jumpToNextBag() {
|
||||
if (this->currentBag.size() < this->nextBag.size()) {
|
||||
std::swap(this->currentBag, this->nextBag);
|
||||
for (int i = 0; i < this->currentBags.size(); i++) {
|
||||
if (this->currentBags.at(i).size() < this->nextBags.at(i).size()) {
|
||||
std::swap(this->currentBags.at(i), this->nextBags.at(i));
|
||||
}
|
||||
|
||||
for (const auto& piece : this->nextBags.at(i)) {
|
||||
this->currentBags.at(i).push_back(piece);
|
||||
}
|
||||
this->nextBags.at(i).clear();
|
||||
}
|
||||
|
||||
for (const std::pair<int, int>& pieceIndex : this->nextBag) {
|
||||
this->currentBag.push_back(pieceIndex);
|
||||
}
|
||||
this->nextBag.clear();
|
||||
|
||||
this->prepareNext();
|
||||
}
|
||||
|
||||
@@ -43,13 +71,40 @@ Piece Bag::getNext() {
|
||||
}
|
||||
|
||||
void Bag::prepareNext() {
|
||||
if (this->currentBag.empty()) {
|
||||
std::swap(this->currentBag, this->nextBag);
|
||||
if (this->distributionMode == DEFAULT) {
|
||||
this->getNextPieceFromBag(0);
|
||||
}
|
||||
else {
|
||||
if (this->sizesBag.empty()) {
|
||||
for (int i = 0; i <= this->highestSize; i++) {
|
||||
if (this->propotionsPerSize.at(i) >= SMALLEST_CONSIDERED_PROPORTION
|
||||
&& !(this->currentBags.at(i).empty() && this->nextBags.at(i).empty())) {
|
||||
while (this->sizesProgression.at(i) < 1) {
|
||||
this->sizesBag.push_back(i);
|
||||
this->sizesProgression.at(i) += this->propotionsPerSize.at(i);
|
||||
}
|
||||
|
||||
this->sizesProgression.at(i) -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int nextSizeIndex = std::rand() % this->sizesBag.size();
|
||||
int nextSize = this->sizesBag.at(nextSizeIndex);
|
||||
this->sizesBag.erase(this->sizesBag.begin() + nextSizeIndex);
|
||||
|
||||
this->getNextPieceFromBag(nextSize);
|
||||
}
|
||||
}
|
||||
|
||||
void Bag::getNextPieceFromBag(int bagIndex) {
|
||||
if (this->currentBags.at(bagIndex).empty()) {
|
||||
std::swap(this->currentBags.at(bagIndex), this->nextBags.at(bagIndex));
|
||||
}
|
||||
|
||||
int indexIndex = std::rand() % this->currentBag.size();
|
||||
this->next = this->currentBag.at(indexIndex);
|
||||
int indexIndex = std::rand() % this->currentBags.at(bagIndex).size();
|
||||
this->next = this->currentBags.at(bagIndex).at(indexIndex);
|
||||
|
||||
this->nextBag.push_back(this->next);
|
||||
this->currentBag.erase(this->currentBag.begin() + indexIndex);
|
||||
this->nextBags.at(bagIndex).push_back(this->next);
|
||||
this->currentBags.at(bagIndex).erase(this->currentBags.at(bagIndex).begin() + indexIndex);
|
||||
}
|
||||
|
||||
@@ -2,11 +2,14 @@
|
||||
|
||||
#include "../Pieces/Piece.h"
|
||||
#include "PiecesList.h"
|
||||
#include "DistributionMode.h"
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
using PieceBag = std::vector<std::pair<int, int>>;
|
||||
|
||||
|
||||
/**
|
||||
* A litteral bag of pieces, in which you take each of its piece randomly one by one then start again with a new bag
|
||||
@@ -14,10 +17,15 @@
|
||||
class Bag {
|
||||
private:
|
||||
std::shared_ptr<PiecesList> piecesList; // the list of loaded pieces
|
||||
int highestSize; // the highest size of piece in the bag
|
||||
std::vector<std::pair<int, int>> selectedPieces; // the list of pieces that can be given to the player
|
||||
DistributionMode distributionMode; // the distribution mode
|
||||
std::vector<double> propotionsPerSize; // the proportion of pieces for each size
|
||||
std::pair<int, int> next; // the next piece to give
|
||||
std::vector<std::pair<int, int>> currentBag; // the list of pieces that are still to be taken out before starting a new bag
|
||||
std::vector<std::pair<int, int>> nextBag; // the list of pieces that have been taken out of the current bag and have been placed in the next
|
||||
std::vector<PieceBag> currentBags; // for each size, the list of pieces that are still to be taken out before starting a new bag
|
||||
std::vector<PieceBag> nextBags; // for each size, the list of pieces that have been taken out of the current bag and have been placed in the next
|
||||
std::vector<int> sizesBag; // the list each of bags that are still to have a piece taken out of them
|
||||
std::vector<double> sizesProgression; // how close each size is to meet its quota of pieces
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -26,7 +34,7 @@ class Bag {
|
||||
Bag(const std::shared_ptr<PiecesList>& piecesList);
|
||||
|
||||
/**
|
||||
* Ignores the remaining pieces in the current bag and startd fresh from a new bag
|
||||
* Ignores the remaining pieces in the current bag and start fresh from a new bag
|
||||
*/
|
||||
void jumpToNextBag();
|
||||
|
||||
@@ -44,7 +52,12 @@ class Bag {
|
||||
|
||||
private:
|
||||
/**
|
||||
* Prepare the next picked piece in advance
|
||||
* Prepares the next picked piece in advance
|
||||
*/
|
||||
void prepareNext();
|
||||
|
||||
/**
|
||||
* Gets the next picked piece from the specified bag
|
||||
*/
|
||||
void getNextPieceFromBag(int bagIndex);
|
||||
};
|
||||
|
||||
27
src/Core/DistributionMode.h
Normal file
27
src/Core/DistributionMode.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
/**
|
||||
* The modes of pieces distribution managed by the app
|
||||
*/
|
||||
enum DistributionMode {
|
||||
DEFAULT,
|
||||
UNIFORM,
|
||||
CUSTOM
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return A string containing the name of the given distribution mode
|
||||
*/
|
||||
inline std::string getPiecesDistributionName(DistributionMode distributionMode) {
|
||||
static const std::string DISTRIBUTION_NAMES[] = {
|
||||
"DEFAULT",
|
||||
"UNIFORM",
|
||||
"CUSTOM"
|
||||
};
|
||||
|
||||
return DISTRIBUTION_NAMES[distributionMode];
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "../Pieces/Piece.h"
|
||||
#include "../Pieces/PiecesFiles.h"
|
||||
#include "DistributionMode.h"
|
||||
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
@@ -11,6 +12,10 @@ PiecesList::PiecesList() {
|
||||
this->highestLoadedSize = 0;
|
||||
this->selectedPieces.clear();
|
||||
|
||||
this->distributionMode = DEFAULT;
|
||||
this->proportionsPerSize.clear();
|
||||
this->customProportionsPerSize.clear();
|
||||
|
||||
// we need to have something at index 0 even if there is no pieces of size 0
|
||||
this->loadedPieces.clear();
|
||||
this->convexPieces.clear();
|
||||
@@ -87,6 +92,14 @@ void PiecesList::unselectAll() {
|
||||
this->selectedPieces.clear();
|
||||
}
|
||||
|
||||
bool PiecesList::setDistributionMode(DistributionMode distributionMode) {
|
||||
if (distributionMode == DEFAULT || distributionMode == UNIFORM || distributionMode == CUSTOM) {
|
||||
this->distributionMode = distributionMode;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int PiecesList::getHighestLoadedSize() const {
|
||||
return this->highestLoadedSize;
|
||||
}
|
||||
@@ -101,13 +114,42 @@ std::vector<std::pair<int, int>> PiecesList::getSelectedPieces() const {
|
||||
return this->selectedPieces;
|
||||
}
|
||||
|
||||
DistributionMode PiecesList::getDistributionMode() const {
|
||||
return this->distributionMode;
|
||||
}
|
||||
|
||||
bool PiecesList::changeCustomDistribution(int size, double distribution) {
|
||||
if (size < 1 || size > this->highestLoadedSize || distribution > 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this->customProportionsPerSize.at(size) = distribution;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<double> PiecesList::getProportionsPerSize() const {
|
||||
if (this->distributionMode == CUSTOM) {
|
||||
return this->customProportionsPerSize;
|
||||
}
|
||||
else {
|
||||
return this->proportionsPerSize;
|
||||
}
|
||||
}
|
||||
|
||||
Piece PiecesList::getPiece(const std::pair<int, int>& pieceIndex) const {
|
||||
return this->loadedPieces.at(pieceIndex.first).at(pieceIndex.second);
|
||||
}
|
||||
|
||||
const Piece& PiecesList::lookAtPiece(const std::pair<int, int>& pieceIndex) const {
|
||||
return this->loadedPieces.at(pieceIndex.first).at(pieceIndex.second);
|
||||
}
|
||||
|
||||
void PiecesList::pushBackEmptyVectors() {
|
||||
this->loadedPieces.push_back(std::vector<Piece>());
|
||||
this->convexPieces.push_back(std::vector<int>());
|
||||
this->holelessPieces.push_back(std::vector<int>());
|
||||
this->otherPieces.push_back(std::vector<int>());
|
||||
|
||||
this->proportionsPerSize.push_back(1);
|
||||
this->customProportionsPerSize.push_back(1);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Pieces/Piece.h"
|
||||
#include "DistributionMode.h"
|
||||
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
@@ -18,6 +19,9 @@ class PiecesList {
|
||||
std::vector<std::vector<int>> holelessPieces; // the list of holeless loaded pieces by size
|
||||
std::vector<std::vector<int>> otherPieces; // the list of other loaded pieces by size
|
||||
std::vector<std::pair<int, int>> selectedPieces; // the list of all currently selected pieces
|
||||
DistributionMode distributionMode; // the current pieces distribution mode
|
||||
std::vector<double> proportionsPerSize; // the proportion of piece for each sizes
|
||||
std::vector<double> customProportionsPerSize; // the proportion of piece for each sizes when the distribution mode is set to custom
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -66,6 +70,19 @@ class PiecesList {
|
||||
*/
|
||||
void unselectAll();
|
||||
|
||||
/**
|
||||
* Changes the current pieces distribution mode
|
||||
* @return If the mode is supported
|
||||
*/
|
||||
bool setDistributionMode(DistributionMode distributionMode);
|
||||
|
||||
/**
|
||||
* Changes the distribution of the specified size for when the distribution mode is set to custom,
|
||||
* the specified distribution must lower or equal to 1
|
||||
* @return If the new distribution was applied
|
||||
*/
|
||||
bool changeCustomDistribution(int size, double distribution);
|
||||
|
||||
/**
|
||||
* @return The highest loaded size of pieces
|
||||
*/
|
||||
@@ -81,10 +98,25 @@ class PiecesList {
|
||||
*/
|
||||
std::vector<std::pair<int, int>> getSelectedPieces() const;
|
||||
|
||||
/**
|
||||
* @return The current distribution mode
|
||||
*/
|
||||
DistributionMode getDistributionMode() const;
|
||||
|
||||
/**
|
||||
* @return The proportion of pieces for each loaded size
|
||||
*/
|
||||
std::vector<double> getProportionsPerSize() const;
|
||||
|
||||
/**
|
||||
* @return A copy of the piece corresponding to the specified index
|
||||
*/
|
||||
Piece getPiece(const std::pair<int, int>& pieceIndex) const;
|
||||
|
||||
/**
|
||||
* @return The piece corresponding to the specified index
|
||||
*/
|
||||
const Piece& lookAtPiece(const std::pair<int, int>& pieceIndex) const;
|
||||
|
||||
private:
|
||||
/**
|
||||
|
||||
@@ -80,4 +80,11 @@ class AppMenu {
|
||||
text.setPosition(sf::Vector2f({sizeMultiplier * 40.f, sizeMultiplier * yPos}));
|
||||
this->renderWindow->draw(text);
|
||||
}
|
||||
|
||||
sf::Color getColorOfBlock(Block block, int luminosityShift) const {
|
||||
Color rgbColor = BLOCKS_COLOR[block];
|
||||
return sf::Color(std::clamp(rgbColor.red + luminosityShift, 0, 255),
|
||||
std::clamp(rgbColor.green + luminosityShift, 0, 255),
|
||||
std::clamp(rgbColor.blue + luminosityShift, 0, 255));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
|
||||
@@ -58,8 +57,6 @@ void GameBoardAppMenu::drawFrame() const {
|
||||
|
||||
this->placeTitle(text, {}, "BOARD SETTINGS", 5.f, {});
|
||||
|
||||
sf::Vector2u windowSize = this->renderWindow->getSize();
|
||||
|
||||
this->placeText(text, this->playerCursor, "< BOARD WIDTH: " + std::to_string(menu.getBoardWidth()) + " >", 5.f, 15.f, sf::Vector2u{0, 0});
|
||||
this->placeText(text, this->playerCursor, "< BOARD HEIGHT: " + std::to_string(menu.getBoardHeight()) + " >", 5.f, 25.f, sf::Vector2u{0, 1});
|
||||
|
||||
|
||||
85
src/GraphicalUI/AppMenus/GameDistributionAppMenu.cpp
Normal file
85
src/GraphicalUI/AppMenus/GameDistributionAppMenu.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
#include "GameDistributionAppMenu.h"
|
||||
|
||||
#include "AppMenu.h"
|
||||
#include "../PlayerCursor.h"
|
||||
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
|
||||
GameDistributionAppMenu::GameDistributionAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow) :
|
||||
AppMenu(menuStack, settings, renderWindow),
|
||||
playerCursor({1}) {
|
||||
|
||||
for (int i = 1; i <= this->settings->getMaximumPiecesSize(); i++) {
|
||||
this->playerCursor.addRow(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void GameDistributionAppMenu::computeFrame() {
|
||||
this->updateMetaBinds();
|
||||
this->playerCursor.updatePosition();
|
||||
|
||||
PiecesList& piecesList = this->settings->getMenu().getPiecesList();
|
||||
|
||||
if (this->playerCursor.getPosition().y == 0) {
|
||||
if (this->playerCursor.movedLeft()) {
|
||||
piecesList.setDistributionMode(DistributionMode((int) piecesList.getDistributionMode() - 1));
|
||||
}
|
||||
if (this->playerCursor.movedRight()) {
|
||||
piecesList.setDistributionMode(DistributionMode((int) piecesList.getDistributionMode() + 1));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (piecesList.getDistributionMode() != CUSTOM) {
|
||||
this->playerCursor.goToPosition({0, 0});
|
||||
}
|
||||
else {
|
||||
if (this->playerCursor.movedLeft()) {
|
||||
this->settings->decreaseDistribution(this->playerCursor.getPosition().y);
|
||||
}
|
||||
if (this->playerCursor.movedRight()) {
|
||||
this->settings->increaseDistribution(this->playerCursor.getPosition().y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this->escReleased) {
|
||||
this->settings->confirmDistribution();
|
||||
this->menuStack->pop();
|
||||
}
|
||||
}
|
||||
|
||||
void GameDistributionAppMenu::drawFrame() const {
|
||||
this->renderWindow->clear(sf::Color(200, 200, 200));
|
||||
|
||||
const Menu& menu = this->settings->getMenu();
|
||||
|
||||
sf::Text text(this->pressStartFont, "", this->settings->getWindowSizeMultiplier() * 2);
|
||||
text.setFillColor(sf::Color(0, 0, 0));
|
||||
text.setOutlineColor(sf::Color(255, 255, 255));
|
||||
|
||||
this->placeTitle(text, {}, "DISTRIBUTION SETTINGS", 5.f, {});
|
||||
|
||||
const DistributionMode distributionMode = this->settings->getMenu().readPiecesList().getDistributionMode();
|
||||
const std::vector<int>& distributions = this->settings->getDistributions();
|
||||
|
||||
int firstElem = std::clamp(((int) this->playerCursor.getPosition().y) - 1, 0, this->settings->getMaximumPiecesSize() - 3);
|
||||
if (firstElem == 0) {
|
||||
this->placeText(text, this->playerCursor, "< DISTRIBUTION MODE: " + getPiecesDistributionName(distributionMode) + " >", 5.f, 15.f, sf::Vector2u{0, 0});
|
||||
}
|
||||
else {
|
||||
this->placeText(text, this->playerCursor, "< SIZE " + std::to_string(firstElem) + " PROBABILITY: " + std::to_string(distributions.at(firstElem)) + " >", 5.f, 15.f, sf::Vector2u{(unsigned int) firstElem, 0});
|
||||
}
|
||||
|
||||
if (distributionMode != CUSTOM) {
|
||||
text.setFillColor(sf::Color(100, 100, 100));
|
||||
}
|
||||
|
||||
this->placeText(text, this->playerCursor, "< SIZE " + std::to_string(firstElem + 1) + " PROBABILITY: " + std::to_string(distributions.at(firstElem + 1)) + " >", 5.f, 25.f, sf::Vector2u{0, (unsigned int) firstElem + 1});
|
||||
this->placeText(text, this->playerCursor, "< SIZE " + std::to_string(firstElem + 2) + " PROBABILITY: " + std::to_string(distributions.at(firstElem + 2)) + " >", 5.f, 35.f, sf::Vector2u{0, (unsigned int) firstElem + 2});
|
||||
this->placeText(text, this->playerCursor, "< SIZE " + std::to_string(firstElem + 3) + " PROBABILITY: " + std::to_string(distributions.at(firstElem + 3)) + " >", 5.f, 45.f, sf::Vector2u{0, (unsigned int) firstElem + 3});
|
||||
|
||||
this->renderWindow->display();
|
||||
}
|
||||
21
src/GraphicalUI/AppMenus/GameDistributionAppMenu.h
Normal file
21
src/GraphicalUI/AppMenus/GameDistributionAppMenu.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "AppMenu.h"
|
||||
#include "../PlayerCursor.h"
|
||||
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
|
||||
class GameDistributionAppMenu : public AppMenu {
|
||||
private:
|
||||
PlayerCursor playerCursor;
|
||||
|
||||
public:
|
||||
GameDistributionAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow);
|
||||
|
||||
void computeFrame() override;
|
||||
|
||||
void drawFrame() const override;
|
||||
};
|
||||
178
src/GraphicalUI/AppMenus/GamePiecesAppMenu.cpp
Normal file
178
src/GraphicalUI/AppMenus/GamePiecesAppMenu.cpp
Normal file
@@ -0,0 +1,178 @@
|
||||
#include "GamePiecesAppMenu.h"
|
||||
|
||||
#include "AppMenu.h"
|
||||
#include "GameDistributionAppMenu.h"
|
||||
#include "../PlayerCursor.h"
|
||||
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
|
||||
GamePiecesAppMenu::GamePiecesAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow) :
|
||||
AppMenu(menuStack, settings, renderWindow),
|
||||
playerCursor({1, (unsigned int) this->settings->getSelectedPieces().size() + 1u}) {
|
||||
|
||||
for (int i = 1; i <= this->settings->getMaximumPiecesSize(); i++) {
|
||||
this->playerCursor.addRow(i + 1, this->settings->getMenu().readPiecesList().getNumberOfPieces(i) + 4);
|
||||
}
|
||||
}
|
||||
|
||||
void GamePiecesAppMenu::computeFrame() {
|
||||
this->updateMetaBinds();
|
||||
this->playerCursor.updatePosition();
|
||||
|
||||
if (this->playerCursor.movedDown() && this->playerCursor.getPosition().y == 2) {
|
||||
this->playerCursor.goToPosition({0, 2});
|
||||
}
|
||||
|
||||
if (this->enterReleased) {
|
||||
if (this->playerCursor.getPosition().y == 0) {
|
||||
this->menuStack->push(std::make_shared<GameDistributionAppMenu>(this->menuStack, this->settings, this->renderWindow));
|
||||
}
|
||||
if (this->playerCursor.getPosition().y > 1) {
|
||||
if (this->playerCursor.getPosition().x >= 4) {
|
||||
this->settings->selectPieces(createSinglePieceType(this->playerCursor.getPosition().y - 1), this->playerCursor.getPosition().x - 4);
|
||||
}
|
||||
else {
|
||||
switch (this->playerCursor.getPosition().x) {
|
||||
case 0 : {this->settings->selectPieces(ALL_PIECES, this->playerCursor.getPosition().y - 1); break;}
|
||||
case 1 : {this->settings->selectPieces(CONVEX_PIECES, this->playerCursor.getPosition().y - 1); break;}
|
||||
case 2 : {this->settings->selectPieces(HOLELESS_PIECES, this->playerCursor.getPosition().y - 1); break;}
|
||||
case 3 : {this->settings->selectPieces(OTHER_PIECES, this->playerCursor.getPosition().y - 1); break;}
|
||||
}
|
||||
}
|
||||
this->playerCursor.addPosition(0, 1);
|
||||
}
|
||||
}
|
||||
if (this->escReleased) {
|
||||
if (this->playerCursor.getPosition().y == 1) {
|
||||
if (this->playerCursor.getPosition().x > 0) {
|
||||
this->settings->unselectPieces(this->playerCursor.getPosition().x - 1);
|
||||
this->playerCursor.removePosition(this->playerCursor.getPosition().x - 1, 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this->settings->confirmSelectedPieces();
|
||||
this->menuStack->pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GamePiecesAppMenu::drawFrame() const {
|
||||
this->renderWindow->clear(sf::Color(200, 200, 200));
|
||||
|
||||
sf::Text text(this->pressStartFont, "", this->settings->getWindowSizeMultiplier() * 2);
|
||||
text.setFillColor(sf::Color(0, 0, 0));
|
||||
text.setOutlineColor(sf::Color(255, 255, 255));
|
||||
|
||||
this->placeTitle(text, {}, "PIECES SELECT", 5.f, {});
|
||||
|
||||
if (this->playerCursor.getPosition().y == 0) {
|
||||
this->placeText(text, this->playerCursor, "PIECES DISTRIBUTION", 5.f, 15.f, sf::Vector2u{0, 0});
|
||||
this->drawSelectedPiecesRow(25.f);
|
||||
this->drawRow(1, 35.f, true);
|
||||
this->drawRow(2, 45.f, true);
|
||||
}
|
||||
else {
|
||||
this->drawSelectedPiecesRow(15.f);
|
||||
|
||||
bool drawFromFirstElem = (this->playerCursor.getPosition().y == 1);
|
||||
int firstElem = std::clamp(((int) this->playerCursor.getPosition().y) - 2, 1, this->settings->getMaximumPiecesSize() - 2);
|
||||
this->drawRow(firstElem, 25.f, drawFromFirstElem);
|
||||
this->drawRow(firstElem + 1, 35.f, drawFromFirstElem);
|
||||
this->drawRow(firstElem + 2, 45.f, drawFromFirstElem);
|
||||
}
|
||||
|
||||
this->renderWindow->display();
|
||||
}
|
||||
|
||||
void GamePiecesAppMenu::drawSelectedPiecesRow(float yPos) const {
|
||||
sf::RectangleShape rect({(float) this->renderWindow->getSize().x, 8.f * this->settings->getWindowSizeMultiplier()});
|
||||
rect.setPosition({0.f, (yPos - 4.f) * this->settings->getWindowSizeMultiplier()});
|
||||
rect.setFillColor({240, 240, 240});
|
||||
this->renderWindow->draw(rect);
|
||||
|
||||
sf::Text text(this->pressStartFont, "", this->settings->getWindowSizeMultiplier());
|
||||
text.setFillColor({0, 0, 0});
|
||||
|
||||
int elem = (this->playerCursor.getPosition().y == 1) ? std::max(((int) this->playerCursor.getPosition().x) - 4, 0) : 0;
|
||||
float xProgress = 1.f;
|
||||
|
||||
bool first = true;
|
||||
while (true) {
|
||||
if ((this->playerCursor.getPosition().y == 1) && (elem == this->playerCursor.getPosition().x)) {
|
||||
this->placeText(text, {}, "|", xProgress, yPos, {});
|
||||
xProgress += (1.f + (text.getGlobalBounds().size.x / this->settings->getWindowSizeMultiplier()));
|
||||
}
|
||||
|
||||
if (elem >= this->settings->getSelectedPieces().size()) return;
|
||||
|
||||
const auto& [pieceType, value] = this->settings->getSelectedPieces().at(elem);
|
||||
|
||||
int pieceSize = getSizeOfPieces(pieceType);
|
||||
if (pieceSize > 0) {
|
||||
const Piece& piece = this->settings->getMenu().readPiecesList().lookAtPiece({pieceSize, value});
|
||||
int cellSize = (8 * this->settings->getWindowSizeMultiplier()) / (piece.getLength());
|
||||
sf::FloatRect piecePosition(sf::Vector2f(xProgress, yPos - 4.f) * (float) this->settings->getWindowSizeMultiplier(), sf::Vector2f(8 , 8) * (float) this->settings->getWindowSizeMultiplier());
|
||||
this->drawPiece(piece, cellSize, piecePosition, false);
|
||||
xProgress += (1.f + 8.f);
|
||||
}
|
||||
else {
|
||||
this->placeText(text, {}, ((first) ? "" : " ") + getPiecesTypeName(pieceType) + "_" + std::to_string(value), xProgress, yPos, {});
|
||||
xProgress += (1.f + (text.getGlobalBounds().size.x / this->settings->getWindowSizeMultiplier()));
|
||||
}
|
||||
|
||||
elem++;
|
||||
}
|
||||
}
|
||||
|
||||
void GamePiecesAppMenu::drawRow(int piecesSize, float yPos, bool drawFromFirstElem) const {
|
||||
int numberOfPieces = this->settings->getMenu().readPiecesList().getNumberOfPieces(piecesSize);
|
||||
int firstElem = (drawFromFirstElem) ? -4 : std::max(((int) this->playerCursor.getPosition().x) - 7, -4);
|
||||
|
||||
sf::Text text(this->pressStartFont, "", this->settings->getWindowSizeMultiplier());
|
||||
text.setFillColor({0, 0, 0});
|
||||
text.setOutlineColor({255, 255, 255});
|
||||
|
||||
this->placeText(text, {}, "SIZE " + std::to_string(piecesSize), 1.f, yPos, {});
|
||||
|
||||
for (int i = 0; i < 7; i++) {
|
||||
if (i + firstElem >= numberOfPieces) return;
|
||||
|
||||
if ((i + firstElem) < 0) {
|
||||
switch (i + firstElem) {
|
||||
case -4 : {this->placeText(text, this->playerCursor, "ALL", 10.f + (i * 10.f), yPos, sf::Vector2u{0, piecesSize + 1u}); break;}
|
||||
case -3 : {this->placeText(text, this->playerCursor, "CONVEX", 10.f + (i * 10.f), yPos, sf::Vector2u{1, piecesSize + 1u}); break;}
|
||||
case -2 : {this->placeText(text, this->playerCursor, "HOLELESS", 10.f + (i * 10.f), yPos, sf::Vector2u{2, piecesSize + 1u}); break;}
|
||||
case -1 : {this->placeText(text, this->playerCursor, "OTHER", 10.f + (i * 10.f), yPos, sf::Vector2u{3, piecesSize + 1u}); break;}
|
||||
}
|
||||
}
|
||||
else {
|
||||
const Piece& piece = this->settings->getMenu().readPiecesList().lookAtPiece({piecesSize, firstElem + i});
|
||||
int cellSize = (8 * this->settings->getWindowSizeMultiplier()) / (piece.getLength());
|
||||
sf::FloatRect piecePosition(sf::Vector2f(10.f + (i * 10.f), yPos - 4.f) * (float) this->settings->getWindowSizeMultiplier(), sf::Vector2f(8 , 8) * (float) this->settings->getWindowSizeMultiplier());
|
||||
this->drawPiece(piece, cellSize, piecePosition, this->playerCursor.getPosition() == sf::Vector2u{i + firstElem + 4u, piecesSize + 1u});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GamePiecesAppMenu::drawPiece(const Piece& piece, int cellSize, const sf::FloatRect& piecePosition, bool selected) const {
|
||||
sf::RectangleShape rect(piecePosition.size);
|
||||
rect.setPosition(piecePosition.position);
|
||||
rect.setFillColor({180, 180, 180});
|
||||
if (selected) {
|
||||
rect.setOutlineColor({0, 0, 0});
|
||||
rect.setOutlineThickness(this->settings->getWindowSizeMultiplier() / 2);
|
||||
}
|
||||
this->renderWindow->draw(rect);
|
||||
|
||||
sf::RectangleShape cell(sf::Vector2f(cellSize, cellSize));
|
||||
cell.setFillColor(this->getColorOfBlock(piece.getBlockType(), 0));
|
||||
|
||||
for (const Position& cellPosition : piece.getPositions()) {
|
||||
cell.setPosition(sf::Vector2f(piecePosition.position.x + (cellPosition.x * cellSize),
|
||||
piecePosition.position.y + ((piece.getLength() - cellPosition.y - 1) * cellSize) ));
|
||||
this->renderWindow->draw(cell);
|
||||
}
|
||||
}
|
||||
29
src/GraphicalUI/AppMenus/GamePiecesAppMenu.h
Normal file
29
src/GraphicalUI/AppMenus/GamePiecesAppMenu.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "AppMenu.h"
|
||||
#include "../PlayerCursor.h"
|
||||
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
|
||||
class GamePiecesAppMenu : public AppMenu {
|
||||
private:
|
||||
PlayerCursor playerCursor;
|
||||
|
||||
public:
|
||||
GamePiecesAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow);
|
||||
|
||||
void computeFrame() override;
|
||||
|
||||
void drawFrame() const override;
|
||||
|
||||
private:
|
||||
void drawSelectedPiecesRow(float yPos) const;
|
||||
|
||||
void drawRow(int piecesSize, float yPos, bool drawFromFirstElem) const;
|
||||
|
||||
void drawPiece(const Piece& piece, int cellSize, const sf::FloatRect& pos, bool selected) const;
|
||||
};
|
||||
@@ -9,14 +9,15 @@
|
||||
#include <string>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
static const int TIME_BEFORE_STARTING = 60;
|
||||
|
||||
|
||||
GamePlayingAppMenu::GamePlayingAppMenu(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->startTimer = TIME_BEFORE_STARTING;
|
||||
this->startTimer = this->settings->getStartTimerLength() * FRAMES_PER_SECOND;
|
||||
if (this->startTimer == 0) {
|
||||
this->game.start();
|
||||
}
|
||||
this->paused = false;
|
||||
this->pausePressed = false;
|
||||
this->retryPressed = false;
|
||||
@@ -39,7 +40,7 @@ GamePlayingAppMenu::GamePlayingAppMenu(std::shared_ptr<MenuStack> menuStack, std
|
||||
|
||||
this->nextCellSizeZoom = this->nextQueuePosition[0].size.y;
|
||||
for (const auto& piece : this->settings->getMenu().getPiecesList().getSelectedPieces()) {
|
||||
float nextPieceCellSizeZoom = ((int) this->nextQueuePosition[0].size.y) / this->settings->getMenu().getPiecesList().getPiece(piece).getLength();
|
||||
float nextPieceCellSizeZoom = ((int) this->nextQueuePosition[0].size.y) / this->settings->getMenu().getPiecesList().lookAtPiece(piece).getLength();
|
||||
this->nextCellSizeZoom = std::min(this->nextCellSizeZoom, nextPieceCellSizeZoom);
|
||||
}
|
||||
|
||||
@@ -77,7 +78,10 @@ void GamePlayingAppMenu::computeFrame() {
|
||||
else {
|
||||
if (this->retryPressed) {
|
||||
this->game.reset();
|
||||
this->startTimer = TIME_BEFORE_STARTING;
|
||||
this->startTimer = this->settings->getStartTimerLength() * FRAMES_PER_SECOND;
|
||||
if (this->startTimer == 0) {
|
||||
this->game.start();
|
||||
}
|
||||
}
|
||||
this->retryPressed = false;
|
||||
}
|
||||
@@ -116,6 +120,8 @@ void GamePlayingAppMenu::drawFrame() const {
|
||||
}
|
||||
}
|
||||
|
||||
// end coutdown
|
||||
|
||||
if (drawActivePiece) {
|
||||
// ghost piece
|
||||
sf::Color ghostColor = this->getColorOfBlock(this->game.getActivePiece()->getBlockType(), 100);
|
||||
@@ -247,6 +253,7 @@ void GamePlayingAppMenu::drawFrame() const {
|
||||
// game state
|
||||
text.setOutlineColor(sf::Color(255, 255, 255));
|
||||
text.setOutlineThickness(windowSizeMultiplier / 2.f);
|
||||
text.setCharacterSize(windowSizeMultiplier * 4);
|
||||
|
||||
if (this->game.hasWon()) {
|
||||
this->placeTitle(text, {}, "WIN", 25.f, {});
|
||||
@@ -258,20 +265,12 @@ void GamePlayingAppMenu::drawFrame() const {
|
||||
this->placeTitle(text, {}, "PAUSE", 25.f, {});
|
||||
}
|
||||
else if (this->startTimer > 0) {
|
||||
text.setCharacterSize(windowSizeMultiplier * 4);
|
||||
this->placeTitle(text, {}, std::to_string(((this->startTimer - 1) / (TIME_BEFORE_STARTING / 4))), 25.f, {});
|
||||
this->placeTitle(text, {}, std::to_string(((this->startTimer - 1) / ((this->settings->getStartTimerLength() * FRAMES_PER_SECOND) / 4))), 25.f, {});
|
||||
}
|
||||
|
||||
this->renderWindow->display();
|
||||
}
|
||||
|
||||
sf::Color GamePlayingAppMenu::getColorOfBlock(Block block, int luminosityShift) const {
|
||||
Color rgbColor = BLOCKS_COLOR[block];
|
||||
return sf::Color(std::clamp(rgbColor.red + luminosityShift, 0, 255),
|
||||
std::clamp(rgbColor.green + luminosityShift, 0, 255),
|
||||
std::clamp(rgbColor.blue + luminosityShift, 0, 255));
|
||||
}
|
||||
|
||||
sf::Vector2f GamePlayingAppMenu::getBoardBlockPosition(int x, int y) const {
|
||||
return sf::Vector2f(this->boardPosition.position.x + (x * this->cellSizeZoom),
|
||||
this->boardPosition.position.y + ((this->game.getBoard().getBaseHeight() + 9 - y) * this->cellSizeZoom));
|
||||
|
||||
@@ -28,7 +28,5 @@ class GamePlayingAppMenu : public AppMenu {
|
||||
|
||||
void drawFrame() const override;
|
||||
|
||||
sf::Color getColorOfBlock(Block block, int luminosityShift) const;
|
||||
|
||||
sf::Vector2f getBoardBlockPosition(int x, int y) const;
|
||||
};
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
#include "GameSettingsAppMenu.h"
|
||||
|
||||
#include "AppMenu.h"
|
||||
#include "GamePiecesAppMenu.h"
|
||||
#include "GameBoardAppMenu.h"
|
||||
#include "GamePlayingAppMenu.h"
|
||||
#include "../PlayerCursor.h"
|
||||
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
|
||||
GameSettingsAppMenu::GameSettingsAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow) :
|
||||
AppMenu(menuStack, settings, renderWindow),
|
||||
playerCursor({2, 3, 3}) {
|
||||
playerCursor({2, 3, 2}) {
|
||||
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ void GameSettingsAppMenu::computeFrame() {
|
||||
switch (this->playerCursor.getPosition().x) {
|
||||
case 0 : {this->settings->setGamemode(MASTER); break;}
|
||||
case 1 : {this->settings->setGamemode(ZEN); break;}
|
||||
case 2 : break; //TODO
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -43,7 +42,7 @@ void GameSettingsAppMenu::computeFrame() {
|
||||
if (this->enterReleased) {
|
||||
if (this->playerCursor.getPosition().y == 0) {
|
||||
if (this->playerCursor.getPosition().x == 0) {
|
||||
//TODO
|
||||
this->menuStack->push(std::make_shared<GamePiecesAppMenu>(this->menuStack, this->settings, this->renderWindow));
|
||||
}
|
||||
if (this->playerCursor.getPosition().x == 1) {
|
||||
this->menuStack->push(std::make_shared<GameBoardAppMenu>(this->menuStack, this->settings, this->renderWindow));
|
||||
@@ -67,15 +66,17 @@ void GameSettingsAppMenu::drawFrame() const {
|
||||
|
||||
this->placeTitle(text, {}, "GAME SETTINGS", 5.f, {});
|
||||
|
||||
this->placeText(text, this->playerCursor, "PIECES SELECT (TODO)", 5.f, 15.f, sf::Vector2u{0, 0});
|
||||
this->placeText(text, this->playerCursor, "PIECES SELECT", 5.f, 15.f, sf::Vector2u{0, 0});
|
||||
this->placeText(text, this->playerCursor, "BOARD SELECT", 40.f, 15.f, sf::Vector2u{1, 0});
|
||||
|
||||
this->placeText(text, this->playerCursor, "SPRINT", 5.f, 25.f, sf::Vector2u{0, 1});
|
||||
this->placeText(text, this->playerCursor, "MARATHON", 25.f, 25.f, sf::Vector2u{1, 1});
|
||||
this->placeText(text, this->playerCursor, "ULTRA", 50.f, 25.f, sf::Vector2u{2, 1});
|
||||
this->placeText(text, this->playerCursor, "MASTER", 5.f, 35.f, sf::Vector2u{0, 2});
|
||||
this->placeText(text, this->playerCursor, "ZEN", 25.f, 35.f, sf::Vector2u{1, 2});
|
||||
this->placeText(text, this->playerCursor, "??? (TODO)", 50.f, 35.f, sf::Vector2u{2, 2});
|
||||
text.setOutlineThickness(0);
|
||||
this->placeTitle(text, {}, "GAMEMODE SELECT", 25.f, {});
|
||||
|
||||
this->placeText(text, this->playerCursor, "SPRINT", 5.f, 35.f, sf::Vector2u{0, 1});
|
||||
this->placeText(text, this->playerCursor, "MARATHON", 25.f, 35.f, sf::Vector2u{1, 1});
|
||||
this->placeText(text, this->playerCursor, "ULTRA", 50.f, 35.f, sf::Vector2u{2, 1});
|
||||
this->placeText(text, this->playerCursor, "MASTER", 5.f, 45.f, sf::Vector2u{0, 2});
|
||||
this->placeText(text, this->playerCursor, "ZEN", 25.f, 45.f, sf::Vector2u{1, 2});
|
||||
|
||||
this->renderWindow->display();
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <regex>
|
||||
#include <filesystem>
|
||||
@@ -15,7 +14,7 @@
|
||||
|
||||
SettingsKeybindsAppMenu::SettingsKeybindsAppMenu(std::shared_ptr<MenuStack> menuStack, std::shared_ptr<Settings> settings, std::shared_ptr<sf::RenderWindow> renderWindow) :
|
||||
AppMenu(menuStack, settings, renderWindow),
|
||||
playerCursor({12, 1}) {
|
||||
playerCursor({1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}) {
|
||||
|
||||
this->selectedAnAction = false;
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
|
||||
@@ -37,10 +36,10 @@ void SettingsMainAppMenu::computeFrame() {
|
||||
}
|
||||
case 3 : {
|
||||
if (this->playerCursor.movedLeft()) {
|
||||
this->settings->lowerMasterVolume();
|
||||
this->settings->shortenStartTimer();
|
||||
}
|
||||
if (this->playerCursor.movedRight()) {
|
||||
this->settings->raiseMasterVolume();
|
||||
this->settings->lengthenStartTimer();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -73,7 +72,7 @@ void SettingsMainAppMenu::drawFrame() const {
|
||||
this->placeText(text, this->playerCursor, "CHANGE KEYBINDS", 5.f, 15.f, sf::Vector2u{0, 0});
|
||||
this->placeText(text, this->playerCursor, "CHANGE CONTROLS", 5.f, 25.f, sf::Vector2u{0, 1});
|
||||
this->placeText(text, this->playerCursor, "< WINDOW SIZE: " + std::to_string(windowSize.x) + "x" + std::to_string(windowSize.y) + " >", 5.f, 35.f, sf::Vector2u{0, 2});
|
||||
this->placeText(text, this->playerCursor, "< VOLUME: " + std::to_string(this->settings->getMasterVolume()) + "% >", 5.f, 45.f, sf::Vector2u{0, 3});
|
||||
this->placeText(text, this->playerCursor, "< START TIMER: " + std::to_string(this->settings->getStartTimerLength()) + "s >", 5.f, 45.f, sf::Vector2u{0, 3});
|
||||
|
||||
this->renderWindow->display();
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
static const double TIME_BETWEEN_FRAMES = (1000.f / FRAMES_PER_SECOND);
|
||||
|
||||
|
||||
GraphApp::GraphApp() {
|
||||
this->settings = std::make_shared<Settings>();
|
||||
GraphApp::GraphApp(int maximumPiecesSize) {
|
||||
this->settings = std::make_shared<Settings>(maximumPiecesSize);
|
||||
this->menuStack = std::make_shared<MenuStack>();
|
||||
this->renderWindow = std::make_shared<sf::RenderWindow>();
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ class GraphApp {
|
||||
std::shared_ptr<sf::RenderWindow> renderWindow;
|
||||
|
||||
public:
|
||||
GraphApp();
|
||||
GraphApp(int maximumPiecesSize);
|
||||
|
||||
void run();
|
||||
};
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <optional>
|
||||
#include <algorithm>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
using sfKey = sf::Keyboard::Key;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
enum PiecesType {
|
||||
CONVEX_PIECES,
|
||||
@@ -19,3 +21,15 @@ inline int getSizeOfPieces(PiecesType type) {
|
||||
inline PiecesType createSinglePieceType(int size) {
|
||||
return PiecesType(SINGLE_PIECE + size - 1);
|
||||
}
|
||||
|
||||
inline std::string getPiecesTypeName(PiecesType piecesType) {
|
||||
static const std::string PIECES_TYPE_NAME[] = {
|
||||
"CONVEX",
|
||||
"HOLELESS",
|
||||
"OTHER",
|
||||
"ALL",
|
||||
"SINGLE"
|
||||
};
|
||||
|
||||
return PIECES_TYPE_NAME[piecesType];
|
||||
}
|
||||
|
||||
@@ -66,6 +66,48 @@ void PlayerCursor::goToPosition(const sf::Vector2u& newPosition) {
|
||||
}
|
||||
}
|
||||
|
||||
bool PlayerCursor::addPosition(unsigned int x, unsigned int y) {
|
||||
if (y >= this->rows.size()) return false;
|
||||
if (x > this->rows.at(y)) return false;
|
||||
|
||||
this->rows.at(y)++;
|
||||
if ((y == this->position.y) && (x <= this->position.x)) {
|
||||
this->position.x++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PlayerCursor::removePosition(unsigned int x, unsigned int y) {
|
||||
if (y >= this->rows.size()) return false;
|
||||
if (x >= this->rows.at(y)) return false;
|
||||
|
||||
this->rows.at(y)--;
|
||||
if ((y == this->position.y) && (x < this->position.x)) {
|
||||
this->position.x--;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PlayerCursor::addRow(unsigned int position, unsigned int width) {
|
||||
if (position > this->rows.size()) return false;
|
||||
|
||||
this->rows.insert(this->rows.begin() + position, width);
|
||||
if (position <= this->position.y) {
|
||||
this->position.y++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PlayerCursor::removeRow(unsigned int position) {
|
||||
if (position >= this->rows.size()) return false;
|
||||
|
||||
this->rows.erase(this->rows.begin() + position);
|
||||
if (position < this->position.y) {
|
||||
this->position.y--;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const sf::Vector2u& PlayerCursor::getPosition() const {
|
||||
return this->position;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,14 @@ class PlayerCursor {
|
||||
|
||||
void goToPosition(const sf::Vector2u& newPosition);
|
||||
|
||||
bool addPosition(unsigned int x, unsigned int y);
|
||||
|
||||
bool removePosition(unsigned int x, unsigned int y);
|
||||
|
||||
bool addRow(unsigned int position, unsigned int width);
|
||||
|
||||
bool removeRow(unsigned int position);
|
||||
|
||||
const sf::Vector2u& getPosition() const;
|
||||
|
||||
private:
|
||||
|
||||
@@ -10,10 +10,13 @@
|
||||
static const sf::Vector2u BASE_WINDOW_SIZE = {80, 50};
|
||||
static const int WINDOW_SIZE_MULTIPLIERS[] = {4, 6, 10, 14, 20, 30, 40};
|
||||
static const int WINDOW_SIZE_LAST_MODE = (sizeof(WINDOW_SIZE_MULTIPLIERS) / sizeof(int)) - 1;
|
||||
static const int START_TIMER_MAX = 4;
|
||||
static const int DISTRIBUTION_MAX = 10;
|
||||
|
||||
|
||||
Settings::Settings() {
|
||||
for (int i = 1; i <= MAXIMUM_PIECES_SIZE; i++) {
|
||||
Settings::Settings(int maximumPiecesSize) {
|
||||
this->maximumPiecesSize = maximumPiecesSize;
|
||||
for (int i = 1; i <= this->maximumPiecesSize; i++) {
|
||||
this->menu.getPiecesList().loadPieces(i);
|
||||
}
|
||||
|
||||
@@ -49,9 +52,9 @@ void Settings::loadSettingsFromFile() {
|
||||
settingsFile.get(byte);
|
||||
this->windowSizeMode = byte;
|
||||
|
||||
// master volume
|
||||
// start timer length
|
||||
settingsFile.get(byte);
|
||||
this->masterVolume = byte;
|
||||
this->startTimerLength = byte;
|
||||
|
||||
// gamemode
|
||||
settingsFile.get(byte);
|
||||
@@ -67,23 +70,43 @@ void Settings::loadSettingsFromFile() {
|
||||
|
||||
// piece distribution
|
||||
settingsFile.get(byte);
|
||||
//TODO
|
||||
if (byte == 2) {
|
||||
for (int i = 1; i <= 15; i++) {
|
||||
settingsFile.get(byte);
|
||||
//TODO
|
||||
}
|
||||
this->menu.getPiecesList().setDistributionMode(DistributionMode(byte));
|
||||
|
||||
this->distributions.clear();
|
||||
this->distributions.push_back(0);
|
||||
for (int i = 1; i <= 15; i++) {
|
||||
settingsFile.get(byte);
|
||||
this->distributions.push_back(byte);
|
||||
}
|
||||
this->confirmDistribution();
|
||||
|
||||
// selected pieces
|
||||
char pieceType;
|
||||
char pieceValue;
|
||||
char pieceSize;
|
||||
char lowByte;
|
||||
char midByte;
|
||||
char highByte;
|
||||
|
||||
this->selectedPieces.clear();
|
||||
while (settingsFile.get(pieceType)) {
|
||||
if (settingsFile.eof()) break;
|
||||
|
||||
settingsFile.get(pieceValue);
|
||||
this->selectedPieces.push_back({PiecesType(pieceType), pieceValue});
|
||||
if (getSizeOfPieces(PiecesType(pieceType)) == 0) {
|
||||
settingsFile.get(pieceSize);
|
||||
|
||||
if (!(pieceSize > this->maximumPiecesSize)) {
|
||||
this->selectedPieces.emplace_back(PiecesType(pieceType), pieceSize);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!(getSizeOfPieces(PiecesType(pieceType)) > this->maximumPiecesSize)) {
|
||||
settingsFile.get(lowByte);
|
||||
settingsFile.get(midByte);
|
||||
settingsFile.get(highByte);
|
||||
int pieceNumber = ((unsigned char) lowByte) + ((unsigned char) midByte << 8) + ((unsigned char) highByte << 16);
|
||||
this->selectedPieces.emplace_back(PiecesType(pieceType), pieceNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
this->confirmSelectedPieces();
|
||||
}
|
||||
@@ -114,8 +137,8 @@ void Settings::saveSettingsToFile() const {
|
||||
byte = this->windowSizeMode;
|
||||
settingsFile.write(&byte, 1);
|
||||
|
||||
// master volume
|
||||
byte = this->masterVolume;
|
||||
// start timer length
|
||||
byte = this->startTimerLength;
|
||||
settingsFile.write(&byte, 1);
|
||||
|
||||
// gamemode
|
||||
@@ -131,15 +154,30 @@ void Settings::saveSettingsToFile() const {
|
||||
settingsFile.write(&byte, 1);
|
||||
|
||||
// piece distribution
|
||||
//TODO
|
||||
byte = this->menu.readPiecesList().getDistributionMode();
|
||||
settingsFile.write(&byte, 1);
|
||||
|
||||
for (int i = 1; i <= 15; i++) {
|
||||
byte = this->distributions.at(i);
|
||||
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);
|
||||
if (getSizeOfPieces(type) == 0) {
|
||||
byte = value;
|
||||
settingsFile.write(&byte, 1);
|
||||
}
|
||||
else {
|
||||
int number = value;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
byte = (number % 256);
|
||||
settingsFile.write(&byte, 1);
|
||||
number = (number >> 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,17 +226,17 @@ void Settings::changeVideoMode(sf::RenderWindow& window) const {
|
||||
window.setPosition(sf::Vector2i((desktopSize.x / 2) - (windowSize.x / 2), (desktopSize.y / 2) - (windowSize.y / 2)));
|
||||
}
|
||||
|
||||
bool Settings::raiseMasterVolume() {
|
||||
if (this->masterVolume < 100) {
|
||||
this->masterVolume = std::min(this->masterVolume + 5, 100);
|
||||
bool Settings::lengthenStartTimer() {
|
||||
if (this->startTimerLength < START_TIMER_MAX) {
|
||||
this->startTimerLength++;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Settings::lowerMasterVolume() {
|
||||
if (this->masterVolume > 0) {
|
||||
this->masterVolume = std::max(this->masterVolume - 5, 0);
|
||||
bool Settings::shortenStartTimer() {
|
||||
if (this->startTimerLength > 0) {
|
||||
this->startTimerLength--;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -221,6 +259,10 @@ void Settings::unselectPieces(int index) {
|
||||
void Settings::confirmSelectedPieces() {
|
||||
this->menu.getPiecesList().unselectAll();
|
||||
|
||||
if (this->getSelectedPieces().size() == 0) {
|
||||
this->selectedPieces.push_back(DEFAULT_SELECTION);
|
||||
}
|
||||
|
||||
for (const auto& [type, value] : this->selectedPieces) {
|
||||
int size = getSizeOfPieces(type);
|
||||
|
||||
@@ -233,13 +275,37 @@ void Settings::confirmSelectedPieces() {
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (size > MAXIMUM_PIECES_SIZE) return;
|
||||
|
||||
this->menu.getPiecesList().selectPiece(size, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Settings::increaseDistribution(int size) {
|
||||
if (size < 1 || size > this->maximumPiecesSize) return false;
|
||||
|
||||
if (this->distributions.at(size) < DISTRIBUTION_MAX) {
|
||||
this->distributions.at(size)++;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Settings::decreaseDistribution(int size) {
|
||||
if (size < 1 || size > this->maximumPiecesSize) return false;
|
||||
|
||||
if (this->distributions.at(size) > 0) {
|
||||
this->distributions.at(size)--;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Settings::confirmDistribution() {
|
||||
for (int i = 1; i <= 15; i++) {
|
||||
this->menu.getPiecesList().changeCustomDistribution(i, (double) 1 / (this->distributions.at(i) + 0.001));
|
||||
}
|
||||
}
|
||||
|
||||
Menu& Settings::getMenu() {
|
||||
return this->menu;
|
||||
}
|
||||
@@ -248,6 +314,10 @@ Keybinds& Settings::getKeybinds() {
|
||||
return this->keybinds.at(this->chosenKeybinds);
|
||||
}
|
||||
|
||||
int Settings::getMaximumPiecesSize() const {
|
||||
return this->maximumPiecesSize;
|
||||
}
|
||||
|
||||
int Settings::getKeybindsLayout() const {
|
||||
return this->chosenKeybinds;
|
||||
}
|
||||
@@ -260,10 +330,14 @@ int Settings::getWindowSizeMultiplier() const {
|
||||
return WINDOW_SIZE_MULTIPLIERS[this->windowSizeMode];
|
||||
}
|
||||
|
||||
int Settings::getMasterVolume() const {
|
||||
return this->masterVolume;
|
||||
int Settings::getStartTimerLength() const {
|
||||
return this->startTimerLength;
|
||||
}
|
||||
|
||||
const std::vector<std::pair<PiecesType, int>>& Settings::getSelectedPieces() const {
|
||||
return this->selectedPieces;
|
||||
}
|
||||
|
||||
const std::vector<int>& Settings::getDistributions() const {
|
||||
return this->distributions;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Core/Menu.h"
|
||||
#include "StartUpMenu.h"
|
||||
#include "Keybinds.h"
|
||||
#include "PiecesType.h"
|
||||
|
||||
@@ -10,26 +11,21 @@
|
||||
static const int MAXIMUM_BOARD_WIDTH = 40;
|
||||
static const int MAXIMUM_BOARD_HEIGHT = 40;
|
||||
|
||||
//#define __JMINOS_RELEASE__
|
||||
#ifdef __JMINOS_RELEASE__
|
||||
static const int MAXIMUM_PIECES_SIZE = 15;
|
||||
#else
|
||||
static const int MAXIMUM_PIECES_SIZE = 10;
|
||||
#endif
|
||||
|
||||
|
||||
class Settings {
|
||||
private:
|
||||
Menu menu;
|
||||
int maximumPiecesSize;
|
||||
std::vector<Keybinds> keybinds;
|
||||
int chosenKeybinds;
|
||||
int windowSizeMode;
|
||||
int masterVolume;
|
||||
int startTimerLength;
|
||||
Gamemode gamemode;
|
||||
std::vector<std::pair<PiecesType, int>> selectedPieces;
|
||||
std::vector<int> distributions;
|
||||
|
||||
public:
|
||||
Settings();
|
||||
Settings(int maximumPiecesSize);
|
||||
|
||||
void loadSettingsFromFile();
|
||||
|
||||
@@ -47,9 +43,9 @@ class Settings {
|
||||
|
||||
void changeVideoMode(sf::RenderWindow& window) const;
|
||||
|
||||
bool raiseMasterVolume();
|
||||
bool lengthenStartTimer();
|
||||
|
||||
bool lowerMasterVolume();
|
||||
bool shortenStartTimer();
|
||||
|
||||
void setGamemode(Gamemode gamemode);
|
||||
|
||||
@@ -59,17 +55,27 @@ class Settings {
|
||||
|
||||
void confirmSelectedPieces();
|
||||
|
||||
bool increaseDistribution(int size);
|
||||
|
||||
bool decreaseDistribution(int size);
|
||||
|
||||
void confirmDistribution();
|
||||
|
||||
Menu& getMenu();
|
||||
|
||||
Keybinds& getKeybinds();
|
||||
|
||||
int getMaximumPiecesSize() const;
|
||||
|
||||
int getKeybindsLayout() const;
|
||||
|
||||
Gamemode getGamemode() const;
|
||||
|
||||
int getWindowSizeMultiplier() const;
|
||||
|
||||
int getMasterVolume() const;
|
||||
int getStartTimerLength() const;
|
||||
|
||||
const std::vector<std::pair<PiecesType, int>>& getSelectedPieces() const;
|
||||
|
||||
const std::vector<int>& getDistributions() const;
|
||||
};
|
||||
|
||||
15
src/GraphicalUI/StartUpMenu.cpp
Normal file
15
src/GraphicalUI/StartUpMenu.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#include "StartUpMenu.h"
|
||||
|
||||
#include "PlayerCursor.h"
|
||||
|
||||
|
||||
StartUpMenu::StartUpMenu() :
|
||||
playerCursor({LOADED_PIECES_SIZE}) {
|
||||
|
||||
this->playerCursor.goToPosition({MINIMUM_PIECES_SIZE, 0});
|
||||
}
|
||||
|
||||
int StartUpMenu::getMaximumPiecesSize() {
|
||||
return LOADED_PIECES_SIZE;
|
||||
//TODO
|
||||
}
|
||||
28
src/GraphicalUI/StartUpMenu.h
Normal file
28
src/GraphicalUI/StartUpMenu.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "PiecesType.h"
|
||||
#include "PlayerCursor.h"
|
||||
|
||||
|
||||
static const int MINIMUM_PIECES_SIZE = 4;
|
||||
static const int MAXIMUM_PIECES_SIZE = 15;
|
||||
|
||||
//#define __JMINOS_RELEASE__
|
||||
#ifdef __JMINOS_RELEASE__
|
||||
static const int LOADED_PIECES_SIZE = 15;
|
||||
#else
|
||||
static const int LOADED_PIECES_SIZE = 10;
|
||||
#endif
|
||||
|
||||
static const std::pair<PiecesType, int> DEFAULT_SELECTION = {ALL_PIECES, MINIMUM_PIECES_SIZE};
|
||||
|
||||
|
||||
class StartUpMenu {
|
||||
private:
|
||||
PlayerCursor playerCursor;
|
||||
|
||||
public:
|
||||
StartUpMenu();
|
||||
|
||||
int getMaximumPiecesSize();
|
||||
};
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "StartUpMenu.h"
|
||||
#include "GraphApp.h"
|
||||
#include "../Pieces/PiecesFiles.h"
|
||||
|
||||
@@ -13,7 +14,7 @@ int main() {
|
||||
std::srand(std::time(NULL));
|
||||
|
||||
PiecesFiles pf;
|
||||
for (int i = 1; i <= MAXIMUM_PIECES_SIZE; i++) {
|
||||
for (int i = 1; i <= LOADED_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);
|
||||
@@ -30,7 +31,10 @@ int main() {
|
||||
}
|
||||
}
|
||||
|
||||
GraphApp UI;
|
||||
StartUpMenu startUp;
|
||||
int maximumPiecesSize = startUp.getMaximumPiecesSize();
|
||||
|
||||
GraphApp UI(maximumPiecesSize);
|
||||
UI.run();
|
||||
|
||||
return 0;
|
||||
@@ -63,8 +67,8 @@ void resetSettingsFile() {
|
||||
byte = 2;
|
||||
settingsFile.write(&byte, 1);
|
||||
|
||||
// master volume
|
||||
byte = 50;
|
||||
// start timer length
|
||||
byte = 2;
|
||||
settingsFile.write(&byte, 1);
|
||||
|
||||
// gamemode
|
||||
@@ -80,8 +84,12 @@ void resetSettingsFile() {
|
||||
settingsFile.write(&byte, 1);
|
||||
|
||||
// piece distribution
|
||||
byte = 0;
|
||||
byte = DEFAULT;
|
||||
settingsFile.write(&byte, 1);
|
||||
for (int i = 1; i <= 15; i++) {
|
||||
byte = 1;
|
||||
settingsFile.write(&byte, 1);
|
||||
}
|
||||
|
||||
// selected pieces
|
||||
byte = ALL_PIECES;
|
||||
|
||||
@@ -91,7 +91,7 @@ bool PiecesFiles::loadPieces(int polyominoSize, std::vector<Piece>& pieces, std:
|
||||
char positionByte;
|
||||
for (int i = 0; i < polyominoSize; i++) {
|
||||
piecesFile.get(positionByte);
|
||||
int x = (positionByte & xMask) >> 4;
|
||||
int x = ((unsigned char) positionByte & xMask) >> 4;
|
||||
int y = positionByte & yMask;
|
||||
piecePositions.insert(Position{x, y});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user