From 434bb963e02548282a172a4d9cbe21b8642385e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D1=8F=D1=87=D0=B5=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A2?= =?UTF-8?q?=D0=B8=D1=82=D0=BE=D0=B2?= Date: Sun, 22 Jul 2018 02:25:56 +0300 Subject: [PATCH 1/6] Added pinch and drag gestures. WARNING!!! Changing board size through settings will result in OS crash! --- README.md | 3 +- source/Engine/GameObject.cpp | 6 +- source/Engine/GameObject.hpp | 3 +- source/Engine/Input.cpp | 92 +++++++++++++++++++++++++++---- source/Engine/Input.hpp | 33 ++++++++++- source/Engine/Widget.cpp | 4 +- source/Engine/Widget.hpp | 3 +- source/GameObjects/Board.cpp | 2 +- source/GameObjects/Board.hpp | 3 +- source/Minesweeper.cpp | 11 +++- source/Scenes/GameScene.cpp | 70 +++++++++++++---------- source/Scenes/GameScene.hpp | 3 +- source/Widgets/SettingsWidget.cpp | 74 ++++++++++++++++++++++--- 13 files changed, 243 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index 68a9faa..38dd664 100644 --- a/README.md +++ b/README.md @@ -13,10 +13,11 @@ Feel free to report bugs and contribute! * ![Reset field](https://raw.githubusercontent.com/rincew1nd/Minesweeper-Switch/master/romfs/easyButton.bmp) 0.1% of cells contains mine * ![Reset field](https://raw.githubusercontent.com/rincew1nd/Minesweeper-Switch/master/romfs/mediumButton.bmp) 0.2% of cells contains mine * ![Reset field](https://raw.githubusercontent.com/rincew1nd/Minesweeper-Switch/master/romfs/hardButton.bmp) 0.3% of cells contains mine +* Pinch to resize board +* Drag to move board ## To-Do: -* Touchscreen gestures for zooming and moving field * Timer and scoreboard ## Roadmap for next release: diff --git a/source/Engine/GameObject.cpp b/source/Engine/GameObject.cpp index 5643c6c..4372dcf 100644 --- a/source/Engine/GameObject.cpp +++ b/source/Engine/GameObject.cpp @@ -20,8 +20,8 @@ void GameObject::SetAction(std::function func) _onPress = func; } -bool GameObject::Hovered(touchPosition* pos) +bool GameObject::Hovered(TouchInfo* ti) { - return pos->px >= _rect->x && pos->px <= _rect->x + _rect->w && - pos->py >= _rect->y && pos->py <= _rect->y + _rect->h; + return ti->ValueOne >= _rect->x && ti->ValueOne <= _rect->x + _rect->w && + ti->ValueTwo >= _rect->y && ti->ValueTwo <= _rect->y + _rect->h; } \ No newline at end of file diff --git a/source/Engine/GameObject.hpp b/source/Engine/GameObject.hpp index d4cad7f..ff8981a 100644 --- a/source/Engine/GameObject.hpp +++ b/source/Engine/GameObject.hpp @@ -1,5 +1,6 @@ #pragma once +#include "Input.hpp" #include #include "SDL2/SDL.h" #include @@ -11,7 +12,7 @@ class GameObject GameObject(int, int, int, int); void SetAction(std::function); void Press() { if (_onPress != nullptr) _onPress(); }; - bool Hovered(touchPosition*); + bool Hovered(TouchInfo*); void Move(int, int); virtual ~GameObject() {}; diff --git a/source/Engine/Input.cpp b/source/Engine/Input.cpp index a12defb..160e9ab 100644 --- a/source/Engine/Input.cpp +++ b/source/Engine/Input.cpp @@ -1,28 +1,100 @@ #include "Input.hpp" -#include -#include +#define ABS(x) ((x)<0?-(x):(x)) int Input::Scan() { hidScanInput(); _touchCount = hidTouchCount(); + _touchType = None; - //Prevent multiple clicks from one touch press - if (_touchCount == 0) - _released = true; - else - if (!_released) - _touchCount = 0; - else - _released = false; + //If touch happens, check touch type + if (_touchCount > 0) + { + //If touch is just pressed, get current app run time + if (_touchPressTime == 0) + { + _touchPressTime = SDL_GetTicks(); + _touchPressed = true; + } + //If touch is held more then 500 ms, change event to pinch or drag + if (SDL_GetTicks() - _touchPressTime >= 250) + { + _lastDragX = _touchPoints[0].px; + _lastDragY = _touchPoints[0].py; + _touchType = _touchCount > 1 ? Pinch : Drag; + } + } + //Reset touch info + else if (_touchPressTime > 0) + { + if (SDL_GetTicks() - _touchPressTime < 500) + _touchType = Press; + _touchPressTime = 0; + _touchPressed = false; + _firstPinch = true; + _firstDrag = true; + + _lastDragX = 0; + _lastDragY = 0; + _lastPinchDelta = 0; + + _lastTouchInfo->ValueOne = 0; + _lastTouchInfo->ValueTwo = 0; + } + + //Store touch info for (int i = 0; i < _touchCount; i++) hidTouchRead(&_touchPoints[i], i); + //Return is touch pressed return _touchCount; } +TouchInfo* Input::GetTouchInfo() +{ + _lastTouchInfo->Type = None; + if (_touchType == Press && !_touchPressed) + { + _lastTouchInfo->Type = Press; + _lastTouchInfo->ValueOne = _touchPoints[0].px; + _lastTouchInfo->ValueTwo = _touchPoints[0].py; + } else if (_touchType == Drag) + { + _lastTouchInfo->Type = Drag; + _lastTouchInfo->ValueOne = _touchPoints[0].px - _lastDragX; + _lastTouchInfo->ValueTwo = _touchPoints[0].py - _lastDragY; + + if (_firstDrag) + { + _lastTouchInfo->ValueOne = 0; + _lastTouchInfo->ValueTwo = 0; + _firstDrag = false; + _firstPinch = true; + } + } else if (_touchType == Pinch) + { + int x = _touchPoints[0].px - _touchPoints[1].px; + int y = _touchPoints[0].py - _touchPoints[1].py; + _lastTouchInfo->Type = Pinch; + _lastTouchInfo->ValueOne = sqrt(fabs(x) + fabs(y)); + _lastTouchInfo->ValueTwo = 0; + + int lastPinch = _lastPinchDelta; + _lastPinchDelta = _lastTouchInfo->ValueOne; + _lastTouchInfo->ValueOne -= lastPinch; + + if (_firstPinch) + { + _lastTouchInfo->ValueOne = 0; + _firstPinch = false; + _firstDrag = true; + } + } + return _lastTouchInfo; +} + touchPosition* Input::GetPointPosition(int i) { if (i < _touchCount) diff --git a/source/Engine/Input.hpp b/source/Engine/Input.hpp index e9f2c9a..dad37ae 100644 --- a/source/Engine/Input.hpp +++ b/source/Engine/Input.hpp @@ -1,14 +1,43 @@ #pragma once #include +#include + +enum InputType +{ + None, + Press, + Drag, + Pinch +}; + +typedef struct TouchInfo +{ + InputType Type; + int ValueOne; + int ValueTwo; +} TouchInfo; class Input { public: int Scan(); touchPosition* GetPointPosition(int); + TouchInfo* GetTouchInfo(); + private: touchPosition _touchPoints[10]; - int _touchCount; - bool _released; + + InputType _touchType = None; + int _lastDragX = 0; + int _lastDragY = 0; + int _lastPinchDelta = 0; + + TouchInfo* _lastTouchInfo = new TouchInfo(); + + int _touchCount = 0; + bool _touchPressed = false; + bool _firstPinch = true; + bool _firstDrag = true; + Uint32 _touchPressTime = 0; }; \ No newline at end of file diff --git a/source/Engine/Widget.cpp b/source/Engine/Widget.cpp index 0d1b978..faeec24 100644 --- a/source/Engine/Widget.cpp +++ b/source/Engine/Widget.cpp @@ -55,9 +55,9 @@ void Widget::Draw(SDL_Renderer* renderer) } } -void Widget::HandleTouch(touchPosition* pos) +void Widget::HandleTouch(TouchInfo* ti) { for(int i = 0; i < _buttons.size(); i++) - if (_buttons[i]->Hovered(pos) && _buttons[i]->IsVisible()) + if (_buttons[i]->Hovered(ti) && _buttons[i]->IsVisible()) _buttons[i]->Press(); } \ No newline at end of file diff --git a/source/Engine/Widget.hpp b/source/Engine/Widget.hpp index 48a940b..af20411 100644 --- a/source/Engine/Widget.hpp +++ b/source/Engine/Widget.hpp @@ -1,5 +1,6 @@ #pragma once +#include "Input.hpp" #include "Button.hpp" #include "TextObject.hpp" #include @@ -8,7 +9,7 @@ class Widget { public: Widget(int, int, int, int); - void HandleTouch(touchPosition*); + void HandleTouch(TouchInfo*); void HandleJoystick() {}; bool IsVisible; diff --git a/source/GameObjects/Board.cpp b/source/GameObjects/Board.cpp index a6d899b..0035be4 100644 --- a/source/GameObjects/Board.cpp +++ b/source/GameObjects/Board.cpp @@ -102,7 +102,7 @@ void Board::Draw(SDL_Renderer* renderer) _cells[i]->Draw(GridLeft, GridTop, renderer); } -void Board::HandleClick(touchPosition* point) +void Board::HandleClick(TouchInfo* point) { for (int i = 0; i < _cells.size(); i++) if (_cells[i]->Hovered(point) && _cells[i]->IsVisible()) diff --git a/source/GameObjects/Board.hpp b/source/GameObjects/Board.hpp index bcbcee9..ae22005 100644 --- a/source/GameObjects/Board.hpp +++ b/source/GameObjects/Board.hpp @@ -10,6 +10,7 @@ #include "../Engine/Defaults.hpp" #include "../Engine/Resources.hpp" +#include "../Engine/Input.hpp" class Board { @@ -20,7 +21,7 @@ class Board void OpenAll(); void Restart(); void Draw(SDL_Renderer*); - void HandleClick(touchPosition*); + void HandleClick(TouchInfo*); void Move(int, int); bool NeedRestart = false; diff --git a/source/Minesweeper.cpp b/source/Minesweeper.cpp index 32b3e23..4e86008 100644 --- a/source/Minesweeper.cpp +++ b/source/Minesweeper.cpp @@ -58,8 +58,13 @@ void Minesweeper::Start() while (appletMainLoop()) { //Handle touchscreen - if (_input->Scan()) - _gameScene->HandleClick(_input->GetPointPosition(0)); + _input->Scan(); + TouchInfo* ti = _input->GetTouchInfo(); + if (ti->Type != None) + { + _gameScene->HandleClick(ti); + printf("%d - %d:%d\n", ti->Type, ti->ValueOne, ti->ValueTwo); + } //Handle joy-con button press if (hidKeysDown(CONTROLLER_P1_AUTO) & KEY_PLUS) break; @@ -76,7 +81,7 @@ void Minesweeper::Start() SDL_RenderPresent(_renderer); //Pause - SDL_Delay(16); + SDL_Delay(6); } DeinitSDL(); diff --git a/source/Scenes/GameScene.cpp b/source/Scenes/GameScene.cpp index fa03be4..0f92b25 100644 --- a/source/Scenes/GameScene.cpp +++ b/source/Scenes/GameScene.cpp @@ -6,7 +6,7 @@ GameScene::GameScene(Resources* resources) _board = new Board(Globals::BoardWidth, Globals::BoardHeight, _resources); - _widgets.push_back((Widget*)new SettingsWidget(490, 200, 450, 350, _resources)); + _widgets.push_back((Widget*)new SettingsWidget(410, 90, 450, 540, _resources)); _widgets[0]->SetColor(152, 120, 24); _widgets.push_back((Widget*)new GameOverWidget(490, 250, 300, 100, _resources)); _widgets[1]->SetColor(152, 120, 24); @@ -23,33 +23,48 @@ void GameScene::Draw(SDL_Renderer* renderer) _widgets[i]->Draw(renderer); } -void GameScene::HandleClick(touchPosition* point) +void GameScene::HandleClick(TouchInfo* ti) { - int widgetVisible = false; - - for (int i = 0; i < _widgets.size(); i++) - if (_widgets[i]->IsVisible) + switch (ti->Type) + { + case 1: { - _widgets[i]->HandleTouch(point); - widgetVisible = true; + int widgetVisible = false; + int guiClick = false; + for (int i = 0; i < _widgets.size(); i++) + if (_widgets[i]->IsVisible) + { + _widgets[i]->HandleTouch(ti); + widgetVisible = true; + } + if (!widgetVisible) + { + for (int i = 0; i < _buttons.size(); i++) + if (_buttons[i]->Hovered(ti) && _buttons[i]->IsVisible()) + { + _buttons[i]->Press(); + guiClick = true; + } + + if (!guiClick) + _board->HandleClick(ti); + + if (_board->NeedRestart) + _board->Restart(); + } + if (_board->IsAllOpened()) + { + ((GameOverWidget*)_widgets[1])->Show(true); + _board->Restart(); + } + break; } - - if (!widgetVisible) - { - for (int i = 0; i < _buttons.size(); i++) - if (_buttons[i]->Hovered(point) && _buttons[i]->IsVisible()) - _buttons[i]->Press(); - - _board->HandleClick(point); - - if (_board->NeedRestart) - _board->Restart(); - } - - if (_board->IsAllOpened()) - { - ((GameOverWidget*)_widgets[1])->Show(true); - _board->Restart(); + case 2: + _board->Move(ti->ValueOne, ti->ValueTwo); + break; + case 3: + Globals::CellSize += ti->ValueOne; + break; } } @@ -75,9 +90,4 @@ void GameScene::InitButtons() Widget* settings = _widgets[0]; button->SetAction([settings] { settings->IsVisible = true; }); _buttons.push_back(button); - - button = new Button(800, 665, 50, 50, "settingsButton"); - button->SetTexture(_resources->GetTexture(button->GetName())); - button->SetAction([this](){ this->GetBoard()->Move(10, 10); }); - _buttons.push_back(button); } \ No newline at end of file diff --git a/source/Scenes/GameScene.hpp b/source/Scenes/GameScene.hpp index 56ea5da..1d10774 100644 --- a/source/Scenes/GameScene.hpp +++ b/source/Scenes/GameScene.hpp @@ -1,3 +1,4 @@ +#include "../Engine/Input.hpp" #include "../GameObjects/Board.hpp" #include "../Engine/Button.hpp" @@ -10,7 +11,7 @@ class GameScene GameScene(Resources*); void InitButtons(); void Draw(SDL_Renderer*); - void HandleClick(touchPosition*); + void HandleClick(TouchInfo*); Board* GetBoard() { return _board; }; private: diff --git a/source/Widgets/SettingsWidget.cpp b/source/Widgets/SettingsWidget.cpp index fb1bb4e..1673749 100644 --- a/source/Widgets/SettingsWidget.cpp +++ b/source/Widgets/SettingsWidget.cpp @@ -8,24 +8,26 @@ SettingsWidget::SettingsWidget(int x, int y, int w, int h, Resources* res) : Wid TextObject* textObject = new TextObject(x+w/2, y+45, res->GetFont()); textObject->Text = "PAUSE"; _textes.push_back(textObject); - textObject = new TextObject(x+w/2, y+120, res->GetFont()); - textObject->Text = "Difficulty"; - _textes.push_back(textObject); - textObject = new TextObject(x+w/2, y+270, res->GetFont()); + textObject = new TextObject(x+w/2, y+450, res->GetFont()); textObject->Text = "Press + to"; _textes.push_back(textObject); - textObject = new TextObject(x+w/2, y+305, res->GetFont()); + textObject = new TextObject(x+w/2, y+500, res->GetFont()); textObject->Text = "exit application"; _textes.push_back(textObject); - textObject = new TextObject(x+w/2, y+175, res->GetFont()); - textObject->Text = std::to_string(Globals::Dificulty); - _textes.push_back(textObject); Button* button = new Button(x + w - 70, y + 20, 50, 50, "escButton"); button->AddTexture(res->GetTexture(button->GetName())); button->SetTexture(0); button->SetAction([this]{ this->IsVisible = false; }); _buttons.push_back(button); + + // Difficulty + textObject = new TextObject(x+w/2, y+120, res->GetFont()); + textObject->Text = "Difficulty"; + _textes.push_back(textObject); + textObject = new TextObject(x+w/2, y+175, res->GetFont()); + textObject->Text = std::to_string(Globals::Dificulty); + _textes.push_back(textObject); button = new Button(x+20, y+150, 50, 50, "minusButton"); button->AddTexture(res->GetTexture(button->GetName())); @@ -46,4 +48,60 @@ SettingsWidget::SettingsWidget(int x, int y, int w, int h, Resources* res) : Wid textObject->Text = std::to_string(Globals::Dificulty); }); _buttons.push_back(button); + + //Board height + textObject = new TextObject(x+w/2, y+225, res->GetFont()); + textObject->Text = "Board Height"; + _textes.push_back(textObject); + textObject = new TextObject(x+w/2, y+275, res->GetFont()); + textObject->Text = std::to_string(Globals::BoardHeight); + _textes.push_back(textObject); + + button = new Button(x+20, y+250, 50, 50, "minusButton"); + button->AddTexture(res->GetTexture(button->GetName())); + button->SetTexture(0); + button->SetAction([textObject]{ + if (--Globals::BoardHeight < 1) + Globals::BoardHeight = 1; + textObject->Text = std::to_string(Globals::BoardHeight); + }); + _buttons.push_back(button); + + button = new Button(x+w-70, y+250, 50, 50, "plusButton"); + button->AddTexture(res->GetTexture(button->GetName())); + button->SetTexture(0); + button->SetAction([textObject]{ + if (++Globals::BoardHeight > 40) + Globals::BoardHeight = 40; + textObject->Text = std::to_string(Globals::BoardHeight); + }); + _buttons.push_back(button); + + //Board width + textObject = new TextObject(x+w/2, y+325, res->GetFont()); + textObject->Text = "Board Width"; + _textes.push_back(textObject); + textObject = new TextObject(x+w/2, y+375, res->GetFont()); + textObject->Text = std::to_string(Globals::BoardWidth); + _textes.push_back(textObject); + + button = new Button(x+20, y+350, 50, 50, "minusButton"); + button->AddTexture(res->GetTexture(button->GetName())); + button->SetTexture(0); + button->SetAction([textObject]{ + if (--Globals::BoardWidth < 1) + Globals::BoardWidth = 1; + textObject->Text = std::to_string(Globals::BoardWidth); + }); + _buttons.push_back(button); + + button = new Button(x+w-70, y+350, 50, 50, "plusButton"); + button->AddTexture(res->GetTexture(button->GetName())); + button->SetTexture(0); + button->SetAction([textObject]{ + if (++Globals::BoardWidth > 40) + Globals::BoardWidth = 40; + textObject->Text = std::to_string(Globals::BoardWidth); + }); + _buttons.push_back(button); } \ No newline at end of file From 12d48485ab0ccc60c494b2fffad610e6a3c7e911 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D1=8F=D1=87=D0=B5=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A2?= =?UTF-8?q?=D0=B8=D1=82=D0=BE=D0=B2?= Date: Tue, 24 Jul 2018 01:11:17 +0300 Subject: [PATCH 2/6] Now board size can be adjusted! Mine counter. Fixed game over screen. Now if all cells with mines are flagged, it's a win. --- source/GameObjects/Board.cpp | 111 ++++++++++++++++++++---------- source/GameObjects/Board.hpp | 16 +++-- source/GameObjects/Cell.cpp | 1 - source/Minesweeper.cpp | 3 - source/Scenes/GameScene.cpp | 27 +++++--- source/Scenes/GameScene.hpp | 3 + source/Widgets/SettingsWidget.cpp | 23 ++++--- source/Widgets/SettingsWidget.hpp | 2 +- 8 files changed, 123 insertions(+), 63 deletions(-) diff --git a/source/GameObjects/Board.cpp b/source/GameObjects/Board.cpp index 0035be4..8a7e82a 100644 --- a/source/GameObjects/Board.cpp +++ b/source/GameObjects/Board.cpp @@ -2,104 +2,143 @@ #include #include -Board::Board(int w, int h, Resources* resources) +Board::Board(Resources* resources) { - GridLeft = (Globals::WindowWidth - Globals::BoardWidth * Globals::CellSize) / 2; - GridTop = (Globals::WindowHeight - Globals::BoardHeight * Globals::CellSize) / 2; - _resources = resources; + GenerateBoard(); +} + +void Board::GenerateBoard() +{ + _boardHeight = Globals::BoardHeight; + _boardWidth = Globals::BoardWidth; - for (int y = 0; y < Globals::BoardHeight; y++) - for (int x = 0; x < Globals::BoardWidth; x++) + _gridLeft = (Globals::WindowWidth - _boardWidth * Globals::CellSize) / 2; + _gridTop = (Globals::WindowHeight - _boardHeight * Globals::CellSize) / 2; + + for (int y = 0; y < _boardHeight; y++) + for (int x = 0; x < _boardWidth; x++) { - Cell* cell = new Cell(x, y, GridLeft, GridTop); + Cell* cell = new Cell(x, y, _gridLeft, _gridTop); cell->AddTexture(_resources->GetTexture(Closed, 0)); cell->AddTexture(_resources->GetTexture(Flagged, 0)); cell->SetTexture(0); cell->SetAction([this, cell]{ if (!cell->SetState(Globals::IsFlag ? Flagged : Opened)) + { NeedRestart = true; + GameOver = true; + } }); _cells.push_back(cell); } - GenerateBoard(); + for (int i = 0; i < _boardWidth; i++) + for (int j = 0; j < _boardHeight; j++) + for (int di = i-1; di <= i+1; di++) + for (int dj = j-1; dj <= j+1; dj++) + if (!(di==i && dj==j) && IsOnBoard(di, dj)) + GetCell(i, j)->AddNearCell(GetCell(di, dj)); + + GenerateMinefield(); } -void Board::GenerateBoard() +void Board::GenerateMinefield() { + MineCount = 0; + srand(time(0)); - for (int mineCount = 0; mineCount <= Globals::BoardHeight * Globals::BoardWidth * 0.1f * Globals::Dificulty; mineCount++) + for (int mineCount = 0; mineCount <= _boardHeight * _boardWidth * 0.1f * Globals::Dificulty; mineCount++) { while(true) { - int posX = rand() % Globals::BoardWidth; - int posY = rand() % Globals::BoardHeight; + int posX = rand() % _boardWidth; + int posY = rand() % _boardHeight; if (GetCell(posX, posY)->NearMinesCount != 9) { GetCell(posX, posY)->NearMinesCount = 9; + MineCount++; break; } } } - for (int i = 0; i < Globals::BoardWidth; i++) - for (int j = 0; j < Globals::BoardHeight; j++) + for (int i = 0; i < _boardWidth; i++) + for (int j = 0; j < _boardHeight; j++) for (int di = i-1; di <= i+1; di++) for (int dj = j-1; dj <= j+1; dj++) if (!(di==i && dj==j) && IsOnBoard(di, dj)) - { - GetCell(i, j)->AddNearCell(GetCell(di, dj)); if (GetCell(di, dj)->NearMinesCount == 9 && GetCell(i, j)->NearMinesCount != 9) GetCell(i, j)->NearMinesCount++; - } - for (int i = 0; i < Globals::BoardWidth * Globals::BoardHeight; i++) + for (int i = 0; i < _boardWidth * _boardHeight; i++) _cells[i]->AddTexture(_resources->GetTexture(Opened, _cells[i]->NearMinesCount), 2); } Cell* Board::GetCell(int x, int y) { - return _cells[x + y * Globals::BoardWidth]; + return _cells[x + y * _boardWidth]; } -bool Board::IsAllOpened() +bool Board::CheckState() { - for (int i = 0; i < Globals::BoardWidth * Globals::BoardHeight; i++) + FlagCount = 0; + bool allFlagsCorrect = true; + bool allCellsOppened = true; + + for (int i = 0; i < _boardWidth * _boardHeight; i++) + { + if (_cells[i]->GetState() == Flagged) + { + if (_cells[i]->NearMinesCount != 9) + allFlagsCorrect = false; + FlagCount++; + } if (_cells[i]->NearMinesCount != 9 && _cells[i]->GetState() != Opened) - return false; - return true; + allCellsOppened = false; + } + + allFlagsCorrect = (allFlagsCorrect) ? FlagCount == MineCount ? true : false : false; + return allCellsOppened || allFlagsCorrect; } bool Board::IsOnBoard(int x, int y) { - if (x >= 0 && x < Globals::BoardWidth) - if (y >= 0 && y < Globals::BoardHeight) + if (x >= 0 && x < _boardWidth) + if (y >= 0 && y < _boardHeight) return true; return false; } void Board::OpenAll() { - for (int i = 0; i < Globals::BoardWidth * Globals::BoardHeight; i++) + for (int i = 0; i < _boardWidth * _boardHeight; i++) _cells[i]->SetState(Opened); } void Board::Restart() { - NeedRestart = false; - - for (int i = 0; i < Globals::BoardWidth * Globals::BoardHeight; i++) - _cells[i]->Reset(); - - GenerateBoard(); + if (NeedRestart) + { + NeedRestart = false; + for (int i = 0; i < _boardWidth * _boardHeight; i++) + _cells[i]->Reset(); + GenerateMinefield(); + } + if (NeedHardRestart) + { + NeedHardRestart = false; + _cells.clear(); + GenerateBoard(); + } } void Board::Draw(SDL_Renderer* renderer) { - for (int i = 0; i < Globals::BoardWidth * Globals::BoardHeight; i++) - _cells[i]->Draw(GridLeft, GridTop, renderer); + Restart(); + for (int i = 0; i < _boardWidth * _boardHeight; i++) + _cells[i]->Draw(_gridLeft, _gridTop, renderer); } void Board::HandleClick(TouchInfo* point) @@ -111,6 +150,6 @@ void Board::HandleClick(TouchInfo* point) void Board::Move(int dx, int dy) { - GridLeft += dx; - GridTop += dy; + _gridLeft += dx; + _gridTop += dy; } \ No newline at end of file diff --git a/source/GameObjects/Board.hpp b/source/GameObjects/Board.hpp index ae22005..3812971 100644 --- a/source/GameObjects/Board.hpp +++ b/source/GameObjects/Board.hpp @@ -15,8 +15,8 @@ class Board { public: - Board(int, int, Resources*); - bool IsAllOpened(); + Board(Resources*); + bool CheckState(); bool IsOnBoard(int, int); void OpenAll(); void Restart(); @@ -25,13 +25,21 @@ class Board void Move(int, int); bool NeedRestart = false; + bool NeedHardRestart = false; + bool GameOver = false; + + int MineCount = 0; + int FlagCount = 0; private: void GenerateBoard(); + void GenerateMinefield(); Cell* GetCell(int, int); - int GridLeft; - int GridTop; + int _gridLeft; + int _gridTop; + int _boardHeight; + int _boardWidth; Resources *_resources; std::vector _cells; }; \ No newline at end of file diff --git a/source/GameObjects/Cell.cpp b/source/GameObjects/Cell.cpp index 569ae1e..93ad2ac 100644 --- a/source/GameObjects/Cell.cpp +++ b/source/GameObjects/Cell.cpp @@ -69,7 +69,6 @@ void Cell::Reset() { NearMinesCount = 0; _state = Closed; - _nearCells.clear(); SetTexture(0); } diff --git a/source/Minesweeper.cpp b/source/Minesweeper.cpp index 4e86008..a5ebf12 100644 --- a/source/Minesweeper.cpp +++ b/source/Minesweeper.cpp @@ -61,10 +61,7 @@ void Minesweeper::Start() _input->Scan(); TouchInfo* ti = _input->GetTouchInfo(); if (ti->Type != None) - { _gameScene->HandleClick(ti); - printf("%d - %d:%d\n", ti->Type, ti->ValueOne, ti->ValueTwo); - } //Handle joy-con button press if (hidKeysDown(CONTROLLER_P1_AUTO) & KEY_PLUS) break; diff --git a/source/Scenes/GameScene.cpp b/source/Scenes/GameScene.cpp index 0f92b25..81848aa 100644 --- a/source/Scenes/GameScene.cpp +++ b/source/Scenes/GameScene.cpp @@ -4,9 +4,9 @@ GameScene::GameScene(Resources* resources) { _resources = resources; - _board = new Board(Globals::BoardWidth, Globals::BoardHeight, _resources); + _board = new Board(_resources); - _widgets.push_back((Widget*)new SettingsWidget(410, 90, 450, 540, _resources)); + _widgets.push_back((Widget*)new SettingsWidget(410, 90, 450, 540, _resources, &(_board->NeedHardRestart))); _widgets[0]->SetColor(152, 120, 24); _widgets.push_back((Widget*)new GameOverWidget(490, 250, 300, 100, _resources)); _widgets[1]->SetColor(152, 120, 24); @@ -21,6 +21,8 @@ void GameScene::Draw(SDL_Renderer* renderer) _buttons[i]->Draw(renderer); for (int i = 0; i < _widgets.size(); i++) _widgets[i]->Draw(renderer); + for (int i = 0; i < _textes.size(); i++) + _textes[i]->Draw(renderer); } void GameScene::HandleClick(TouchInfo* ti) @@ -47,16 +49,21 @@ void GameScene::HandleClick(TouchInfo* ti) } if (!guiClick) + { _board->HandleClick(ti); - - if (_board->NeedRestart) - _board->Restart(); + if (_board->GameOver) + { + ((GameOverWidget*)_widgets[1])->Show(false); + _board->GameOver = false; + } + } } - if (_board->IsAllOpened()) + if (_board->CheckState()) { ((GameOverWidget*)_widgets[1])->Show(true); - _board->Restart(); + _board->NeedRestart = true; } + _textes[0]->Text = std::to_string(_board->MineCount - _board->FlagCount); break; } case 2: @@ -70,9 +77,13 @@ void GameScene::HandleClick(TouchInfo* ti) void GameScene::InitButtons() { + TextObject* textObject = new TextObject(60, 700, _resources->GetFont()); + textObject->Text = std::to_string(_board->MineCount - _board->FlagCount); + _textes.push_back(textObject); + Button* button = new Button(545, 665, 50, 50, "restartButton"); button->SetTexture(_resources->GetTexture(button->GetName())); - button->SetAction([this](){ this->GetBoard()->Restart(); }); + button->SetAction([this](){ this->GetBoard()->NeedRestart = true; }); _buttons.push_back(button); button = new Button(615, 665, 50, 50, "flagButton"); diff --git a/source/Scenes/GameScene.hpp b/source/Scenes/GameScene.hpp index 1d10774..b7c3cf0 100644 --- a/source/Scenes/GameScene.hpp +++ b/source/Scenes/GameScene.hpp @@ -17,6 +17,9 @@ class GameScene private: Board* _board; Resources* _resources; + TTF_Font* _font = nullptr; + std::vector _buttons; std::vector _widgets; + std::vector _textes; }; \ No newline at end of file diff --git a/source/Widgets/SettingsWidget.cpp b/source/Widgets/SettingsWidget.cpp index 1673749..74739a7 100644 --- a/source/Widgets/SettingsWidget.cpp +++ b/source/Widgets/SettingsWidget.cpp @@ -1,10 +1,7 @@ #include "SettingsWidget.hpp" -SettingsWidget::SettingsWidget(int x, int y, int w, int h, Resources* res) : Widget(x, y, w, h) +SettingsWidget::SettingsWidget(int x, int y, int w, int h, Resources* res, bool* restartFlag) : Widget(x, y, w, h) { - //Place window in center of screen - //*_widgetPosition = {}; - TextObject* textObject = new TextObject(x+w/2, y+45, res->GetFont()); textObject->Text = "PAUSE"; _textes.push_back(textObject); @@ -32,20 +29,22 @@ SettingsWidget::SettingsWidget(int x, int y, int w, int h, Resources* res) : Wid button = new Button(x+20, y+150, 50, 50, "minusButton"); button->AddTexture(res->GetTexture(button->GetName())); button->SetTexture(0); - button->SetAction([textObject]{ + button->SetAction([textObject, restartFlag]{ if (--Globals::Dificulty < 1) Globals::Dificulty = 1; textObject->Text = std::to_string(Globals::Dificulty); + *restartFlag = true; }); _buttons.push_back(button); button = new Button(x+w-70, y+150, 50, 50, "plusButton"); button->AddTexture(res->GetTexture(button->GetName())); button->SetTexture(0); - button->SetAction([textObject]{ + button->SetAction([textObject, restartFlag]{ if (++Globals::Dificulty > 4) Globals::Dificulty = 4; textObject->Text = std::to_string(Globals::Dificulty); + *restartFlag = true; }); _buttons.push_back(button); @@ -60,20 +59,22 @@ SettingsWidget::SettingsWidget(int x, int y, int w, int h, Resources* res) : Wid button = new Button(x+20, y+250, 50, 50, "minusButton"); button->AddTexture(res->GetTexture(button->GetName())); button->SetTexture(0); - button->SetAction([textObject]{ + button->SetAction([textObject, restartFlag]{ if (--Globals::BoardHeight < 1) Globals::BoardHeight = 1; textObject->Text = std::to_string(Globals::BoardHeight); + *restartFlag = true; }); _buttons.push_back(button); button = new Button(x+w-70, y+250, 50, 50, "plusButton"); button->AddTexture(res->GetTexture(button->GetName())); button->SetTexture(0); - button->SetAction([textObject]{ + button->SetAction([textObject, restartFlag]{ if (++Globals::BoardHeight > 40) Globals::BoardHeight = 40; textObject->Text = std::to_string(Globals::BoardHeight); + *restartFlag = true; }); _buttons.push_back(button); @@ -88,20 +89,22 @@ SettingsWidget::SettingsWidget(int x, int y, int w, int h, Resources* res) : Wid button = new Button(x+20, y+350, 50, 50, "minusButton"); button->AddTexture(res->GetTexture(button->GetName())); button->SetTexture(0); - button->SetAction([textObject]{ + button->SetAction([textObject, restartFlag]{ if (--Globals::BoardWidth < 1) Globals::BoardWidth = 1; textObject->Text = std::to_string(Globals::BoardWidth); + *restartFlag = true; }); _buttons.push_back(button); button = new Button(x+w-70, y+350, 50, 50, "plusButton"); button->AddTexture(res->GetTexture(button->GetName())); button->SetTexture(0); - button->SetAction([textObject]{ + button->SetAction([textObject, restartFlag]{ if (++Globals::BoardWidth > 40) Globals::BoardWidth = 40; textObject->Text = std::to_string(Globals::BoardWidth); + *restartFlag = true; }); _buttons.push_back(button); } \ No newline at end of file diff --git a/source/Widgets/SettingsWidget.hpp b/source/Widgets/SettingsWidget.hpp index d12549b..6409723 100644 --- a/source/Widgets/SettingsWidget.hpp +++ b/source/Widgets/SettingsWidget.hpp @@ -6,5 +6,5 @@ class SettingsWidget : public Widget { public: - SettingsWidget(int, int, int, int, Resources*); + SettingsWidget(int, int, int, int, Resources*, bool*); }; \ No newline at end of file From a06155629b04e76ef640acb1f2e0b69e8619c69b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D1=8F=D1=87=D0=B5=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A2?= =?UTF-8?q?=D0=B8=D1=82=D0=BE=D0=B2?= Date: Tue, 24 Jul 2018 01:28:33 +0300 Subject: [PATCH 3/6] Pressing already opened numbers with right count of flagged near cells will result in opening all near unflagged cells. --- source/GameObjects/Board.cpp | 2 +- source/GameObjects/Cell.cpp | 16 ++++++++++++++++ source/GameObjects/Cell.hpp | 1 + 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/source/GameObjects/Board.cpp b/source/GameObjects/Board.cpp index 8a7e82a..c792840 100644 --- a/source/GameObjects/Board.cpp +++ b/source/GameObjects/Board.cpp @@ -24,7 +24,7 @@ void Board::GenerateBoard() cell->AddTexture(_resources->GetTexture(Flagged, 0)); cell->SetTexture(0); cell->SetAction([this, cell]{ - if (!cell->SetState(Globals::IsFlag ? Flagged : Opened)) + if ((cell->GetState() == Opened && !cell->OpenNearCells()) || !cell->SetState(Globals::IsFlag ? Flagged : Opened)) { NeedRestart = true; GameOver = true; diff --git a/source/GameObjects/Cell.cpp b/source/GameObjects/Cell.cpp index 93ad2ac..ce5bc10 100644 --- a/source/GameObjects/Cell.cpp +++ b/source/GameObjects/Cell.cpp @@ -82,4 +82,20 @@ void Cell::Draw(int left, int top, SDL_Renderer* renderer) _rect->h = Globals::CellSize; } SpriteObject::Draw(renderer); +} + +bool Cell::OpenNearCells() +{ + int flagCount = 0; + for (int i = 0; i < _nearCells.size(); i++) + if (_nearCells[i]->GetState() == Flagged) + flagCount++; + + if (flagCount == NearMinesCount) + for (int i = 0; i < _nearCells.size(); i++) + if (_nearCells[i]->GetState() == Closed) + if (!_nearCells[i]->SetState(Opened)) + return false; + + return true; } \ No newline at end of file diff --git a/source/GameObjects/Cell.hpp b/source/GameObjects/Cell.hpp index 77059f4..decf0d7 100644 --- a/source/GameObjects/Cell.hpp +++ b/source/GameObjects/Cell.hpp @@ -13,6 +13,7 @@ class Cell : public SpriteObject bool SetState(CellState); void Reset(); void Draw(int, int, SDL_Renderer*); + bool OpenNearCells(); int NearMinesCount; private: From 39d93d415199f3fb8f3b26de4372a544edd8f853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D1=8F=D1=87=D0=B5=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A2?= =?UTF-8?q?=D0=B8=D1=82=D0=BE=D0=B2?= Date: Tue, 24 Jul 2018 01:30:31 +0300 Subject: [PATCH 4/6] README.md updated --- README.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/README.md b/README.md index 38dd664..d85f47d 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,4 @@ Feel free to report bugs and contribute! ## To-Do: -* Timer and scoreboard - -## Roadmap for next release: - -* Timer and scoreboard (000%). \ No newline at end of file +* Timer and scoreboard \ No newline at end of file From abf728c56960dab139bdf6349f4b04558d036e8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D1=8F=D1=87=D0=B5=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A2?= =?UTF-8?q?=D0=B8=D1=82=D0=BE=D0=B2?= Date: Tue, 24 Jul 2018 01:31:11 +0300 Subject: [PATCH 5/6] README.md update --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d85f47d..b091b21 100644 --- a/README.md +++ b/README.md @@ -18,4 +18,5 @@ Feel free to report bugs and contribute! ## To-Do: -* Timer and scoreboard \ No newline at end of file +* Timer and scoreboard +* Custom skins (HYPE!) \ No newline at end of file From 652c9fd67ca4966126177e3a9915a91ab753228b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D1=8F=D1=87=D0=B5=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A2?= =?UTF-8?q?=D0=B8=D1=82=D0=BE=D0=B2?= Date: Tue, 24 Jul 2018 01:33:30 +0300 Subject: [PATCH 6/6] Game version update --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3f29c49..f44f3bc 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ include $(DEVKITPRO)/libnx/switch_rules #--------------------------------------------------------------------------------- APP_TITLE := Minesweeper APP_AUTHOR := Rincew1nd -APP_VERSION := 1.1.0 +APP_VERSION := 2.0.0 ICON := icon.jpg TARGET := $(notdir $(CURDIR)) BUILD := build