diff --git a/Bin/VC10/VC10.vcxproj b/Bin/VC10/VC10.vcxproj index 3336f69..6107e44 100644 --- a/Bin/VC10/VC10.vcxproj +++ b/Bin/VC10/VC10.vcxproj @@ -100,6 +100,7 @@ <ClInclude Include="..\..\src\Level\MapTile.h" /> <ClInclude Include="..\..\src\Level\Tileset.h" /> <ClInclude Include="..\..\src\Main\Game.h" /> + <ClInclude Include="..\..\src\Main\TitleScreen.h" /> <ClInclude Include="..\..\src\Math\FPS.h" /> <ClInclude Include="..\..\src\Math\MathBox.h" /> <ClInclude Include="..\..\src\Math\Rect.h" /> @@ -128,6 +129,8 @@ <ClInclude Include="..\..\src\TMXParser\TmxTile.h" /> <ClInclude Include="..\..\src\TMXParser\TmxTileset.h" /> <ClInclude Include="..\..\src\TMXParser\TmxUtil.h" /> + <ClInclude Include="..\..\src\UI\Button.h" /> + <ClInclude Include="..\..\src\UI\Menu.h" /> </ItemGroup> <ItemGroup> <ClCompile Include="..\..\src\Actor\Actor.cpp" /> @@ -145,6 +148,7 @@ <ClCompile Include="..\..\src\Level\Tileset.cpp" /> <ClCompile Include="..\..\src\Main\Game.cpp" /> <ClCompile Include="..\..\src\Main\main.cpp" /> + <ClCompile Include="..\..\src\Main\TitleScreen.cpp" /> <ClCompile Include="..\..\src\Math\FPS.cpp" /> <ClCompile Include="..\..\src\Math\Timer.cpp" /> <ClCompile Include="..\..\src\Math\Vec2.cpp" /> @@ -167,6 +171,8 @@ <ClCompile Include="..\..\src\TMXParser\TmxTile.cpp" /> <ClCompile Include="..\..\src\TMXParser\TmxTileset.cpp" /> <ClCompile Include="..\..\src\TMXParser\TmxUtil.cpp" /> + <ClCompile Include="..\..\src\UI\Button.cpp" /> + <ClCompile Include="..\..\src\UI\Menu.cpp" /> </ItemGroup> <ItemGroup> <ProjectReference Include="tinyxml.vcxproj"> diff --git a/Bin/VC10/VC10.vcxproj.filters b/Bin/VC10/VC10.vcxproj.filters index 52683a1..8424bb1 100644 --- a/Bin/VC10/VC10.vcxproj.filters +++ b/Bin/VC10/VC10.vcxproj.filters @@ -46,6 +46,9 @@ <Filter Include="Animation"> <UniqueIdentifier>{2826112d-5f07-4ee2-b4b4-2be9289c6811}</UniqueIdentifier> </Filter> + <Filter Include="UI"> + <UniqueIdentifier>{da9ad984-368f-4f6f-8f68-648733ae3a44}</UniqueIdentifier> + </Filter> </ItemGroup> <ItemGroup> <ClInclude Include="..\..\src\Main\Game.h"> @@ -183,6 +186,15 @@ <ClInclude Include="..\..\src\Animation\AnimationSequence.h"> <Filter>Animation</Filter> </ClInclude> + <ClInclude Include="..\..\src\UI\Button.h"> + <Filter>UI</Filter> + </ClInclude> + <ClInclude Include="..\..\src\Main\TitleScreen.h"> + <Filter>Main</Filter> + </ClInclude> + <ClInclude Include="..\..\src\UI\Menu.h"> + <Filter>UI</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="..\..\src\Main\main.cpp"> @@ -296,5 +308,14 @@ <ClCompile Include="..\..\src\Animation\AnimatingSprite.cpp"> <Filter>Animation</Filter> </ClCompile> + <ClCompile Include="..\..\src\UI\Button.cpp"> + <Filter>UI</Filter> + </ClCompile> + <ClCompile Include="..\..\src\Main\TitleScreen.cpp"> + <Filter>Main</Filter> + </ClCompile> + <ClCompile Include="..\..\src\UI\Menu.cpp"> + <Filter>UI</Filter> + </ClCompile> </ItemGroup> </Project> \ No newline at end of file diff --git a/Data/Img/Magica/WaterElement.png b/Data/Img/Magica/WaterElement.png new file mode 100644 index 0000000..423caf2 Binary files /dev/null and b/Data/Img/Magica/WaterElement.png differ diff --git a/LibDQt/LibDQt.pro b/LibDQt/LibDQt.pro index 522cf79..913dd74 100644 --- a/LibDQt/LibDQt.pro +++ b/LibDQt/LibDQt.pro @@ -8,7 +8,7 @@ LIBS += -lGL \ -ltinyxml \ -lSDL_mixer \ -lSDL_ttf -win32: { +win32: { LIBS -= -lGL \ -lGLU LIBS += -lkernel32 \ @@ -63,6 +63,9 @@ HEADERS += ../src/Actor/Player.h \ ../src/System/String.h \ ../src/Font/Font.h \ ../src/Animation/AnimatingSprite.h \ + ../src/UI/Menu.h \ + ../src/UI/Button.h \ + ../src/Main/TitleScreen.h SOURCES += ../src/Actor/Player.cpp \ ../src/Collision/AABB.cpp \ ../src/Global/Globals.cpp \ @@ -100,4 +103,6 @@ SOURCES += ../src/Actor/Player.cpp \ ../src/System/String.cpp \ ../src/Font/Font.cpp \ ../src/Animation/AnimatingSprite.cpp \ -OTHER_FILES += + ../src/UI/Menu.cpp \ + ../src/UI/Button.cpp \ + ../src/Main/TitleScreen.cpp diff --git a/src/Font/Font.cpp b/src/Font/Font.cpp index f06b2f6..247ddd5 100644 --- a/src/Font/Font.cpp +++ b/src/Font/Font.cpp @@ -19,8 +19,8 @@ Font::~Font(void) { } } -bool Font::Load(const std::string& filename) { - TTF_Font* font = TTF_OpenFont(filename.c_str(), 16); +bool Font::Load(const std::string& filename, int size) { + TTF_Font* font = TTF_OpenFont(filename.c_str(), size); if(!font) { Debug::logger->message("Error loading %s: %s", filename.c_str(), TTF_GetError()); return false; @@ -94,7 +94,7 @@ bool Font::Load(const std::string& filename) { return true; } -void Font::DrawText(int xOffset, int yOffset, const char* text) { +void Font::RenderText(int xOffset, int yOffset, const char* text) { glEnable(GL_TEXTURE_2D); BindTexture(_texture); @@ -159,3 +159,24 @@ void Font::DrawText(int xOffset, int yOffset, const char* text) { glColor4f(1.0f, 1.0f, 1.0f, 1.0f); } + +void Font::TextSize(const char* text, int& width, int& height) { + width = 0; + height = _lineSkip; + + int textLength = strlen(text); + for(int i = 0; i < textLength; i++) { + char c = text[i]; + if(c == '\n') { + height += _lineSkip; + continue; + } else if(c == ' ') { + width += _spaceWidth; + continue; + } else if(c == '\t') { + width += _tabWidth; + continue; + } + width += _characters[(int)c].advance; + } +} diff --git a/src/Font/Font.h b/src/Font/Font.h index 28356f6..5c85738 100644 --- a/src/Font/Font.h +++ b/src/Font/Font.h @@ -16,16 +16,15 @@ struct FontChar { int advance; }; -class Font : public Resource { - template<class T> friend class ResourceManager; - +class Font { public: Font(void); ~Font(void); - bool Load(const std::string& filename); + bool Load(const std::string& filename, int size); - void DrawText(int xOffset, int yOffset, const char* text); + void RenderText(int xOffset, int yOffset, const char* text); + void TextSize(const char* text, int& width, int& height); int GetLineSkip() const { return _lineSkip; } float* GetColor() { return _color; } diff --git a/src/Main/Game.cpp b/src/Main/Game.cpp index 36a032e..c967953 100644 --- a/src/Main/Game.cpp +++ b/src/Main/Game.cpp @@ -12,8 +12,10 @@ #include "../System/Debug.h" #include "../Sprite/Sprite.h" #include "../Texture/Texture.h" + #include "../Level/Level.h" #include "Game.h" +#include "TitleScreen.h" Game::Game(void) { _level = new Level(); @@ -23,8 +25,11 @@ Game::Game(void) { _NPC->SetXY(30.0f, 30.0f); _testFont = new Font(); - _testFont->Load("../Data/Font/Fairydust.ttf"); - _testFont->SetColor(0.0f, 1.0f, 1.0f, 1.0f); + + _titleScreen = new TitleScreen(); + _inTitleScreen = true; + + _running = true; } Game::~Game(void) { @@ -40,12 +45,6 @@ bool Game::Init(void) { glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.1f); - _level->Load("../Data/Map/Ugly.tmx"); - _level->PlayBGM(); - - _player->LoadSprites("Player"); - _NPC->LoadSprites("Player"); - // Return success. return true; } @@ -56,7 +55,84 @@ void Game::Prepare(float dt) { void Game::Render(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + if(_inTitleScreen) { + RenderTitle(); + } else { + RenderGame(); + } +} +void Game::Shutdown(void) { + Debug::logger->message("\n ----- Cleaning Engine -----"); + delete _testFont; + delete _NPC; + delete _player; + delete _level; + delete _titleScreen; +} + +void Game::ProcessEvents(float dt) { + if(_inTitleScreen) { + UpdateTitle(dt); + } else { + UpdateGame(dt); + } +} + +void Game::OnResize(int width, int height) { + glViewport(0, 0, width, height); + + windowWidth = width; + windowHeight = height; + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0.0, (GLdouble)windowWidth, (GLdouble)windowHeight, 0.0, 0.0, 1.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} + +void Game::UpdateTitle(float dt) { + _titleScreen->Update(dt); + + if(!_titleScreen->IsAlive()) { + switch(_titleScreen->GetResult()) { + case TitleScreen::NEW_GAME: + NewGame(); + break; + + case TitleScreen::LOAD_GAME: + LoadGame(); + break; + + case TitleScreen::QUIT: + Quit(); + break; + } + } +} + +void Game::UpdateGame(float dt) { + _player->Update(dt); + _NPC->Update(dt); + _level->Update(dt); +} + +void Game::RenderTitle(void) { + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glDisable(GL_DEPTH_TEST); + glDisable(GL_ALPHA_TEST); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + _titleScreen->Render(); +} + +void Game::RenderGame(void) { glMatrixMode(GL_MODELVIEW); glLoadIdentity(); @@ -80,35 +156,28 @@ void Game::Render(void) { _level->Draw(xOffset, yOffset); _player->Render(); _NPC->Render(); - _testFont->DrawText( + _testFont->RenderText( _player->GetX() - 5, _player->GetY() - _testFont->GetLineSkip() - 2, "Miss D"); } -void Game::Shutdown(void) { - Debug::logger->message("\n ----- Cleaning Engine -----"); - delete _testFont; - delete _NPC; - delete _player; - delete _level; +void Game::NewGame(void) { + _level->Load("../Data/Map/Ugly.tmx"); + _level->PlayBGM(); + + _player->LoadSprites("Player"); + _NPC->LoadSprites("Player"); + + _testFont->Load("../Data/Font/Fairydust.ttf", 16); + _testFont->SetColor(0.0f, 1.0f, 1.0f, 1.0f); + + _inTitleScreen = false; } -void Game::ProcessEvents(float dt) { - _player->Update(dt); - _NPC->Update(dt); +void Game::LoadGame(void) { } -void Game::OnResize(int width, int height) { - glViewport(0, 0, width, height); - - windowWidth = width; - windowHeight = height; - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0.0, (GLdouble)windowWidth, (GLdouble)windowHeight, 0.0, 0.0, 1.0); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); +void Game::Quit(void) { + SetRunning(false); } diff --git a/src/Main/Game.h b/src/Main/Game.h index d80066b..ca4f984 100644 --- a/src/Main/Game.h +++ b/src/Main/Game.h @@ -6,6 +6,8 @@ class Sprite; class Level; +class Button; +class TitleScreen; class Game { public: @@ -21,9 +23,26 @@ public: void OnResize(int width, int height); + bool IsRunning() { return _running; } + void SetRunning(bool running) { _running = running; } + private: + void UpdateTitle(float dt); + void UpdateGame(float dt); + void RenderTitle(void); + void RenderGame(void); + + void NewGame(void); + void LoadGame(void); + void Quit(void); + Font* _testFont; Player* _player; NPC* _NPC; Level* _level; + + TitleScreen* _titleScreen; + bool _inTitleScreen; + + bool _running; }; diff --git a/src/Main/TitleScreen.cpp b/src/Main/TitleScreen.cpp new file mode 100644 index 0000000..4825bfc --- /dev/null +++ b/src/Main/TitleScreen.cpp @@ -0,0 +1,61 @@ +#include "TitleScreen.h" +#include "../Font/Font.h" +#include "../UI/Button.h" +#include "../Global/Globals.h" + +TitleScreen::TitleScreen(void) { + _alive = true; + _result = TitleScreen::QUIT; + + _font = new Font(); + _font->Load("../Data/Font/Fairydust.ttf", 24); + + Button* newGameButton = new Button(); + Button* loadGameButton = new Button(); + Button* quitButton = new Button(); + + newGameButton->SetFont(_font); + loadGameButton->SetFont(_font); + quitButton->SetFont(_font); + + newGameButton->SetText("New Game"); + loadGameButton->SetText("Load Game"); + quitButton->SetText("Quit"); + + _menu.AddButton(newGameButton); + _menu.AddButton(loadGameButton); + _menu.AddButton(quitButton); + _menu.AlignButtons(Menu::ALIGN_VERTICALLY); +} + +TitleScreen::~TitleScreen(void) { + if(_font) { + delete _font; + _font = NULL; + } +} + +void TitleScreen::Update(float dt) { + _menu.Update(); + switch(_menu.GetTriggeredButton()) { + case 0: + _alive = false; + _result = TitleScreen::NEW_GAME; + break; + + case 1: + _alive = false; + _result = TitleScreen::LOAD_GAME; + break; + + case 2: + _alive = false; + _result = TitleScreen::QUIT; + break; + } +} + +void TitleScreen::Render(void) { + _menu.SetXY(32, windowHeight - 128); + _menu.Render(); +} diff --git a/src/Main/TitleScreen.h b/src/Main/TitleScreen.h new file mode 100644 index 0000000..7555bc9 --- /dev/null +++ b/src/Main/TitleScreen.h @@ -0,0 +1,30 @@ +#pragma once + +#include "../UI/Menu.h" + +class Font; + +class TitleScreen { +public: + enum { + NEW_GAME, + LOAD_GAME, + QUIT + }; + + TitleScreen(void); + ~TitleScreen(void); + + void Update(float dt); + void Render(void); + + bool IsAlive(void) { return _alive; } + int GetResult(void) { return _result; } + +private: + bool _alive; + int _result; + + Font* _font; + Menu _menu; +}; \ No newline at end of file diff --git a/src/Main/main.cpp b/src/Main/main.cpp index 19ac5d3..3a01324 100644 --- a/src/Main/main.cpp +++ b/src/Main/main.cpp @@ -99,12 +99,11 @@ int main(int argc, char** argv) { // screws up for me. -- Allanis. game.OnResize(windowWidth, windowHeight); - bool isRunning = true; - while(isRunning) { + while(game.IsRunning()) { while(SDL_PollEvent(&event)) { if((event.type == SDL_QUIT) || KeyStillDown(SDLK_ESCAPE)) { - isRunning = false; + game.SetRunning(false); break; } if(event.type == SDL_VIDEORESIZE) { diff --git a/src/UI/Button.cpp b/src/UI/Button.cpp new file mode 100644 index 0000000..c1aedfa --- /dev/null +++ b/src/UI/Button.cpp @@ -0,0 +1,59 @@ +#include "Button.h" +#include "../Font/Font.h" +#include "../IO/Input.h" + +Button::Button(void) { + _text = ""; + _font = NULL; + _highlighted = false; + _selected = false; + _triggered = false; + x = 0; + y = 0; + w = 0; + h = 0; +} + +void Button::Update(void) { + _triggered = false; + + int mouseX = ::GetX(); + int mouseY = ::GetY(); + + if((mouseX >= x) && (mouseX < (x + w)) && + (mouseY >= y) && (mouseY < (y + h))) + { + _highlighted = true; + if(MouseUp(SDL_BUTTON(1))) { + _triggered = true; + } + } else { + _highlighted = false; + } +} + +void Button::Render(void) { + if(_font) { + if(_highlighted || _selected) { + _font->SetColor(1.0f, 1.0f, 1.0f, 1.0f); + } else { + _font->SetColor(0.5f, 0.5f, 0.5f, 1.0f); + } + _font->RenderText(x, y, _text.GetPointer()); + _font->SetColor(1.0f, 1.0f, 1.0f, 1.0f); + } +} + +void Button::SetFont(Font* font) { + _font = font; + if(_text.Length() > 0) { + font->TextSize(_text.GetPointer(), w, h); + } +} + +void Button::SetText(const String& text) { + _text = text; + if((_text.Length() > 0) && _font) { + _font->TextSize(text.GetPointer(), w, h); + } +} diff --git a/src/UI/Button.h b/src/UI/Button.h new file mode 100644 index 0000000..6400559 --- /dev/null +++ b/src/UI/Button.h @@ -0,0 +1,48 @@ +#pragma once + +#include "../System/String.h" +#include "../Font/Font.h" + +class Button { +public: + Button(void); + + void Update(void); + void Render(void); + + Font* GetFont(void) { return _font; } + void SetFont(Font* font); + + const String& GetText(void) const { return _text;} + void SetText(const String& text); + + bool IsHighlighted(void) const { return _highlighted; } + void SetHighlighted(bool highlighted) { _highlighted = highlighted; } + + bool IsSelected(void) const { return _selected; } + void SetSelected(bool selected) { _selected = selected; } + + bool Triggered(void) const { return _triggered; } + + int GetX(void) const { return x; } + int GetY(void) const { return y; } + void SetX(int x) { this->x = x; } + void SetY(int y) { this->y = y; } + void SetXY(int x, int y) { SetX(x); SetY(y); } + + int GetWidth(void) const { return w; } + int GetHeight(void) const { return h; } + +private: + Font* _font; + String _text; + + bool _highlighted; + bool _selected; + bool _triggered; + + int x; + int y; + int w; + int h; +}; diff --git a/src/UI/Menu.cpp b/src/UI/Menu.cpp new file mode 100644 index 0000000..a12a9ae --- /dev/null +++ b/src/UI/Menu.cpp @@ -0,0 +1,102 @@ +#include "Menu.h" +#include "Button.h" +#include "../IO/Input.h" + +Menu::Menu(void) { + _triggeredButton = -1; + _selectedButton = 0; + x = 0; + y = 0; +} + +Menu::~Menu(void) { + for(std::list<Button*>::iterator i = _buttons.begin(); i != _buttons.end(); ++i) { + delete (*i); + } + _buttons.clear(); +} + +void Menu::AddButton(Button* button) { + // Select first button. + if(_buttons.empty()) { + button->SetSelected(true); + } + + _buttons.push_back(button); +} + +void Menu::AlignButtons(int how) { + int x = 0; + int y = 0; + for(std::list<Button*>::iterator i = _buttons.begin(); i != _buttons.end(); ++i) { + Button* button = (*i); + button->SetXY(x, y); + + if(how == Menu::ALIGN_HORIZONTALLY) { + x += button->GetWidth() + 24; + } else if(how == Menu::ALIGN_VERTICALLY) { + y += button->GetHeight() + 2; + } + } +} + +void Menu::SelectButton(int index) { + int buttonsIndex = 0; + for(std::list<Button*>::iterator i = _buttons.begin(); i != _buttons.end(); ++i) { + (*i)->SetSelected(buttonsIndex == index); + buttonsIndex++; + } + _selectedButton = index; +} + +void Menu::Update(void) { + _triggeredButton = -1; + + int index = 0; + for(std::list<Button*>::iterator i = _buttons.begin(); i != _buttons.end(); ++i) { + Button* button = (*i); + + int oldX = button->GetX(); + int oldY = button->GetY(); + button->SetXY(oldX + x, oldY + y); + button->Update(); + button->SetXY(oldX, oldY); + + if(button->Triggered()) { + _triggeredButton = index; + } + + index++; + } + + if(KeyDown(SDLK_DOWN)) { + _selectedButton++; + if(_selectedButton == _buttons.size()) { + _selectedButton = 0; + } + SelectButton(_selectedButton); + } + else if(KeyDown(SDLK_UP)) { + _selectedButton--; + if(_selectedButton < 0) { + _selectedButton = _buttons.size() - 1; + } + SelectButton(_selectedButton); + } + + if(KeyDown(SDLK_RETURN)) { + _triggeredButton = _selectedButton; + } +} + +void Menu::Render(void) { + for(std::list<Button*>::iterator i = _buttons.begin(); i != _buttons.end(); ++i) { + Button* button = (*i); + + int oldX = button->GetX(); + int oldY = button->GetY(); + button->SetXY(oldX + x, oldY + y); + button->Render(); + button->SetXY(oldX, oldY); + } +} diff --git a/src/UI/Menu.h b/src/UI/Menu.h new file mode 100644 index 0000000..453a782 --- /dev/null +++ b/src/UI/Menu.h @@ -0,0 +1,39 @@ +#pragma once + +#include <list> + +class Button; + +class Menu { +public: + enum { + ALIGN_HORIZONTALLY, + ALIGN_VERTICALLY + }; + + Menu(void); + ~Menu(void); + + void AddButton(Button* button); + void AlignButtons(int how); + void SelectButton(int index); + + void Update(void); + void Render(void); + + int GetTriggeredButton() const { return _triggeredButton; } + + int GetX(void) const { return x; } + int GetY(void) const { return y; } + void SetX(int x) { this->x = x; } + void SetY(int y) { this->y = y; } + void SetXY(int x, int y) { SetX(x); SetY(y); } + +private: + std::list<Button*> _buttons; + int _triggeredButton; + int _selectedButton; + + int x; + int y; +}; \ No newline at end of file