diff --git a/.gitignore b/.gitignore index 47772a3..6d65327 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,4 @@ install_manifest.txt windows* build/tetris +.kdev4* diff --git a/.kdev4/Tetris.kdev4 b/.kdev4/Tetris.kdev4 index 89e105a..2ffea92 100644 --- a/.kdev4/Tetris.kdev4 +++ b/.kdev4/Tetris.kdev4 @@ -49,5 +49,8 @@ Use External Terminal=true Working Directory= isExecutable=false +[Project] +VersionControlSupport=kdevgit + [SourceFileTemplates] LastUsedTemplate=/home/juraj/.kde/share/apps/kdevfiletemplates/template_descriptions/cpp_basic.desktop diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..2fa0007 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 2.8) + +add_executable(${EXE_NAME} + scoreitem.cpp + scorestate.cpp + stringinput.cpp + part.cpp + main.cpp + global.cpp + map.cpp + resource.cpp + game.cpp + pausestate.cpp + playstate.cpp + menustate.cpp + menuitem.cpp + menu.cpp +) + +target_link_libraries(${EXE_NAME} SDL SDL_ttf) + +set(CMAKE_CXX_FLAGS "-Wextra -ftabstop=4 -march=native -std=gnu++11 -fshow-column -ftabstop=4 -frounding-math -pipe") + +install(TARGETS ${EXE_NAME} RUNTIME DESTINATION bin) diff --git a/src/LICENCE b/src/LICENCE new file mode 100644 index 0000000..4e45844 --- /dev/null +++ b/src/LICENCE @@ -0,0 +1,23 @@ +Copyright (c) 2014, [SG]Orava +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/game.cpp b/src/game.cpp new file mode 100644 index 0000000..8fcf29d --- /dev/null +++ b/src/game.cpp @@ -0,0 +1,228 @@ +#include "game.hpp" +#include "gamestate.hpp" + + +game::game() +{ } + +game::~game() +{ } + + + +bool game::Init() +{ + if ( SDL_Init ( SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_AUDIO ) == -1 ) + { + cerr << "[ERROR] Cannot init SDL" << endl; + + m_bRunning = false; + + return false; + } + + SDL_EnableUNICODE ( SDL_ENABLE ); + + + SDL_WM_SetCaption ( "[SG]Tetris", NULL ); + + m_pScreen = SDL_SetVideoMode ( WIDTH * SIZE + 130, HEIGHT * SIZE, 32, SDL_HWSURFACE | SDL_DOUBLEBUF ); + + if ( m_pScreen == NULL ) + { + cerr << "[ERROR] Cannot setup screen" << endl; + + m_bRunning = false; + + return false; + } + + + if ( TTF_Init() ) + { + cerr << "[ERROR] Cannot init SDL_ttf" << endl; + + m_bRunning = false; + + return false; + } + + + m_bRunning = Load(); + m_bGameOver = false; + tick = 0; + + return m_bRunning; +} + +bool game::Load() +{ + fontMenu = TTF_OpenFont ( "data-latin.ttf", 38 ); + + if ( fontMenu == NULL ) + { + cerr << "[ERROR] Cannot load font 'data-latin.ttf'" << endl; + + return false; + } + + + fontGame = TTF_OpenFont ( "handelgotd.ttf", 30 ); + + if ( fontGame == NULL ) + { + cerr << "[ERROR] Cannot load font 'handelgotd.ttf'" << endl; + + return false; + } + + + return true; +} + +void game::ChangeState ( GameState * state ) +{ + // cleanup the current state + if ( !states.empty() ) + { + states.back()->Clean(); + states.pop_back(); + } + + // store and init the new state + states.push_back ( state ); + states.back()->Init(); +} + +void game::PushState ( GameState * state ) +{ + // pause current state + if ( !states.empty() ) + { + states.back()->Pause(); + } + + // store and init the new state + states.push_back ( state ); + states.back()->Init(); +} + +void game::PopState() +{ + // cleanup the current state + if ( !states.empty() ) + { + states.back()->Clean(); + states.pop_back(); + } + + // resume previous state + if ( !states.empty() ) + { + states.back()->Resume(); + } +} + +void game::DelStateF() +{ + // cleanup the first state + if ( !states.empty() ) + { + states.front()->Clean(); + states.erase(states.begin()); + } +} + +# ifdef DEBUG + int game::CountStates() + { + return states.size(); + } +# endif + +void game::HandleEvents() +{ + states.back()->HandleEvents ( this ); +} + +void game::Update() +{ + states.back()->Update ( this ); +} + +void game::Draw() +{ + states.back()->Draw ( this ); +} + + +SDL_Surface * game::GetScreen() +{ + return m_pScreen; +} + +bool game::Running() +{ + return m_bRunning; +} + +void game::Clean() +{ + # ifdef DEBUG + cout << "Cleanning..." << endl; + # endif + + TTF_CloseFont ( fontMenu ); + + TTF_Quit(); + SDL_Quit(); +} + +void game::Quit() +{ + m_bRunning = false; + + # ifdef DEBUG + cout << "Shutting down..." << endl; + # endif +} + +void game::ReduceFPS() +{ + if ( 1000 / FPS > ( SDL_GetTicks() - start ) ) + { + SDL_Delay ( 1000 / FPS - ( SDL_GetTicks() - start ) ); + } +} + +void game::UpdateFPS() +{ + if ( tick <= FPS ) + { + tick += 1; + } + else + { + tick = 1; + } +} + +Uint32 game::GetStart() +{ + return start; +} + +void game::SetStart ( Uint32 start ) +{ + this->start = start; +} + +TTF_Font * game::GetfontGame() +{ + return fontGame; +} + +TTF_Font * game::GetfontMenu() +{ + return fontMenu; +} diff --git a/src/game.hpp b/src/game.hpp new file mode 100644 index 0000000..105b1ca --- /dev/null +++ b/src/game.hpp @@ -0,0 +1,73 @@ +#ifndef GAME_HPP_INCLUDED +#define GAME_HPP_INCLUDED + +#include +#include +#include +#include + +#include "map.hpp" +#include "part.hpp" + + +using namespace std; + + +class GameState; + +class game +{ + public: + game(); + ~game(); + + bool Init(); + bool Load(); + + void ChangeState ( GameState * state ); + void PushState ( GameState * state ); + void PopState(); + void DelStateF(); + + # ifdef DEBUG + int CountStates(); + # endif + + + void HandleEvents(); + void Update(); + void Draw(); + + SDL_Surface * GetScreen(); + Uint32 GetStart(); + + TTF_Font * GetfontMenu(); + TTF_Font * GetfontGame(); + + void SetStart ( Uint32 start ); + void SetRunning ( bool m_bRunning ); + + void Clean(); + + bool Running(); + void Quit(); + + void ReduceFPS(); + void UpdateFPS(); + + private: + SDL_Surface * m_pScreen; + vector states; + + bool m_bRunning; + bool m_bGameOver; + + TTF_Font * fontMenu; + TTF_Font * fontGame; + + Uint32 start; + int tick; +}; + + +#endif diff --git a/src/gamestate.hpp b/src/gamestate.hpp new file mode 100644 index 0000000..ef2e653 --- /dev/null +++ b/src/gamestate.hpp @@ -0,0 +1,32 @@ +#ifndef GAME_STATE_HPP_INCLUDED +#define GAME_STATE_HPP_INCLUDED + +#include "game.hpp" + + +class GameState +{ + public: + virtual void Init() = 0; + virtual void Clean() = 0; + + virtual void Pause() = 0; + virtual void Resume() = 0; + + virtual void HandleEvents ( game * Game ) = 0; + virtual void Update ( game * Game ) = 0; + virtual void Draw ( game * Game ) = 0; + + void ChangeState ( game * Game, GameState * state ) + { + Game->ChangeState ( state ); + } + + protected: + GameState() { } + + bool FirstRun; +}; + + +#endif diff --git a/src/global.cpp b/src/global.cpp new file mode 100644 index 0000000..be01a1c --- /dev/null +++ b/src/global.cpp @@ -0,0 +1,29 @@ +#include "global.hpp" + + +void drawQuad ( SDL_Surface * screen, short int x, short int y, int color ) +{ + SDL_Rect rect = {x, y, SIZE, SIZE}; + + SDL_FillRect ( screen, &rect, color ); +} + +void apply_surface ( int x, int y, SDL_Surface * source, SDL_Surface * destination, SDL_Rect * clip ) +{ + //Holds offsets + SDL_Rect offset; + + //Get offsets + offset.x = x; + offset.y = y; + + //Blit + SDL_BlitSurface ( source, clip, destination, &offset ); +} + +SDL_Color make_color ( Uint8 r, Uint8 g, Uint8 b ) +{ + SDL_Color color = {r, g, b}; + + return color; +} diff --git a/src/global.hpp b/src/global.hpp new file mode 100644 index 0000000..f94e847 --- /dev/null +++ b/src/global.hpp @@ -0,0 +1,19 @@ +#ifndef GLOBAL_HPP_INCLUDED +#define GLOBAL_HPP_INCLUDED + +#include +#include +#include +#include + +#include "resource.hpp" + + + + +void drawQuad ( SDL_Surface* screen, short int x, short int y, int color ); +void apply_surface ( int x, int y, SDL_Surface * source, SDL_Surface * destination, SDL_Rect * clip = NULL ); +SDL_Color make_color ( Uint8 r, Uint8 g, Uint8 b ); + + +#endif diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..6d9bcb3 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,44 @@ +#include +#include +#include +#include + +#include "resource.hpp" +#include "global.hpp" +#include "game.hpp" + +#include "states.hpp" + + +using namespace std; + + +int main ( int argc, char ** argv ) +{ + srand ( time ( NULL ) ); + + game Game; + + if ( !Game.Init() ) + { + return 0; + } + + + Game.ChangeState ( MenuState::Instance() ); + + while ( Game.Running() ) + { + Game.SetStart ( SDL_GetTicks() ); + + Game.HandleEvents(); + Game.Update(); + Game.Draw(); + + Game.ReduceFPS(); + } + + Game.Clean(); + + return 0; +} diff --git a/src/map.cpp b/src/map.cpp new file mode 100644 index 0000000..fb6693a --- /dev/null +++ b/src/map.cpp @@ -0,0 +1,140 @@ +#include "map.hpp" + + +map::map() +{ + reset(); +} + +void map::reset() +{ + for (int y = 0; y < HEIGHT; y++) + { + for (int x = 0; x < WIDTH; x++) + { + data[y][x] = 0; + } + } +} + +bool map::isCollision(part Part, bool strict) +{ + for (int y = 0; y < 4; y++) + { + for (int x = 0; x < 4; x++) + { + if (strict) + { + if ( (Part.getPosY() + y >= 0) && + ( ( data[Part.getPosY() + y][Part.getPosX() + x] && Part.getElement(x, y) ) || + ( Part.getElement(x, y) && Part.getPosX() + x >= WIDTH)) ) + { + return true; + } + } + else + { + if ( (Part.getPosY() + y >= 0) && + ( ( data[Part.getPosY() + y + 1][Part.getPosX() + x] && Part.getElement(x, y) ) || + ( Part.getElement(x, y) && Part.getPosY() + y >= HEIGHT - 1)) ) + { + return true; + } + } + } + } + + return false; +} + +void map::addPart(part Part) +{ + for (int y = 0; y < 4; y++) + { + for (int x = 0; x < 4; x++) + { + if (Part.getElement(x, y)) + data[Part.getPosY() + y][Part.getPosX() + x] = Part.getColor() + 1; + } + } +} + +void map::applyGravity(int h) +{ + int tmp = 0; + + for (int y = h; y > -1; y--) + { + for (int x = 0; x < WIDTH; x++) + { + if (y < (HEIGHT - 1) && data[y + 1][x] == 0 && data[y][x]) + { + tmp = data[y + 1][x]; + data[y + 1][x] = data[y][x]; + data[y][x] = 0; + } + } + } +} + +int map::destroyLines() +{ + int pocet = 0; + + for (int y = 0; y < HEIGHT; y++) + { + bool good = true; + + for (int x = 0; x < WIDTH; x++) + { + if (!data[y][x]) + { + good = false; + + break; + } + } + + if (good) + { + for (int x = 0; x < WIDTH; x++) + { + data[y][x] = 0; + } + + applyGravity(y); + pocet++; + + y = 0; + } + } + + return pocet; +} + +bool map::isFull() +{ + for (int x = 0; x < WIDTH; x++) + { + if (data[0][x]) + { + return true; + } + } + + return false; +} + +void map::draw(SDL_Surface *screen) +{ + for(int i = 0; i < HEIGHT; i++) + { + for(int m = 0; m < WIDTH; m++) + { + if(data[i][m]) + { + drawQuad(screen, m * SIZE, i * SIZE, colors[data[i][m] - 1]); + } + } + } +} diff --git a/src/map.hpp b/src/map.hpp new file mode 100644 index 0000000..b9b2b34 --- /dev/null +++ b/src/map.hpp @@ -0,0 +1,29 @@ +#ifndef MAP_HPP_INCLUDED +#define MAP_HPP_INCLUDED + +#include +#include + +#include "resource.hpp" +#include "part.hpp" +#include "global.hpp" + + +class map +{ + private: + int data[HEIGHT][WIDTH]; + + public: + map(); + + void reset(); + bool isCollision ( part Part, bool strict = false ); + void addPart ( part Part ); + void applyGravity ( int h ); + int destroyLines(); + bool isFull(); + void draw ( SDL_Surface * screen ); +}; + +#endif diff --git a/src/menu.cpp b/src/menu.cpp new file mode 100644 index 0000000..1e59fef --- /dev/null +++ b/src/menu.cpp @@ -0,0 +1,68 @@ +#include "menu.hpp" + + +Menu::Menu() +{ + select = 0; + + # ifdef DEBUG + cout << "First item selected" << endl; + # endif +} + +Menu::~Menu() +{ + +} + +void Menu::addItem(const char* nazov, void (* action)(game*)) +{ + MenuItem item = MenuItem(nazov, action); + + polozky.push_back(item); + + # ifdef DEBUG + cout << "Item was added" << endl; + # endif +} + +void Menu::Execute(game* Game) +{ + polozky[select].Execute(Game); +} + +void Menu::Draw(game* Game) +{ + int i = 0; + + for (vector::iterator it = polozky.begin(); it != polozky.end(); it++) + { + it->draw(Game, 100, (i * 50 + 50), (i == select)); + + i++; + } +} + +void Menu::Down(game* Game) +{ + if (polozky.size() > (select + 1)) + { + select++; + + # ifdef DEBUG + cout << "Next item" << endl; + # endif + } +} + +void Menu::Up(game* Game) +{ + if (select > 0) + { + # ifdef DEBUG + cout << "Previous item" << endl; + # endif + + select--; + } +} diff --git a/src/menu.hpp b/src/menu.hpp new file mode 100644 index 0000000..182445d --- /dev/null +++ b/src/menu.hpp @@ -0,0 +1,34 @@ +#ifndef MENU_HPP_INCLUDED +#define MENU_HPP_INCLUDED + + +#include +#include + +#include "game.hpp" +#include "menuitem.hpp" + + +using namespace std; + + +class Menu +{ + public: + Menu(); + ~Menu(); + + void addItem ( const char * nazov, void ( * action ) ( game * ) ); + void Execute ( game * Game ); + void Draw ( game * Game ); + + void Down ( game * Game ); + void Up ( game * Game ); + + private: + vector polozky; + int select; +}; + + +#endif diff --git a/src/menuitem.cpp b/src/menuitem.cpp new file mode 100644 index 0000000..4c0a82e --- /dev/null +++ b/src/menuitem.cpp @@ -0,0 +1,39 @@ +#include "menuitem.hpp" + + +MenuItem::MenuItem(const char* nazov, void (* action)(game*)) +{ + this->nazov = nazov; + this->action = action; +} + +void MenuItem::Execute(game* Game) +{ + # ifdef DEBUG + cout << "Executing..." << endl; + # endif + + action(Game); +} + +void MenuItem::draw(game* Game, int x, int y, bool active) +{ + SDL_Color textColor; + + if (active) + { + textColor = make_color(123, 123, 255); + } + else + { + textColor = make_color(255, 255, 255); + } + + message = TTF_RenderText_Solid( Game->GetfontMenu(), nazov, textColor); + + apply_surface(x, y, message, Game->GetScreen()); + + + SDL_FreeSurface(message); +} + diff --git a/src/menuitem.hpp b/src/menuitem.hpp new file mode 100644 index 0000000..a703514 --- /dev/null +++ b/src/menuitem.hpp @@ -0,0 +1,34 @@ +#ifndef MENUITEM_HPP_INCLUDED +#define MENUITEM_HPP_INCLUDED + + +#include +#include +#include + +#include "global.hpp" +#include "game.hpp" + + +using namespace std; + + +class MenuItem +{ + public: + MenuItem ( const char * nazov, void ( * action ) ( game * ) ); + + void Execute ( game * Game ); + void draw ( game * Game, int x, int y, bool active = false ); + + private: + void ( * action ) ( game * ); + + const char * nazov; + SDL_Surface * message; + + SDL_Color text_color; +}; + + +#endif diff --git a/src/menustate.cpp b/src/menustate.cpp new file mode 100644 index 0000000..6000851 --- /dev/null +++ b/src/menustate.cpp @@ -0,0 +1,127 @@ +#include "states.hpp" + + +MenuState MenuState::m_MenuState; + +void MenuState::Init() +{ + menu = new Menu(); + + menu->addItem("Play", play); + menu->addItem("High Score", score); + + # ifdef DEBUG + menu->addItem("Debug Info", Debug_Info); + # endif + + menu->addItem("Exit", quit); + + # ifdef DEBUG + std::cout << "MenuState Init Successful" << std::endl; + # endif +} + +void MenuState::Clean() +{ + delete menu; + + # ifdef DEBUG + std::cout << "MenuState Clean Successful" << std::endl; + # endif +} + +void MenuState::Pause() +{ + # ifdef DEBUG + std::cout << "MenuState Paused" << std::endl; + # endif +} + +void MenuState::Resume() +{ + # ifdef DEBUG + std::cout << "MenuState Resumed" << std::endl; + # endif +} + +void MenuState::HandleEvents(game* Game) +{ + SDL_Event event; + + while (SDL_PollEvent(&event)) + { + switch (event.type) + { + case SDL_QUIT: + Game->Quit(); + break; + + case SDL_KEYDOWN: + switch (event.key.keysym.sym) + { + case SDLK_ESCAPE: + { + Game->Quit(); + } + break; + + case SDLK_DOWN: + menu->Down(Game); + break; + + case SDLK_UP: + menu->Up(Game); + break; + + case SDLK_SPACE: + menu->Execute(Game); + break; + + case SDLK_RETURN: + menu->Execute(Game); + break; + } + break; + } + } +} + +void MenuState::Update(game* Game) +{ + SDL_FillRect(Game->GetScreen(), NULL, 0x000000); +} + +// We have to change the way we get the screen in this function +void MenuState::Draw(game* Game) +{ + menu->Draw(Game); + + SDL_Flip(Game->GetScreen()); +} + + +void MenuState::play(game* Game) +{ + Game->ChangeState(PlayState::Instance()); +} + +void MenuState::score(game* Game) +{ + Game->PushState(ScoreState::Instance()); +} + +void MenuState::quit(game* Game) +{ + Game->Quit(); +} + +# ifdef DEBUG + void MenuState::Debug_Info(game* Game) + { + std::cout << "\n\n=== DEBUG INFO ===\n" << std::endl; + + std::cout << "Number of States: " << Game->CountStates() << std::endl; + + std::cout << "\n=== Debug Info ===\n\n" << endl; + } +# endif diff --git a/src/menustate.hpp b/src/menustate.hpp new file mode 100644 index 0000000..a8d32df --- /dev/null +++ b/src/menustate.hpp @@ -0,0 +1,52 @@ +#ifndef MENU_STATE_HPP_INCLUDED +#define MENU_STATE_HPP_INCLUDED + + +#include +#include + +#include "game.hpp" +#include "gamestate.hpp" +#include "menuitem.hpp" +#include "menu.hpp" + + +class MenuState : public GameState +{ + public: + void Init(); + void Clean(); + + void Pause(); + void Resume(); + + void HandleEvents ( game * Game ); + void Update ( game * Game ); + void Draw ( game * Game ); + + // Implement Singleton Pattern + static MenuState * Instance() + { + return &m_MenuState; + } + + + static void play ( game * Game ); + static void score ( game * Game ); + static void quit ( game * Game ); + + # ifdef DEBUG + static void Debug_Info ( game * Game ); + # endif + + protected: + MenuState() {} + + private: + static MenuState m_MenuState; + + Menu * menu; +}; + + +#endif diff --git a/src/part.cpp b/src/part.cpp new file mode 100644 index 0000000..de5adf3 --- /dev/null +++ b/src/part.cpp @@ -0,0 +1,132 @@ +#include "part.hpp" + + +part::part() +{ + posX = WIDTH / 2 - 1; + posY = -4; + + generate(); +} + +void part::fillData() +{ + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 4; j++) + { + data[i][j] = Shapes[shapeIndex][i][j]; + } + } +} + +void part::generate() +{ + int g; + + g = (rand() % 7) * 4; + + shapeIndex = (ShapeIndexes)g; + color = g / 4; + + fillData(); +} + +void part::move(int x, int y) +{ + if (isValid(x, y)) + { + posX += x; + posY += y; + } +} + +void part::rotate() +{ + int coIndex; + + coIndex = shapeIndex; + + shapeIndex = ((shapeIndex + 1) % 4 == 0 ? shapeIndex - 3 : shapeIndex + 1); + + fillData(); + + if (!isValid()) + { + shapeIndex = coIndex; + + fillData(); + } +} + +bool part::isValid(int xOffset, int yOffset) +{ + for (int y = 0; y < 4; y++) + { + for (int x = 0; x < 4; x++) + { + if ( (data[y][x] && (posX + x + xOffset >= WIDTH || posX + xOffset < 0)) || (data[y][x] && (posY + y + yOffset > HEIGHT)) ) + { + # ifdef DEBUG + cout << "InValid" << endl; + # endif + + return false; + } + } + } + + # ifdef DEBUG + cout << "Valid" << endl; + # endif + + return true; +} + +void part::draw(SDL_Surface *screen) +{ + for (int i = 0; i < 4 ;i++) + { + for (int m = 0; m < 4; m++) + { + if (data[i][m]) + { + drawQuad(screen, (m + posX) * SIZE, (i + posY) * SIZE, colors[color]); + } + } + } +} + +void part::draw ( int startX, int startY, SDL_Surface * screen ) +{ + for (int i = 0; i < 4 ;i++) + { + for (int m = 0; m < 4; m++) + { + if (data[i][m]) + { + drawQuad(screen, (m + posX) * SIZE + startX, (i + posY) * SIZE + startY, colors[color]); + } + } + } +} + +int part::getPosX() +{ + return posX; +} + +int part::getPosY() +{ + return posY; +} + +int part::getElement(int x, int y) +{ + return data[y][x]; +} + +int part::getColor() +{ + return color; +} diff --git a/src/part.hpp b/src/part.hpp new file mode 100644 index 0000000..f22dd20 --- /dev/null +++ b/src/part.hpp @@ -0,0 +1,45 @@ +#ifndef PART_HPP_INCLUDED +#define PART_HPP_INCLUDED + +#include +#include + +#include "resource.hpp" +#include "global.hpp" + + +using namespace std; + + +class part +{ + private: + int shapeIndex; + int posX; + int posY; + + void fillData(); + + + protected: + int data[4][4]; + int color; + + + public: + part(); + + void generate(); + void move ( int x, int y ); + void rotate(); + bool isValid ( int xOffset = 0, int yOffset = 0 ); + void draw ( SDL_Surface * screen ); + void draw ( int startX, int startY, SDL_Surface * screen ); + + int getPosX(); + int getPosY(); + int getElement ( int x, int y ); + int getColor(); +}; + +#endif diff --git a/src/pausestate.cpp b/src/pausestate.cpp new file mode 100644 index 0000000..989a1c0 --- /dev/null +++ b/src/pausestate.cpp @@ -0,0 +1,110 @@ +#include "states.hpp" + + +PauseState PauseState::m_PauseState; + +void PauseState::Init() +{ + menu = new Menu(); + + menu->addItem("Resume", resume); + menu->addItem("To menu", go_to_menu); + menu->addItem("Exit", quit); + + # ifdef DEBUG + std::cout << "PauseState Init Successful" << std::endl; + # endif +} + +void PauseState::Clean() +{ + delete menu; + + # ifdef DEBUG + std::cout << "PauseState Clean Successful" << std::endl; + # endif +} + +void PauseState::Pause() +{ + # ifdef DEBUG + std::cout << "PauseState Paused" << std::endl; + # endif +} + +void PauseState::Resume() +{ + # ifdef DEBUG + std::cout << "PauseState Resumed" << std::endl; + # endif +} + +void PauseState::HandleEvents(game* Game) +{ + SDL_Event event; + + while (SDL_PollEvent(&event)) + { + switch (event.type) + { + case SDL_QUIT: + Game->Quit(); + break; + + case SDL_KEYDOWN: + switch (event.key.keysym.sym) + { + case SDLK_ESCAPE: + Game->PopState(); + break; + + case SDLK_DOWN: + menu->Down(Game); + break; + + case SDLK_UP: + menu->Up(Game); + break; + + case SDLK_SPACE: + menu->Execute(Game); + break; + + case SDLK_RETURN: + menu->Execute(Game); + break; + } + break; + } + } +} + +void PauseState::Update(game* Game) +{ + SDL_FillRect(Game->GetScreen(), NULL, 0x000000); +} + +// We have to change the way we get the screen in this function +void PauseState::Draw(game* Game) +{ + menu->Draw(Game); + + SDL_Flip(Game->GetScreen()); +} + + +void PauseState::resume(game* Game) +{ + Game->PopState(); +} + +void PauseState::go_to_menu(game* Game) +{ + Game->DelStateF(); + Game->ChangeState(MenuState::Instance()); +} + +void PauseState::quit(game* Game) +{ + Game->Quit(); +} diff --git a/src/pausestate.hpp b/src/pausestate.hpp new file mode 100644 index 0000000..d4baa03 --- /dev/null +++ b/src/pausestate.hpp @@ -0,0 +1,48 @@ +#ifndef PAUSE_STATE_HPP_INCLUDED +#define PAUSE_STATE_HPP_INCLUDED + + +#include +#include + +#include "game.hpp" +#include "gamestate.hpp" +#include "menuitem.hpp" +#include "menu.hpp" + + +class PauseState : public GameState +{ + public: + void Init(); + void Clean(); + + void Pause(); + void Resume(); + + void HandleEvents ( game * Game ); + void Update ( game * Game ); + void Draw ( game * Game ); + + // Implement Singleton Pattern + static PauseState * Instance() + { + return &m_PauseState; + } + + + static void resume ( game * Game ); + static void go_to_menu ( game * Game ); + static void quit ( game * Game ); + + protected: + PauseState() {} + + private: + static PauseState m_PauseState; + + Menu * menu; +}; + + +#endif diff --git a/src/playstate.cpp b/src/playstate.cpp new file mode 100644 index 0000000..8617532 --- /dev/null +++ b/src/playstate.cpp @@ -0,0 +1,373 @@ +# include "game.hpp" +# include "states.hpp" + + +PlayState PlayState::m_PlayState; + + +void PlayState::Init() +{ + Map = map(); + Part = part(); + Next = part(); + + level = 0; + lines = 0; + score = 0; + + tick = 1; + + nameEntered = false; + nameEntering = false; + message = NULL; + + textColor = make_color(255, 255, 255); + + SDL_EnableKeyRepeat ( REPAET_DELAY, SDL_DEFAULT_REPEAT_INTERVAL ); + + # ifdef DEBUG + std::cout << "PlayState Init Successful" << std::endl; + # endif +} + +void PlayState::Clean() +{ + SDL_EnableKeyRepeat ( 0, 0 ); + + # ifdef DEBUG + std::cout << "PlayState Clean Successful" << std::endl; + # endif +} + +void PlayState::Pause() +{ + SDL_EnableKeyRepeat ( 0, 0 ); + + # ifdef DEBUG + std::cout << "PlayState Paused" << std::endl; + # endif +} + +void PlayState::Resume() +{ + SDL_EnableKeyRepeat ( REPAET_DELAY, SDL_DEFAULT_REPEAT_INTERVAL ); + + # ifdef DEBUG + std::cout << "PlayState Resumed" << std::endl; + # endif +} + +void PlayState::HandleEvents ( game* Game ) +{ + SDL_Event event; + + while ( SDL_PollEvent ( &event ) ) + { + if ( event.type == SDL_QUIT) + Game->Quit(); + + /* Game Over - Write name for score */ + if( nameEntering == true && nameEntered == false ) + { + //Get user input + name.handle_input(Game, &event); + + //If the enter key was pressed + if( ( event.type == SDL_KEYDOWN ) && ( event.key.keysym.sym == SDLK_RETURN ) ) + { + //Change the flag + nameEntered = true; + nameEntering = false; + + Save(name.GetStr(), lines); + + name.Clear(); + + //Free the old message surface + SDL_FreeSurface( message ); + + //Change the message + } + + name.show_centered(Game); + } + /* Game key logic... */ + else + { + switch ( event.type ) + { + /* key pressed.... */ + case SDL_KEYDOWN: + switch ( event.key.keysym.sym ) + { + /* ESCAPE - Pause game (run PauseState) */ + case SDLK_ESCAPE: + { + //Game->SetRunning(false); + Game->PushState ( PauseState::Instance() ); + } + break; + + /* move part to the right */ + case SDLK_RIGHT: + { + /* */ + part p = Part; + + # ifdef DEBUG + std::cout << "move to Right: "; + # endif + + Part.move ( 1, 0 ); + + if ( Map.isCollision ( Part, true ) ) + { + # ifdef DEBUG + std::cout << "Collision" << std::endl; + # endif + + Part = p; + } + } + break; + + case SDLK_LEFT: + { + part p = Part; + + # ifdef DEBUG + std::cout << "move to Left: "; + # endif + + Part.move ( -1, 0 ); + + if ( Map.isCollision ( Part, true ) ) + { + # ifdef DEBUG + std::cout << "Collision" << std::endl; + # endif + + Part = p; + } + } + break; + + case SDLK_DOWN: + # ifdef DEBUG + std::cout << "move to Down: "; + # endif + + if ( !Map.isCollision ( Part ) ) + { + Part.move ( 0, 1 ); + } + else + { + # ifdef DEBUG + std::cout << "Collision" << std::endl; + # endif + } + break; + + case SDLK_UP: + { + part p = Part; + + # ifdef DEBUG + std::cout << "Rotate: "; + # endif + + Part.rotate(); + + if ( Map.isCollision ( Part, true ) ) + { + # ifdef DEBUG + std::cout << "Map: Collission" << std::endl; + # endif + + Part = p; + } + } + break; + + case SDLK_SPACE: + # ifdef DEBUG + std::cout << "move to Bottom" << std::endl; + # endif + + while ( !Map.isCollision ( Part ) ) + { + Part.move ( 0, 1 ); + + tick = ( FPS / ( ( level > 30 ) ? 30 : level ) ) - 1; + } + break; + + case SDLK_RETURN: + { + # ifdef DEBUG + std::cout << "continue" << std::endl; + # endif + + //Game->m_bGameOver = false; + } + break; + } + break; + } + } + } +} + +void PlayState::Update ( game* Game ) +{ + /* kontrola či je plné hracie pole... */ + if ( Map.isFull() ) + { + /* Start enter name */ + nameEntering = true; + + if (nameEntered) + { + nameEntering = false; + nameEntered = false; + //text.setString("Score " + intToStr(Map.getScore()) + "\n" + "Press enter"); + Map.reset(); + + lines = 0; + level = 1; + } + } + + + if (!nameEntering) + { + if ( level == 0 ) + { + level = 1; + } + + if ( tick % ( FPS / ( ( level > 30 ) ? 30 : level ) ) == 0 && !Map.isCollision ( Part ) ) + { + # ifdef DEBUG + std::cout << "move to Down: "; + # endif + + Part.move ( 0, 1 ); + } + + /* + if ( tick % ( FPS / ( ( level > 30 ) ? 30 : level ) ) != 0 && Map.isCollision ( Part ) && tick != ( FPS / ( ( level > 30 ) ? 30 : level ) ) -1 ) + std::cout << "DEBUG" << std::endl; + */ + + if ( Map.isCollision ( Part ) && ( tick ) == ( FPS / ( ( level > 30 ) ? 30 : level ) ) -1 ) + { + int count; + + Map.addPart ( Part ); + + count = Map.destroyLines(); + + lines += count; + // level = (lines >= 5) ? (lines / 10) : 0; + level = lines / 10 + 1; + + # ifdef DEBUG + std::cout << "Lines: " << lines << std::endl; + std::cout << "Level: " << level << std::endl; + # endif + + Part = Next; + Next = part(); + } + + + if ( tick < FPS ) + { + tick++; + } + else + { + tick = 1; + } + } +} + + +void PlayState::Draw ( game* Game ) +{ + if (!nameEntering) + { + SDL_FillRect ( Game->GetScreen(), NULL, 0x000000 ); + + SDL_Rect rect = {WIDTH * SIZE, 0, 130, HEIGHT * SIZE}; + + SDL_FillRect ( Game->GetScreen(), &rect, 0x111111 ); + + Map.draw ( Game->GetScreen() ); + Part.draw ( Game->GetScreen() ); + Next.draw ( 165, 100, Game->GetScreen() ); + + PlayInfo(this, Game); + } + else + { + SDL_FillRect ( Game->GetScreen(), NULL, 0x000000 ); + + message = TTF_RenderText_Solid( Game->GetfontGame(), "Enter Name: ", textColor ); + apply_surface(10, 40, message, Game->GetScreen()); + + name.show_centered(Game); + } + + SDL_Flip ( Game->GetScreen() ); +} + + +void PlayState::Save ( string Name, int Lines ) +{ + ofstream file; + + file.open(".score", ios_base::app); + + if (file.is_open()) + { + file << Name << " " << Lines << endl; + + file.close(); + } + else + { + cerr << "Cannot open file '.score'" << endl; + } +} + + +void PlayInfo ( PlayState * Info, game * Game ) +{ + SDL_Color textColor; + SDL_Surface * message; + char temp[10]; + + textColor = make_color(255, 255, 255); + + + message = TTF_RenderText_Solid( Game->GetfontGame(), "Lines", textColor); + apply_surface(220, 150, message, Game->GetScreen()); + + std::sprintf ( temp, "%d", Info->lines); + message = TTF_RenderText_Solid( Game->GetfontGame(), temp, textColor); + apply_surface(220, 185, message, Game->GetScreen()); + + + message = TTF_RenderText_Solid( Game->GetfontGame(), "Level", textColor); + apply_surface(220, 230, message, Game->GetScreen()); + + std::sprintf ( temp, "%d", Info->level); + message = TTF_RenderText_Solid( Game->GetfontGame(), temp, textColor); + apply_surface(220, 265, message, Game->GetScreen()); + + + SDL_FreeSurface(message); +} diff --git a/src/playstate.hpp b/src/playstate.hpp new file mode 100644 index 0000000..f13616d --- /dev/null +++ b/src/playstate.hpp @@ -0,0 +1,68 @@ +# ifndef PLAY_STATE_HPP_INCLUDED +# define PLAY_STATE_HPP_INCLUDED + +# include +# include +# include +# include + +# include "game.hpp" +# include "gamestate.hpp" +# include "resource.hpp" +# include "part.hpp" +# include "map.hpp" +# include "stringinput.hpp" + + +class PlayState : public GameState +{ + public: + void Init(); + void Clean(); + + void Pause(); + void Resume(); + + void HandleEvents ( game * Game ); + void Update ( game * Game ); + void Draw ( game * Game ); + + // Implement Singleton Pattern + static PlayState * Instance() + { + return &m_PlayState; + } + + friend void PlayInfo ( PlayState * Info, game * Game ); + + protected: + PlayState() {} + + private: + void Save(string Name, int Lines); + + static PlayState m_PlayState; + + map Map; + part Part; + part Next; + + int score; + int level; + int lines; + + int tick; + + bool nameEntered; + bool nameEntering; + + SDL_Surface * message; + SDL_Color textColor; + + StringInput name; +}; + + +void PlayInfo ( PlayState * Info, game * Game ); + +# endif diff --git a/src/resource.cpp b/src/resource.cpp new file mode 100644 index 0000000..d66a55e --- /dev/null +++ b/src/resource.cpp @@ -0,0 +1,21 @@ +#include "resource.hpp" + + +int colors[7] = +{ + 0xFF0000, + 0x00FF00, + 0x0000FF, + 0xFF00FF, + 0x00FFFF, + 0xFFFF00, + 0xFF8000 +}; + +int points[4] = +{ + 40, + 100, + 300, + 1200 +}; diff --git a/src/resource.hpp b/src/resource.hpp new file mode 100644 index 0000000..41186a8 --- /dev/null +++ b/src/resource.hpp @@ -0,0 +1,203 @@ +# ifndef RESOURCE_HPP_INCLUDED +# define RESOURCE_HPP_INCLUDED + + +# define WIDTH 10 +# define HEIGHT 20 +# define SIZE 20 +# define FPS 60 + +# define REPAET_DELAY 170 + +extern int colors[7]; +extern int points[4]; + +enum ShapeIndexes { I = 0, O = 4, S = 8, Z = 12, T = 16, L = 20, J = 24 }; + +/* Šablóny hracích "kociak" */ +const bool Shapes[][4][4] = +{ + /* I */ + { + {1, 0, 0, 0}, + {1, 0, 0, 0}, + {1, 0, 0, 0}, + {1, 0, 0, 0} + }, + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {1, 1, 1, 1} + }, + { + {1, 0, 0, 0}, + {1, 0, 0, 0}, + {1, 0, 0, 0}, + {1, 0, 0, 0} + }, + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {1, 1, 1, 1} + }, + + /* O - kocka */ + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {1, 1, 0, 0}, + {1, 1, 0, 0} + }, + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {1, 1, 0, 0}, + {1, 1, 0, 0} + }, + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {1, 1, 0, 0}, + {1, 1, 0, 0} + }, + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {1, 1, 0, 0}, + {1, 1, 0, 0} + }, + + /* S */ + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 1, 1, 0}, + {1, 1, 0, 0} + }, + { + {0, 0, 0, 0}, + {1, 0, 0, 0}, + {1, 1, 0, 0}, + {0, 1, 0, 0} + }, + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 1, 1, 0}, + {1, 1, 0, 0} + }, + { + {0, 0, 0, 0}, + {1, 0, 0, 0}, + {1, 1, 0, 0}, + {0, 1, 0, 0} + }, + + /* Z */ + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {1, 1, 0, 0}, + {0, 1, 1, 0} + }, + { + {0, 0, 0, 0}, + {0, 1, 0, 0}, + {1, 1, 0, 0}, + {1, 0, 0, 0} + }, + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {1, 1, 0, 0}, + {0, 1, 1, 0} + }, + { + {0, 0, 0, 0}, + {0, 1, 0, 0}, + {1, 1, 0, 0}, + {1, 0, 0, 0} + }, + + /* T */ + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 1, 0, 0}, + {1, 1, 1, 0} + }, + { + {0, 0, 0, 0}, + {1, 0, 0, 0}, + {1, 1, 0, 0}, + {1, 0, 0, 0} + }, + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {1, 1, 1, 0}, + {0, 1, 0, 0} + }, + { + {0, 0, 0, 0}, + {0, 1, 0, 0}, + {1, 1, 0, 0}, + {0, 1, 0, 0} + }, + + /* L */ + { + {0, 0, 0, 0}, + {1, 0, 0, 0}, + {1, 0, 0, 0}, + {1, 1, 0, 0} + }, + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {1, 1, 1, 0}, + {1, 0, 0, 0} + }, + { + {0, 0, 0, 0}, + {1, 1, 0, 0}, + {0, 1, 0, 0}, + {0, 1, 0, 0} + }, + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 1, 0}, + {1, 1, 1, 0} + }, + + /* J */ + { + {0, 0, 0, 0}, + {0, 1, 0, 0}, + {0, 1, 0, 0}, + {1, 1, 0, 0} + }, + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {1, 0, 0, 0}, + {1, 1, 1, 0} + }, + { + {0, 0, 0, 0}, + {1, 1, 0, 0}, + {1, 0, 0, 0}, + {1, 0, 0, 0} + }, + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {1, 1, 1, 0}, + {0, 0, 1, 0} + }, +}; + +#endif diff --git a/src/scoreitem.cpp b/src/scoreitem.cpp new file mode 100644 index 0000000..cb719fc --- /dev/null +++ b/src/scoreitem.cpp @@ -0,0 +1,35 @@ +#include "scoreitem.hpp" + +ScoreItem::ScoreItem ( string Name, int Lines ) +{ + this->Name = Name; + this->Lines = Lines; + + message = NULL; + + textColor = make_color(255, 255, 255); +} + +ScoreItem::~ScoreItem() +{ + +} + +void ScoreItem::Draw ( game * Game, int y ) +{ + char temp[10]; + + message = TTF_RenderText_Solid( Game->GetfontMenu(), Name.c_str(), textColor); + apply_surface(105, y, message, Game->GetScreen()); + + std::sprintf ( temp, "%d", Lines); + message = TTF_RenderText_Solid( Game->GetfontMenu(), temp, textColor); + apply_surface(15, y, message, Game->GetScreen()); + + SDL_FreeSurface(message); +} + +int ScoreItem::GetLines() +{ + return Lines; +} diff --git a/src/scoreitem.hpp b/src/scoreitem.hpp new file mode 100644 index 0000000..62d136f --- /dev/null +++ b/src/scoreitem.hpp @@ -0,0 +1,32 @@ +#ifndef SCOREITEM_H +#define SCOREITEM_H + +# include +# include +# include + +# include "game.hpp" +# include "global.hpp" + +using namespace std; + + +class ScoreItem +{ + public: + ScoreItem ( string Name, int Lines ); + ~ScoreItem(); + + int GetLines(); + + void Draw( game * Game, int y ); + + private: + string Name; + int Lines; + + SDL_Surface * message; + SDL_Color textColor; +}; + +#endif // SCOREITEM_H diff --git a/src/scorestate.cpp b/src/scorestate.cpp new file mode 100644 index 0000000..1204343 --- /dev/null +++ b/src/scorestate.cpp @@ -0,0 +1,108 @@ +#include "scorestate.hpp" + + +bool operator< (ScoreItem First, ScoreItem Second ) +{ + return (First.GetLines() > Second.GetLines()); +} + + +ScoreState ScoreState::m_ScoreState; + +void ScoreState::Draw ( game * Game ) +{ + for (int i = 0; i < (Items.size() > 10 ? 10 : (int) Items.size()); i++) + { + Items[i].Draw(Game, i * 35); + } + + SDL_Flip(Game->GetScreen()); +} + +void ScoreState::Update ( game * Game ) +{ + SDL_FillRect(Game->GetScreen(), NULL, 0x000000); +} + +void ScoreState::HandleEvents ( game * Game ) +{ + SDL_Event event; + + while (SDL_PollEvent(&event)) + { + switch (event.type) + { + case SDL_QUIT: + Game->Quit(); + break; + + case SDL_KEYDOWN: + switch (event.key.keysym.sym) + { + case SDLK_ESCAPE: + Game->PopState(); + break; + } + break; + } + } +} + +void ScoreState::Resume() +{ + # ifdef DEBUG + std::cout << "ScoreState Resumed" << std::endl; + # endif +} + +void ScoreState::Pause() +{ + # ifdef DEBUG + std::cout << "ScoreState Paused" << std::endl; + # endif +} + +void ScoreState::Clean() +{ + Items.clear(); + + # ifdef DEBUG + std::cout << "ScoreState Clean Successful" << std::endl; + # endif +} + +void ScoreState::Init() +{ + Load(); + + sort(Items.begin(), Items.end()); + + # ifdef DEBUG + std::cout << "ScoreState Init Successful" << std::endl; + # endif +} + +void ScoreState::Load() +{ + ifstream file; + string Name; + int Lines; + + file.open(".score"); + + if (file.is_open()) + { + while (!file.eof()) + { + file >> Name; + file >> Lines; + + if (!file.eof()) + Items.push_back(ScoreItem(Name, Lines)); + } + + file.close(); + } + else + cerr << "Cannot open file '.score'" << endl; +} diff --git a/src/scorestate.hpp b/src/scorestate.hpp new file mode 100644 index 0000000..98bed17 --- /dev/null +++ b/src/scorestate.hpp @@ -0,0 +1,46 @@ +#ifndef SCORESTATE_H +#define SCORESTATE_H + +# include +# include +# include +# include + +# include "gamestate.hpp" +# include "scoreitem.hpp" + +using namespace std; + + +class ScoreState : public GameState +{ + public: + void Init(); + void Clean(); + + void Pause(); + void Resume(); + + void HandleEvents ( game * Game ); + void Update ( game * Game ); + void Draw ( game * Game ); + + // Implement Singleton Pattern + static ScoreState * Instance() + { + return &m_ScoreState; + } + + + protected: + ScoreState() {} + + private: + void Load(); + + static ScoreState m_ScoreState; + + vector Items; +}; + +#endif // SCORESTATE_H diff --git a/src/states.hpp b/src/states.hpp new file mode 100644 index 0000000..b2201ba --- /dev/null +++ b/src/states.hpp @@ -0,0 +1,4 @@ +# include "playstate.hpp" +# include "menustate.hpp" +# include "pausestate.hpp" +# include "scorestate.hpp" diff --git a/src/stringinput.cpp b/src/stringinput.cpp new file mode 100644 index 0000000..dd1db89 --- /dev/null +++ b/src/stringinput.cpp @@ -0,0 +1,99 @@ +#include "stringinput.hpp" + +StringInput::StringInput() +{ + str = ""; + text = NULL; + textColor = make_color ( 255, 255, 255 ); +} + +StringInput::~StringInput() +{ + SDL_FreeSurface ( text ); +} + + +void StringInput::handle_input ( game * Game, SDL_Event *event) +{ + //If a key was pressed + if ( event->type == SDL_KEYDOWN ) + { + //Keep a copy of the current version of the string + string temp = str; + + //If the string less than maximum size + if ( str.length() <= 11 ) + { + //If the key is a number + if ( ( event->key.keysym.unicode >= ( Uint16 ) '0' ) && ( event->key.keysym.unicode <= ( Uint16 ) '9' ) ) + { + //Append the character + str += ( char ) event->key.keysym.unicode; + } + else if ( ( event->key.keysym.unicode == ( Uint16 ) '-' ) ) + { + //Append the character + str += ( char ) event->key.keysym.unicode; + } + //If the key is a uppercase letter + else if ( ( event->key.keysym.unicode >= ( Uint16 ) 'A' ) && ( event->key.keysym.unicode <= ( Uint16 ) 'Z' ) ) + { + //Append the character + str += ( char ) event->key.keysym.unicode; + } + //If the key is a lowercase letter + else if ( ( event->key.keysym.unicode >= ( Uint16 ) 'a' ) && ( event->key.keysym.unicode <= ( Uint16 ) 'z' ) ) + { + //Append the character + str += ( char ) event->key.keysym.unicode; + } + } + + #ifdef DEBUG + cout << str << endl; + #endif + + //If backspace was pressed and the string isn't blank + if ( ( event->key.keysym.sym == SDLK_BACKSPACE ) && ( str.length() != 0 ) ) + { + //Remove a character from the end + str.erase ( str.length() - 1 ); + } + + //If the string was changed + if ( str != temp ) + { + //Free the old surface + SDL_FreeSurface ( text ); + + //Render a new text surface + text = TTF_RenderText_Solid ( Game->GetfontGame(), str.c_str(), textColor ); + } + } + +} + +void StringInput::show_centered ( game * Game ) +{ + //If the surface isn't blank + if ( text != NULL ) + { + //Show the name + apply_surface ( 50, 85, text, Game->GetScreen() ); + } +} + + +string StringInput::GetStr() +{ + return str; +} + + +void StringInput::Clear() +{ + str = ""; + + SDL_FreeSurface ( text ); + text = NULL; +} diff --git a/src/stringinput.hpp b/src/stringinput.hpp new file mode 100644 index 0000000..f02d0d9 --- /dev/null +++ b/src/stringinput.hpp @@ -0,0 +1,35 @@ +#ifndef STRINGINPUT_H +#define STRINGINPUT_H + +# include +# include +# include +# include + +# include "game.hpp" +# include "global.hpp" + +using namespace std; + + +class StringInput +{ + public: + StringInput(); + ~StringInput(); + + string GetStr(); + + void handle_input( game * Game, SDL_Event * event ); + void show_centered( game * Game ); + + void Clear(); + + private: + string str; + + SDL_Surface *text; + SDL_Color textColor; +}; + +#endif // STRINGINPUT_H