diff --git a/Makefile b/Makefile index f3ba8a8..3f29c49 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ include $(DEVKITPRO)/libnx/switch_rules #--------------------------------------------------------------------------------- APP_TITLE := Minesweeper APP_AUTHOR := Rincew1nd -APP_VERSION := 1.0.3 +APP_VERSION := 1.1.0 ICON := icon.jpg TARGET := $(notdir $(CURDIR)) BUILD := build @@ -52,12 +52,12 @@ CFLAGS := -g -Wall -O2 -ffunction-sections \ CFLAGS += $(INCLUDE) -D__SWITCH__ -CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 +CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 -Wno-sign-compare ASFLAGS := -g $(ARCH) LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) -LIBS := -lSDL2_image -lSDL2_mixer -lSDL2 -lnx +LIBS := -lSDL2_image -lSDL2_mixer -lSDL2_ttf -lSDL2 -lfreetype -lpng -lz -lbz2 -lnx -lm #--------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level containing @@ -77,12 +77,23 @@ export OUTPUT := $(CURDIR)/$(TARGET) export TOPDIR := $(CURDIR) export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ - $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + $(foreach dir,$(SOURCES)/Engine,$(CURDIR)/$(dir)) \ + $(foreach dir,$(SOURCES)/GameObjects,$(CURDIR)/$(dir)) \ + $(foreach dir,$(SOURCES)/Scenes,$(CURDIR)/$(dir)) \ + $(foreach dir,$(SOURCES)/Widgets,$(CURDIR)/$(dir)) \ + $(foreach dir,$(SOURCES),$(foreach subdir,$(SOURCES)/$(dir),$(CURDIR)/$(dir)/$(subdir))) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +$(info VAR is $(VPATH)) export DEPSDIR := $(CURDIR)/$(BUILD) CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) -CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) \ + $(foreach dir,$(SOURCES)/Engine,$(notdir $(wildcard $(dir)/*.cpp))) \ + $(foreach dir,$(SOURCES)/GameObjects,$(notdir $(wildcard $(dir)/*.cpp))) \ + $(foreach dir,$(SOURCES)/Scenes,$(notdir $(wildcard $(dir)/*.cpp))) \ + $(foreach dir,$(SOURCES)/Widgets,$(notdir $(wildcard $(dir)/*.cpp))) SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) @@ -194,4 +205,4 @@ $(OFILES_SRC) : $(HFILES_BIN) #--------------------------------------------------------------------------------------- endif -#--------------------------------------------------------------------------------------- +#--------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/README.md b/README.md index 8d5e46b..68a9faa 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,9 @@ Feel free to report bugs and contribute! ## To-Do: -* Option screen with basic parametrization -* Touch screen gestures for zooming and moving field +* Touchscreen gestures for zooming and moving field * Timer and scoreboard + +## Roadmap for next release: + +* Timer and scoreboard (000%). \ No newline at end of file diff --git a/romfs/Pixeled.ttf b/romfs/Pixeled.ttf new file mode 100644 index 0000000..4730e44 Binary files /dev/null and b/romfs/Pixeled.ttf differ diff --git a/romfs/easyButton.bmp b/romfs/arrowLeftButton.bmp similarity index 51% rename from romfs/easyButton.bmp rename to romfs/arrowLeftButton.bmp index ef0e8e9..4474f16 100644 Binary files a/romfs/easyButton.bmp and b/romfs/arrowLeftButton.bmp differ diff --git a/romfs/hardButton.bmp b/romfs/arrowRightButton.bmp similarity index 51% rename from romfs/hardButton.bmp rename to romfs/arrowRightButton.bmp index 79705cf..0f9a90a 100644 Binary files a/romfs/hardButton.bmp and b/romfs/arrowRightButton.bmp differ diff --git a/romfs/escButton.bmp b/romfs/escButton.bmp new file mode 100644 index 0000000..f960a0b Binary files /dev/null and b/romfs/escButton.bmp differ diff --git a/romfs/mediumButton.bmp b/romfs/mediumButton.bmp deleted file mode 100644 index f9ab3f3..0000000 Binary files a/romfs/mediumButton.bmp and /dev/null differ diff --git a/romfs/minusButton.bmp b/romfs/minusButton.bmp new file mode 100644 index 0000000..081a88b Binary files /dev/null and b/romfs/minusButton.bmp differ diff --git a/romfs/plusButton.bmp b/romfs/plusButton.bmp new file mode 100644 index 0000000..30da234 Binary files /dev/null and b/romfs/plusButton.bmp differ diff --git a/romfs/settingsButton.bmp b/romfs/settingsButton.bmp new file mode 100644 index 0000000..175f251 Binary files /dev/null and b/romfs/settingsButton.bmp differ diff --git a/source/Board.cpp b/source/Board.cpp deleted file mode 100644 index 4ffd965..0000000 --- a/source/Board.cpp +++ /dev/null @@ -1,199 +0,0 @@ -#include "Board.hpp" -#include -#include - -Board::Board(int w, int h, Resources* resources) -{ - //1280x720 -> 1200x650 - GridLeft = 40; - GridTop = 10; - - _resources = resources; - - printf("Init buttons\n"); - InitButtons(); - - printf("Fill array of cells\n"); - for (int y = 0; y < Globals::BoardHeight; y++) - for (int x = 0; x < Globals::BoardWidth; x++) - _cells.push_back(new Cell(x, y, GridLeft, GridTop, _resources)); - - printf("Generate board\n"); - GenerateBoard(); -} - -void Board::GenerateBoard() -{ - printf("Random mines\n"); - srand(time(0)); - for (int mineCount = 0; mineCount <= Globals::BoardHeight * Globals::BoardWidth * Globals::Dificulty; mineCount++) - { - while(true) - { - int posX = rand() % Globals::BoardWidth; - int posY = rand() % Globals::BoardHeight; - - if (GetCell(posX, posY)->NearMinesCount != 9) - { - GetCell(posX, posY)->NearMinesCount = 9; - break; - } - } - } - - printf("Fill neighbors\n"); - for (int i = 0; i < Globals::BoardWidth; i++) - for (int j = 0; j < Globals::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++; - } - - printf("Set textures\n"); - for (int i = 0; i < Globals::BoardWidth * Globals::BoardHeight; i++) - _cells[i]->SetMineTexture(_resources->GetTexture(Opened, _cells[i]->NearMinesCount)); - - printf("Done!\n"); -} - -Cell* Board::GetCell(int x, int y) -{ - return _cells[x + y * Globals::BoardWidth]; -} - -bool Board::IsAllOpened() -{ - for (int i = 0; i < Globals::BoardWidth * Globals::BoardHeight; i++) - if (_cells[i]->GetState() != Opened || _cells[i]->GetState() != Flagged) - return false; - return true; -} - -bool Board::IsOnBoard(int x, int y) -{ - if (x >= 0 && x < Globals::BoardWidth) - if (y >= 0 && y < Globals::BoardHeight) - return true; - return false; -} - -void Board::OpenAll() -{ - for (int i = 0; i < Globals::BoardWidth * Globals::BoardHeight; i++) - _cells[i]->SetState(Opened); -} - -void Board::Restart() -{ - printf("Clear near cell count\n"); - for (int i = 0; i < Globals::BoardWidth * Globals::BoardHeight; i++) - _cells[i]->Reset(); - - GenerateBoard(); -} - -void Board::Draw(SDL_Renderer* renderer) -{ - for (int i = 0; i < Globals::BoardWidth * Globals::BoardHeight; i++) - _cells[i]->Draw(renderer); - for (unsigned long i = 0; i < _buttons.size(); i++) - _buttons[i]->Draw(renderer); -} - -void Board::HandleClick(touchPosition* point) -{ - int x = (point->px - GridLeft); - x = x / Globals::CellSize; - int y = (point->py - GridTop); - y = y / Globals::CellSize; - - if (IsOnBoard(x, y)) - if (!GetCell(x, y)->SetState(Globals::IsFlag ? Flagged : Opened)) - Restart(); - - for (int i = 0; i < _buttons.size(); i++) - if (point->px >= _buttons[i]->GetRect()->x && point->px <= _buttons[i]->GetRect()->x + _buttons[i]->GetRect()->w && - point->py >= _buttons[i]->GetRect()->y && point->py <= _buttons[i]->GetRect()->y + _buttons[i]->GetRect()->h && - _buttons[i]->IsVisible()) - if (_buttons[i]->Name == "restartButton") - { - Restart(); - break; - } - else if (_buttons[i]->Name == "flagOnButton") - { - Globals::IsFlag = false; - _buttons[1]->SetVisible(false); - _buttons[2]->SetVisible(true); - break; - } - else if (_buttons[i]->Name == "flagOffButton") - { - Globals::IsFlag = true; - _buttons[2]->SetVisible(false); - _buttons[1]->SetVisible(true); - break; - } - else if (_buttons[i]->Name == "hardButton") - { - printf("hard\n"); - Globals::Dificulty = 0.2f; - _buttons[i]->SetVisible(false); - _buttons[i+1]->SetVisible(true); - Restart(); - break; - } - else if (_buttons[i]->Name == "mediumButton") - { - printf("medium\n"); - Globals::Dificulty = 0.1f; - _buttons[i]->SetVisible(false); - _buttons[i+1]->SetVisible(true); - Restart(); - break; - } - else if (_buttons[i]->Name == "easyButton") - { - printf("easy\n"); - Globals::Dificulty = 0.3f; - _buttons[i]->SetVisible(false); - _buttons[i-2]->SetVisible(true); - Restart(); - break; - } -} - -void Board::InitButtons() -{ - Button* button = new Button(580, 665, 50, 50, "restartButton"); - button->SetTexture(_resources->GetTexture(button->Name)); - _buttons.push_back(button); - - button = new Button(650, 665, 50, 50, "flagOnButton"); - button->SetTexture(_resources->GetTexture(button->Name)); - button->SetVisible(false); - _buttons.push_back(button); - - button = new Button(650, 665, 50, 50, "flagOffButton"); - button->SetTexture(_resources->GetTexture(button->Name)); - _buttons.push_back(button); - - button = new Button(300, 665, 100, 50, "hardButton"); - button->SetTexture(_resources->GetTexture(button->Name)); - button->SetVisible(true); - _buttons.push_back(button); - - button = new Button(300, 665, 100, 50, "mediumButton"); - button->SetTexture(_resources->GetTexture(button->Name)); - button->SetVisible(false); - _buttons.push_back(button); - - button = new Button(300, 665, 100, 50, "easyButton"); - button->SetTexture(_resources->GetTexture(button->Name)); - button->SetVisible(false); - _buttons.push_back(button); -} \ No newline at end of file diff --git a/source/Button.cpp b/source/Button.cpp deleted file mode 100644 index 258a962..0000000 --- a/source/Button.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "Button.hpp" - -Button::Button(int x, int y, int w, int h, std::string name) - : DrawableObject(x, y, w, h) -{ - Name = name; -} \ No newline at end of file diff --git a/source/Button.hpp b/source/Button.hpp deleted file mode 100644 index 90c4b13..0000000 --- a/source/Button.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include -#include -#include "DrawableObject.hpp" - -class Button : public DrawableObject -{ - public: - Button(int, int, int, int, std::string); - std::string Name; -}; \ No newline at end of file diff --git a/source/Cell.hpp b/source/Cell.hpp deleted file mode 100644 index b6d4b17..0000000 --- a/source/Cell.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include "SDL2/SDL.h" -#include - -#include "Resources.hpp" -#include "DrawableObject.hpp" -#include "Defaults.hpp" - -class Cell : public DrawableObject -{ - public: - Cell(int, int, int, int, Resources*); - void AddNearCell(Cell*); - CellState GetState(); - bool SetState(CellState); - void SetMineTexture(SDL_Texture*); - int NearMinesCount; - void Reset(); - - int posi; - int posj; - private: - Cell(); - CellState _state; - std::vector _nearCells; - - SDL_Texture* _closedTexture; - SDL_Texture* _openedTexture; - SDL_Texture* _flaggedTexture; -}; \ No newline at end of file diff --git a/source/DrawableObject.cpp b/source/DrawableObject.cpp deleted file mode 100644 index 97356d6..0000000 --- a/source/DrawableObject.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "DrawableObject.hpp" - -DrawableObject::DrawableObject(int x, int y, int w, int h) -{ - _rect = new SDL_Rect(); - _rect->x = x; - _rect->y = y; - _rect->w = w; - _rect->h = h; - _isVisible = true; -} - -void DrawableObject::SetColor(int r, int g, int b, int a) -{ - _color = new SDL_Color(); - _color->r = r; - _color->g = g; - _color->b = b; - _color->a = a; -} - -void DrawableObject::SetColor(int r, int g, int b) -{ - SetColor(r, g, b, 255); -} - -void DrawableObject::Draw(SDL_Renderer *renderer) -{ - if (_isVisible) - { - //SDL_SetRenderDrawColor(renderer, _color->r, _color->g, _color->b, _color->a); - if (_texture != NULL) - SDL_RenderCopy(renderer, _texture, NULL, _rect); - else - SDL_RenderFillRect(renderer, _rect); - } -} - -void DrawableObject::SetTexture(SDL_Texture* texture) -{ - _texture = texture; -} - -void DrawableObject::SetVisible(bool visibility) -{ - _isVisible = visibility; -} - -bool DrawableObject::IsVisible() -{ - return _isVisible; -} - -SDL_Rect* DrawableObject::GetRect() { return _rect; } \ No newline at end of file diff --git a/source/Engine/Button.cpp b/source/Engine/Button.cpp new file mode 100644 index 0000000..f76f592 --- /dev/null +++ b/source/Engine/Button.cpp @@ -0,0 +1,12 @@ +#include "Button.hpp" + +Button::Button(int x, int y, int w, int h, std::string name, std::function func) : SpriteObject(x, y, w, h) +{ + _name = name; + SetAction(func); +} + +Button::Button(int x, int y, int w, int h, std::string name) : SpriteObject(x, y, w, h) +{ + _name = name; +} \ No newline at end of file diff --git a/source/Engine/Button.hpp b/source/Engine/Button.hpp new file mode 100644 index 0000000..8de1c4d --- /dev/null +++ b/source/Engine/Button.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include + +#include "SpriteObject.hpp" + +class Button : public SpriteObject +{ + public: + Button(int, int, int, int, std::string); + Button(int, int, int, int, std::string, std::function); + std::string GetName() { return _name; }; + + private: + std::string _name; +}; \ No newline at end of file diff --git a/source/Defaults.cpp b/source/Engine/Defaults.cpp similarity index 81% rename from source/Defaults.cpp rename to source/Engine/Defaults.cpp index d004302..04b242e 100644 --- a/source/Defaults.cpp +++ b/source/Engine/Defaults.cpp @@ -5,4 +5,4 @@ int Globals::BoardWidth = 24; int Globals::BoardHeight = 13; bool Globals::IsFlag = false; -float Globals::Dificulty = 0.3f; \ No newline at end of file +int Globals::Dificulty = 1; \ No newline at end of file diff --git a/source/Defaults.hpp b/source/Engine/Defaults.hpp similarity index 88% rename from source/Defaults.hpp rename to source/Engine/Defaults.hpp index b6483d8..7c4e7bd 100644 --- a/source/Defaults.hpp +++ b/source/Engine/Defaults.hpp @@ -16,7 +16,7 @@ class Globals static bool IsFlag; - static float Dificulty; + static int Dificulty; private: Globals() {} }; \ No newline at end of file diff --git a/source/Engine/GameObject.cpp b/source/Engine/GameObject.cpp new file mode 100644 index 0000000..5643c6c --- /dev/null +++ b/source/Engine/GameObject.cpp @@ -0,0 +1,27 @@ +#include "GameObject.hpp" + +GameObject::GameObject(int x, int y, int w, int h) +{ + _rect = new SDL_Rect(); + _rect->x = x; + _rect->y = y; + _rect->w = w; + _rect->h = h; +} + +void GameObject::Move(int dx, int dy) +{ + _rect->x += dx; + _rect->y += dy; +}; + +void GameObject::SetAction(std::function func) +{ + _onPress = func; +} + +bool GameObject::Hovered(touchPosition* pos) +{ + return pos->px >= _rect->x && pos->px <= _rect->x + _rect->w && + pos->py >= _rect->y && pos->py <= _rect->y + _rect->h; +} \ No newline at end of file diff --git a/source/Engine/GameObject.hpp b/source/Engine/GameObject.hpp new file mode 100644 index 0000000..d4cad7f --- /dev/null +++ b/source/Engine/GameObject.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include +#include "SDL2/SDL.h" +#include +#include + +class GameObject +{ + public: + GameObject(int, int, int, int); + void SetAction(std::function); + void Press() { if (_onPress != nullptr) _onPress(); }; + bool Hovered(touchPosition*); + void Move(int, int); + virtual ~GameObject() {}; + + protected: + SDL_Rect* _rect; + + private: + std::function _onPress; +}; \ No newline at end of file diff --git a/source/Engine/GraphicalObject.cpp b/source/Engine/GraphicalObject.cpp new file mode 100644 index 0000000..4b302bb --- /dev/null +++ b/source/Engine/GraphicalObject.cpp @@ -0,0 +1,46 @@ +#include "GraphicalObject.hpp" + +GraphicalObject::GraphicalObject(int x, int y, int w, int h) : GameObject(x, y, w, h) +{ + _color = new SDL_Color(); + _color->r = 0; + _color->g = 0; + _color->b = 0; + _color->a = 255; + _isVisible = true; +} + +void GraphicalObject::SetColor(int r, int g, int b, int a) +{ + _color = new SDL_Color(); + _color->r = r; + _color->g = g; + _color->b = b; + _color->a = a; +} + +void GraphicalObject::SetColor(int r, int g, int b) +{ + SetColor(r, g, b, 255); +} + +void GraphicalObject::Draw(SDL_Renderer *renderer) +{ + if (_isVisible) + { + SDL_SetRenderDrawColor(renderer, _color->r, _color->g, _color->b, _color->a); + SDL_RenderFillRect(renderer, _rect); + } +} + +void GraphicalObject::SetVisible(bool visibility) +{ + _isVisible = visibility; +} + +bool GraphicalObject::IsVisible() +{ + return _isVisible; +} + +SDL_Rect* GraphicalObject::GetRect() { return _rect; } \ No newline at end of file diff --git a/source/DrawableObject.hpp b/source/Engine/GraphicalObject.hpp similarity index 56% rename from source/DrawableObject.hpp rename to source/Engine/GraphicalObject.hpp index 0568837..f86ddf8 100644 --- a/source/DrawableObject.hpp +++ b/source/Engine/GraphicalObject.hpp @@ -1,22 +1,19 @@ #pragma once -#include -#include -class DrawableObject +#include "GameObject.hpp" + +class GraphicalObject : public GameObject { public: - DrawableObject(int, int, int, int); + GraphicalObject(int, int, int, int); void SetColor(int, int, int, int); void SetColor(int, int, int); void Draw(SDL_Renderer*); SDL_Rect* GetRect(); - void SetTexture(SDL_Texture*); void SetVisible(bool); bool IsVisible(); - private: - SDL_Rect* _rect; + protected: SDL_Color* _color; - SDL_Texture* _texture; bool _isVisible; }; \ No newline at end of file diff --git a/source/Input.cpp b/source/Engine/Input.cpp similarity index 100% rename from source/Input.cpp rename to source/Engine/Input.cpp diff --git a/source/Input.hpp b/source/Engine/Input.hpp similarity index 93% rename from source/Input.hpp rename to source/Engine/Input.hpp index 719a067..e9f2c9a 100644 --- a/source/Input.hpp +++ b/source/Engine/Input.hpp @@ -1,3 +1,5 @@ +#pragma once + #include class Input diff --git a/source/Resources.cpp b/source/Engine/Resources.cpp similarity index 61% rename from source/Resources.cpp rename to source/Engine/Resources.cpp index a8e725b..b22b8c6 100644 --- a/source/Resources.cpp +++ b/source/Engine/Resources.cpp @@ -20,9 +20,15 @@ void Resources::LoadROMFS(SDL_Renderer* renderer) _textures.insert(std::make_pair("flagOnButton", LoadTexture(renderer, "flagOnButton"))); _textures.insert(std::make_pair("flagOffButton", LoadTexture(renderer, "flagOffButton"))); _textures.insert(std::make_pair("restartButton", LoadTexture(renderer, "restartButton"))); - _textures.insert(std::make_pair("hardButton", LoadTexture(renderer, "hardButton"))); - _textures.insert(std::make_pair("mediumButton", LoadTexture(renderer, "mediumButton"))); - _textures.insert(std::make_pair("easyButton", LoadTexture(renderer, "easyButton"))); + _textures.insert(std::make_pair("settingsButton", LoadTexture(renderer, "settingsButton"))); + _textures.insert(std::make_pair("escButton", LoadTexture(renderer, "escButton"))); + _textures.insert(std::make_pair("arrowRightButton", LoadTexture(renderer, "arrowRightButton"))); + _textures.insert(std::make_pair("arrowLeftButton", LoadTexture(renderer, "arrowLeftButton"))); + _textures.insert(std::make_pair("minusButton", LoadTexture(renderer, "minusButton"))); + _textures.insert(std::make_pair("plusButton", LoadTexture(renderer, "plusButton"))); + + //Font + _font = TTF_OpenFont("romfs:/Pixeled.ttf", 28); } SDL_Texture* Resources::LoadTexture(SDL_Renderer* renderer, std::string image) @@ -31,7 +37,9 @@ SDL_Texture* Resources::LoadTexture(SDL_Renderer* renderer, std::string image) sprintf(imagePath, "romfs:/%s.bmp", image.c_str()); SDL_Surface* surface = SDL_LoadBMP(imagePath); - return SDL_CreateTextureFromSurface(renderer, surface); + SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface); + SDL_FreeSurface(surface); + return texture; } SDL_Texture* Resources::GetTexture(CellState state, int order) @@ -42,4 +50,14 @@ SDL_Texture* Resources::GetTexture(CellState state, int order) SDL_Texture *Resources::GetTexture(std::string textureName) { return _textures[textureName]; +} + +TTF_Font* Resources::GetFont() +{ + return _font; +} + +Resources::~Resources() +{ + //for (int i = 0; i < ) } \ No newline at end of file diff --git a/source/Resources.hpp b/source/Engine/Resources.hpp similarity index 76% rename from source/Resources.hpp rename to source/Engine/Resources.hpp index 173e362..d5202b1 100644 --- a/source/Resources.hpp +++ b/source/Engine/Resources.hpp @@ -1,6 +1,8 @@ #pragma once + #include #include +#include #include "Defaults.hpp" #include @@ -15,9 +17,12 @@ class Resources void LoadROMFS(SDL_Renderer*); SDL_Texture* LoadTexture(SDL_Renderer*, std::string); SDL_Texture* GetTexture(CellState, int); - SDL_Texture *GetTexture(std::string); + SDL_Texture* GetTexture(std::string); + TTF_Font* GetFont(); + ~Resources(); private: + TTF_Font* _font; std::map> _cellTextures; std::map _textures; }; \ No newline at end of file diff --git a/source/Engine/SpriteObject.cpp b/source/Engine/SpriteObject.cpp new file mode 100644 index 0000000..29c7c6a --- /dev/null +++ b/source/Engine/SpriteObject.cpp @@ -0,0 +1,44 @@ +#include "SpriteObject.hpp" + +SpriteObject::SpriteObject(int x, int y, int w, int h) : GraphicalObject(x, y, w, h) {} + +void SpriteObject::Draw(SDL_Renderer *renderer) +{ + if (_isVisible) + { + if (_texture != nullptr) + SDL_RenderCopy(renderer, _texture, NULL, _rect); + else + { + SDL_SetRenderDrawColor(renderer, _color->r, _color->g, _color->b, _color->a); + SDL_RenderFillRect(renderer, _rect); + } + } +} + +void SpriteObject::AddTexture(SDL_Texture* texture) +{ + _textures.push_back(texture); +} + +bool SpriteObject::AddTexture(SDL_Texture* texture, int pos) +{ + if (_textures.size() > pos) + _textures.at(pos) = texture; + else if (_textures.size() == pos) + _textures.push_back(texture); + else + return false; + return true; +} + +void SpriteObject::SetTexture(SDL_Texture* texture) +{ + _texture = texture; +} + +void SpriteObject::SetTexture(int pos) +{ + if (_textures.size() > pos) + SetTexture(_textures.at(pos)); +} \ No newline at end of file diff --git a/source/Engine/SpriteObject.hpp b/source/Engine/SpriteObject.hpp new file mode 100644 index 0000000..5caf1cb --- /dev/null +++ b/source/Engine/SpriteObject.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "GraphicalObject.hpp" + +class SpriteObject : public GraphicalObject +{ + public: + SpriteObject(int, int, int, int); + void Draw(SDL_Renderer*); + void SetTexture(SDL_Texture*); + void SetTexture(int); + void AddTexture(SDL_Texture*); + bool AddTexture(SDL_Texture*, int); + + protected: + SDL_Texture* _texture = nullptr;; + std::vector _textures; +}; \ No newline at end of file diff --git a/source/Engine/TextObject.cpp b/source/Engine/TextObject.cpp new file mode 100644 index 0000000..378d73d --- /dev/null +++ b/source/Engine/TextObject.cpp @@ -0,0 +1,43 @@ +#include "TextObject.hpp" + +TextObject::TextObject(int x, int y, TTF_Font* font) : GraphicalObject(0, 0, 0, 0) +{ + _centerX = x; + _centerY = y; + _font = font; +} + +void TextObject::SetFont(TTF_Font* font) +{ + _font = font; +} + +void TextObject::Draw(SDL_Renderer* renderer) +{ + if (IsVisible()) + { + if (_lastText != Text) + { + if (_texture != nullptr) SDL_DestroyTexture(_texture); + SDL_Surface* textSurface = TTF_RenderText_Solid(_font, Text.c_str(), *_color); + _texture = SDL_CreateTextureFromSurface(renderer, textSurface); + + //Get the size of the text and position texture on x;y center + int w, h; + TTF_SizeText(_font, Text.c_str(), &w, &h); + *_rect = {_centerX-w/2, _centerY-h/2, w, h}; + + SDL_FreeSurface(textSurface); + _lastText = Text; + } + + SDL_RenderCopy(renderer, _texture, NULL, _rect); + } +} + +void TextObject::Move(int dx, int dy) +{ + GraphicalObject::Move(dx, dy); + _centerX += dx; + _centerY += dy; +} \ No newline at end of file diff --git a/source/Engine/TextObject.hpp b/source/Engine/TextObject.hpp new file mode 100644 index 0000000..16f986e --- /dev/null +++ b/source/Engine/TextObject.hpp @@ -0,0 +1,19 @@ +#include "GraphicalObject.hpp" + +#include + +class TextObject : public GraphicalObject +{ + public: + TextObject(int, int, TTF_Font*); + void SetFont(TTF_Font*); + void Move(int, int); + void Draw(SDL_Renderer*); + std::string Text; + + protected: + int _centerX, _centerY; + std::string _lastText; + TTF_Font* _font = nullptr; + SDL_Texture* _texture = nullptr; +}; \ No newline at end of file diff --git a/source/Engine/Widget.cpp b/source/Engine/Widget.cpp new file mode 100644 index 0000000..0d1b978 --- /dev/null +++ b/source/Engine/Widget.cpp @@ -0,0 +1,63 @@ +#include "Widget.hpp" + +Widget::Widget(int x, int y, int w, int h) +{ + _widgetPosition = new SDL_Rect(); + _widgetPosition->x = x; + _widgetPosition->y = y; + _widgetPosition->w = w; + _widgetPosition->h = h; + + IsVisible = false; +} + +void Widget::SetColor(int r, int g, int b) +{ + SetColor(r, g, b, 255); +} + +void Widget::SetColor(int r, int g, int b, int a) +{ + _widgetBackgroundColor = new SDL_Color(); + _widgetBackgroundColor->r = r; + _widgetBackgroundColor->g = g; + _widgetBackgroundColor->b = b; + _widgetBackgroundColor->a = a; +} + +void Widget::SetTexture(SDL_Texture* texture) +{ + _widgetBackgroundTexture = texture; +} + +void Widget::SetFont(TTF_Font* font) +{ + _font = font; +} + +void Widget::Draw(SDL_Renderer* renderer) +{ + if (IsVisible) + { + if (_widgetBackgroundTexture != nullptr) + SDL_RenderCopy(renderer, _widgetBackgroundTexture, NULL, _widgetPosition); + else + { + SDL_SetRenderDrawColor(renderer, + _widgetBackgroundColor->r, _widgetBackgroundColor->g, _widgetBackgroundColor->b, _widgetBackgroundColor->a + ); + SDL_RenderFillRect(renderer, _widgetPosition); + } + for(int i = 0; i < _buttons.size(); i++) + _buttons[i]->Draw(renderer); + for(int i = 0; i < _textes.size(); i++) + _textes[i]->Draw(renderer); + } +} + +void Widget::HandleTouch(touchPosition* pos) +{ + for(int i = 0; i < _buttons.size(); i++) + if (_buttons[i]->Hovered(pos) && _buttons[i]->IsVisible()) + _buttons[i]->Press(); +} \ No newline at end of file diff --git a/source/Engine/Widget.hpp b/source/Engine/Widget.hpp new file mode 100644 index 0000000..48a940b --- /dev/null +++ b/source/Engine/Widget.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include "Button.hpp" +#include "TextObject.hpp" +#include + +class Widget +{ + public: + Widget(int, int, int, int); + void HandleTouch(touchPosition*); + void HandleJoystick() {}; + + bool IsVisible; + void SetColor(int, int, int, int); + void SetColor(int, int, int); + void SetTexture(SDL_Texture*); + void SetFont(TTF_Font*); + void Draw(SDL_Renderer*); + virtual ~Widget() {}; + + protected: + SDL_Rect* _widgetPosition; + SDL_Color* _widgetBackgroundColor; + SDL_Texture* _widgetBackgroundTexture = nullptr; + TTF_Font* _font = nullptr; + + std::vector _buttons; + std::vector _textes; +}; \ No newline at end of file diff --git a/source/Cell.cpp b/source/GameObjects/Cell.cpp similarity index 67% rename from source/Cell.cpp rename to source/GameObjects/Cell.cpp index a478149..1377699 100644 --- a/source/Cell.cpp +++ b/source/GameObjects/Cell.cpp @@ -1,18 +1,11 @@ #include "Cell.hpp" -#include "Defaults.hpp" -Cell::Cell(int posX, int posY, int dX, int dY, Resources* res) - : DrawableObject(posX * Globals::CellSize + dX, posY * Globals::CellSize + dY, Globals::CellSize, Globals::CellSize) +Cell::Cell(int posX, int posY, int dX, int dY) : SpriteObject(posX * Globals::CellSize + dX, posY * Globals::CellSize + dY, Globals::CellSize, Globals::CellSize) { - posi = posX; - posj = posY; - NearMinesCount = 0; _state = Closed; SetColor(0, 0, 0); - _closedTexture = res->GetTexture(Closed, 0); - _flaggedTexture = res->GetTexture(Flagged, 0); - SetTexture(_closedTexture); + SetTexture(0); } void Cell::AddNearCell(Cell* cell) @@ -31,13 +24,13 @@ bool Cell::SetState(CellState state) { case Closed: _state = Closed; - SetTexture(_closedTexture); + SetTexture(0); return true; case Opened: if (_state != Opened && _state != Flagged) { _state = Opened; - SetTexture(_openedTexture); + SetTexture(2); if (NearMinesCount == 9) return false; if (NearMinesCount == 0) @@ -51,11 +44,11 @@ bool Cell::SetState(CellState state) { case Closed: _state = Flagged; - SetTexture(_flaggedTexture); + SetTexture(1); break; case Flagged: _state = Closed; - SetTexture(_closedTexture); + SetTexture(0); break; default: break; @@ -67,15 +60,10 @@ bool Cell::SetState(CellState state) } } -void Cell::SetMineTexture(SDL_Texture* texture) -{ - _openedTexture = texture; -} - void Cell::Reset() { NearMinesCount = 0; _state = Closed; _nearCells.clear(); - SetTexture(_closedTexture); + SetTexture(0); } \ No newline at end of file diff --git a/source/GameObjects/Cell.hpp b/source/GameObjects/Cell.hpp new file mode 100644 index 0000000..be96960 --- /dev/null +++ b/source/GameObjects/Cell.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include "../Engine/Resources.hpp" +#include "../Engine/SpriteObject.hpp" +#include "../Engine/Defaults.hpp" + +class Cell : public SpriteObject +{ + public: + Cell(int, int, int, int); + void AddNearCell(Cell*); + CellState GetState(); + bool SetState(CellState); + void Reset(); + int NearMinesCount; + private: + CellState _state; + std::vector _nearCells; +}; \ No newline at end of file diff --git a/source/Minesweeper.cpp b/source/Minesweeper.cpp index 60b88ff..8d32bfa 100644 --- a/source/Minesweeper.cpp +++ b/source/Minesweeper.cpp @@ -2,16 +2,14 @@ Minesweeper::Minesweeper() { - InitSDL(); - InitGame(); + if (InitSDL()) + InitGame(); } void Minesweeper::InitGame() { - printf("Init input\n"); _input = new Input(); - printf("Init ROMFS\n"); Result rc = romfsInit(); if (R_FAILED(rc)) printf("ERROR: romfsInit: %08X\n", rc); @@ -21,17 +19,15 @@ void Minesweeper::InitGame() _resources->LoadROMFS(_renderer); } - printf("Init board\n"); - _board = new Board(1280, 720, _resources); + _board = new BoardScene(1280, 720, _resources); } -void Minesweeper::InitSDL() +bool Minesweeper::InitSDL() { - printf("Initialize SDL"); if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) { printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError()); - return; + return false; } atexit(SDL_Quit); @@ -40,12 +36,21 @@ void Minesweeper::InitSDL() if (_window == NULL) { printf("Window could not be created! SDL_Error: %s\n", SDL_GetError()); - return; + return false; + } + + //Initialize SDL_ttf + if( TTF_Init() == -1 ) + { + printf( "SDL_ttf could not initialize! SDL_ttf Error: %s\n", TTF_GetError() ); + return false; } SDL_SetRenderDrawColor(_renderer, 208, 176, 48, 255); SDL_RenderClear(_renderer); SDL_RenderPresent(_renderer); + + return true; } void Minesweeper::Start() @@ -79,9 +84,11 @@ void Minesweeper::Start() void Minesweeper::DeinitSDL() { - printf("Destroy window\n"); + SDL_DestroyRenderer(_renderer); SDL_DestroyWindow(_window); + _renderer = NULL; + _window = NULL; - printf("Quit SDL subsystems\n"); + TTF_Quit(); SDL_Quit(); } \ No newline at end of file diff --git a/source/Minesweeper.hpp b/source/Minesweeper.hpp index 081a868..49e2994 100644 --- a/source/Minesweeper.hpp +++ b/source/Minesweeper.hpp @@ -1,10 +1,12 @@ #pragma once + #include #include +#include -#include "Defaults.hpp" -#include "Input.hpp" -#include "Board.hpp" +#include "Engine/Defaults.hpp" +#include "Engine/Input.hpp" +#include "Scenes/BoardScene.hpp" class Minesweeper { @@ -13,7 +15,7 @@ class Minesweeper void Start(); private: - void InitSDL(); + bool InitSDL(); void InitGame(); void DeinitSDL(); @@ -21,6 +23,6 @@ class Minesweeper SDL_Renderer *_renderer; Input* _input; - Board* _board; + BoardScene* _board; Resources* _resources; }; \ No newline at end of file diff --git a/source/Scenes/BoardScene.cpp b/source/Scenes/BoardScene.cpp new file mode 100644 index 0000000..9615ac2 --- /dev/null +++ b/source/Scenes/BoardScene.cpp @@ -0,0 +1,170 @@ +#include "BoardScene.hpp" +#include +#include + +BoardScene::BoardScene(int w, int h, Resources* resources) +{ + //1280x720 -> 1200x650 + GridLeft = 40; + GridTop = 10; + + _resources = resources; + + _widgets.push_back((Widget*)new SettingsWidget(490, 200, 450, 350, resources)); + _widgets[0]->SetColor(152, 120, 24); + _widgets.push_back((Widget*)new GameOverWidget(490, 250, 300, 100, resources)); + _widgets[1]->SetColor(152, 120, 24); + + InitButtons(); + + for (int y = 0; y < Globals::BoardHeight; y++) + for (int x = 0; x < Globals::BoardWidth; x++) + { + 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)) + Restart(); + }); + _cells.push_back(cell); + } + + GenerateBoard(); +} + +void BoardScene::GenerateBoard() +{ + srand(time(0)); + for (int mineCount = 0; mineCount <= Globals::BoardHeight * Globals::BoardWidth * 0.1f * Globals::Dificulty; mineCount++) + { + while(true) + { + int posX = rand() % Globals::BoardWidth; + int posY = rand() % Globals::BoardHeight; + + if (GetCell(posX, posY)->NearMinesCount != 9) + { + GetCell(posX, posY)->NearMinesCount = 9; + break; + } + } + } + + for (int i = 0; i < Globals::BoardWidth; i++) + for (int j = 0; j < Globals::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++) + _cells[i]->AddTexture(_resources->GetTexture(Opened, _cells[i]->NearMinesCount), 2); +} + +Cell* BoardScene::GetCell(int x, int y) +{ + return _cells[x + y * Globals::BoardWidth]; +} + +bool BoardScene::IsAllOpened() +{ + for (int i = 0; i < Globals::BoardWidth * Globals::BoardHeight; i++) + if (_cells[i]->NearMinesCount != 9 && _cells[i]->GetState() != Opened) + return false; + return true; +} + +bool BoardScene::IsOnBoard(int x, int y) +{ + if (x >= 0 && x < Globals::BoardWidth) + if (y >= 0 && y < Globals::BoardHeight) + return true; + return false; +} + +void BoardScene::OpenAll() +{ + for (int i = 0; i < Globals::BoardWidth * Globals::BoardHeight; i++) + _cells[i]->SetState(Opened); +} + +void BoardScene::Restart() +{ + for (int i = 0; i < Globals::BoardWidth * Globals::BoardHeight; i++) + _cells[i]->Reset(); + + GenerateBoard(); +} + +void BoardScene::Draw(SDL_Renderer* renderer) +{ + for (int i = 0; i < Globals::BoardWidth * Globals::BoardHeight; i++) + _cells[i]->Draw(renderer); + for (int i = 0; i < _buttons.size(); i++) + _buttons[i]->Draw(renderer); + for (int i = 0; i < _widgets.size(); i++) + _widgets[i]->Draw(renderer); +} + +void BoardScene::HandleClick(touchPosition* point) +{ + int widgetVisible = false; + + for (int i = 0; i < _widgets.size(); i++) + if (_widgets[i]->IsVisible) + { + _widgets[i]->HandleTouch(point); + widgetVisible = true; + } + + if (!widgetVisible) + { + for (int i = 0; i < _cells.size(); i++) + if (_cells[i]->Hovered(point) && _cells[i]->IsVisible()) + { + if (_cells[i]->NearMinesCount == 9 && !Globals::IsFlag) + ((GameOverWidget*)_widgets[1])->Show(false); + _cells[i]->Press(); + } + + for (int i = 0; i < _buttons.size(); i++) + if (_buttons[i]->Hovered(point) && _buttons[i]->IsVisible()) + _buttons[i]->Press(); + } + + if (IsAllOpened()) + { + ((GameOverWidget*)_widgets[1])->Show(true); + Restart(); + } +} + +void BoardScene::InitButtons() +{ + Button* button = new Button(545, 665, 50, 50, "restartButton"); + button->SetTexture(_resources->GetTexture(button->GetName())); + button->SetAction([this](){ Restart(); }); + _buttons.push_back(button); + + button = new Button(615, 665, 50, 50, "flagButton"); + button->AddTexture(_resources->GetTexture("flagOnButton")); + button->AddTexture(_resources->GetTexture("flagOffButton")); + button->SetTexture(1); + button->SetAction([button]{ + Globals::IsFlag = !Globals::IsFlag; + button->SetTexture(Globals::IsFlag ? 0 : 1); + }); + _buttons.push_back(button); + + button = new Button(685, 665, 50, 50, "settingsButton"); + button->SetTexture(_resources->GetTexture(button->GetName())); + Widget* settings = _widgets[0]; + button->SetAction([settings] { settings->IsVisible = true; }); + _buttons.push_back(button); +} \ No newline at end of file diff --git a/source/Board.hpp b/source/Scenes/BoardScene.hpp similarity index 64% rename from source/Board.hpp rename to source/Scenes/BoardScene.hpp index 0502686..4a5f0e9 100644 --- a/source/Board.hpp +++ b/source/Scenes/BoardScene.hpp @@ -1,19 +1,23 @@ #pragma once + #include #include #include #include #include -#include "Cell.hpp" -#include "Defaults.hpp" -#include "Resources.hpp" -#include "Button.hpp" +#include "../GameObjects/Cell.hpp" + +#include "../Engine/Defaults.hpp" +#include "../Engine/Resources.hpp" +#include "../Engine/Button.hpp" +#include "../Widgets/SettingsWidget.hpp" +#include "../Widgets/GameOverWidget.hpp" -class Board +class BoardScene { public: - Board(int, int, Resources*); + BoardScene(int, int, Resources*); void InitButtons(); Cell* GetCell(int, int); bool IsAllOpened(); @@ -26,9 +30,10 @@ class Board private: void GenerateBoard(); - Resources *_resources; int GridLeft; int GridTop; + Resources *_resources; std::vector _cells; std::vector _buttons; + std::vector _widgets; }; \ No newline at end of file diff --git a/source/Widgets/GameOverWidget.cpp b/source/Widgets/GameOverWidget.cpp new file mode 100644 index 0000000..dfbab82 --- /dev/null +++ b/source/Widgets/GameOverWidget.cpp @@ -0,0 +1,21 @@ +#include "GameOverWidget.hpp" + +GameOverWidget::GameOverWidget(int x, int y, int w, int h, Resources* res) : Widget(x, y, w, h) +{ + //Place window in center of screen + //*_widgetPosition = {}; + + TextObject* textObject = new TextObject(x+w/2, y+50, res->GetFont()); + _textes.push_back(textObject); + + Button* button = new Button(x, y, w, h, "escButton"); + button->SetColor(152, 120, 24); + button->SetAction([this]{ this->IsVisible = false; }); + _buttons.push_back(button); +} + +void GameOverWidget::Show(bool win) +{ + IsVisible = true; + _textes[0]->Text = win ? "YOU WON" : "GAME OVER"; +} \ No newline at end of file diff --git a/source/Widgets/GameOverWidget.hpp b/source/Widgets/GameOverWidget.hpp new file mode 100644 index 0000000..f871fca --- /dev/null +++ b/source/Widgets/GameOverWidget.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include "../Engine/Widget.hpp" +#include "../Engine/Resources.hpp" + +class GameOverWidget : public Widget +{ + public: + GameOverWidget(int, int, int, int, Resources*); + void Show(bool); +}; \ No newline at end of file diff --git a/source/Widgets/SettingsWidget.cpp b/source/Widgets/SettingsWidget.cpp new file mode 100644 index 0000000..fb1bb4e --- /dev/null +++ b/source/Widgets/SettingsWidget.cpp @@ -0,0 +1,49 @@ +#include "SettingsWidget.hpp" + +SettingsWidget::SettingsWidget(int x, int y, int w, int h, Resources* res) : 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); + 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->Text = "Press + to"; + _textes.push_back(textObject); + textObject = new TextObject(x+w/2, y+305, 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); + + button = new Button(x+20, y+150, 50, 50, "minusButton"); + button->AddTexture(res->GetTexture(button->GetName())); + button->SetTexture(0); + button->SetAction([textObject]{ + if (--Globals::Dificulty < 1) + Globals::Dificulty = 1; + textObject->Text = std::to_string(Globals::Dificulty); + }); + _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]{ + if (++Globals::Dificulty > 4) + Globals::Dificulty = 4; + textObject->Text = std::to_string(Globals::Dificulty); + }); + _buttons.push_back(button); +} \ No newline at end of file diff --git a/source/Widgets/SettingsWidget.hpp b/source/Widgets/SettingsWidget.hpp new file mode 100644 index 0000000..d12549b --- /dev/null +++ b/source/Widgets/SettingsWidget.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include "../Engine/Widget.hpp" +#include "../Engine/Resources.hpp" + +class SettingsWidget : public Widget +{ + public: + SettingsWidget(int, int, int, int, Resources*); +}; \ No newline at end of file