From 065788dedca0d8e8093b61b785390d5a613b7111 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C5=82ogowski?= Date: Fri, 29 Jun 2018 22:17:05 +0200 Subject: [PATCH] v1.2.0 Added StateMachine, Menu, About --- .gitignore | 329 ++++++++++++++++++++++++++++++++++++ Tanks/AboutState.cpp | 57 +++++++ Tanks/AboutState.h | 17 ++ Tanks/Bullet.cpp | 5 + Tanks/Bullet.h | 3 +- Tanks/Game.cpp | 158 ++++++++--------- Tanks/Game.h | 20 ++- Tanks/GameState.cpp | 88 ++++++++++ Tanks/GameState.h | 18 ++ Tanks/MenuState.cpp | 135 +++++++++++++++ Tanks/MenuState.h | 38 +++++ Tanks/Object.cpp | 8 + Tanks/Object.h | 4 +- Tanks/State.cpp | 30 ++++ Tanks/State.h | 34 ++++ Tanks/Tank.cpp | 23 ++- Tanks/Tank.h | 2 + Tanks/Tanks.vcxproj | 15 +- Tanks/Tanks.vcxproj.filters | 127 +++++++++----- Tanks/TitleState.cpp | 46 +++++ Tanks/TitleState.h | 19 +++ Tanks/UI.cpp | 29 ++-- Tanks/UI.h | 3 +- Tanks/Wall.cpp | 15 +- Tanks/Wall.h | 7 +- Tanks/images/title.png | Bin 0 -> 46577 bytes Tanks/main.cpp | 6 +- Tanks/map.txt | 4 +- 28 files changed, 1074 insertions(+), 166 deletions(-) create mode 100644 .gitignore create mode 100644 Tanks/AboutState.cpp create mode 100644 Tanks/AboutState.h create mode 100644 Tanks/GameState.cpp create mode 100644 Tanks/GameState.h create mode 100644 Tanks/MenuState.cpp create mode 100644 Tanks/MenuState.h create mode 100644 Tanks/State.cpp create mode 100644 Tanks/State.h create mode 100644 Tanks/TitleState.cpp create mode 100644 Tanks/TitleState.h create mode 100644 Tanks/images/title.png diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f431ddc --- /dev/null +++ b/.gitignore @@ -0,0 +1,329 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ diff --git a/Tanks/AboutState.cpp b/Tanks/AboutState.cpp new file mode 100644 index 0000000..dff0e04 --- /dev/null +++ b/Tanks/AboutState.cpp @@ -0,0 +1,57 @@ +#include "AboutState.h" + + + +AboutState::AboutState(std::string version, TTF_Font *font72, TTF_Font *font48, TTF_Font *font24, TTF_Font *font18) +{ + texture.push_back(new Texture(400, 50)); + texture.push_back(new Texture(460, 130)); + texture.push_back(new Texture(100, 500)); + texture.push_back(new Texture(100, 550)); + texture.push_back(new Texture(100, 600)); + texture.push_back(new Texture(100, 650)); + + texture[0]->loadText("TANKS", font72); + texture[1]->loadText(version, font48); + texture[2]->loadText("Copyright \xa9 2018 Michal Glogowski (Szaman97)", font24); + texture[3]->loadText("https://github.com/Szaman97", font24); + texture[4]->loadText("License: BSD 3-Clause", font24); + texture[5]->loadText("This software uses Simple DirectMedia Layer library", font24); +} + + +AboutState::~AboutState() +{ + for (int i = 0; i < static_cast(texture.size()); i++) + { + delete texture[i]; + } +} + +void AboutState::handleEvents(SDL_Event &e) +{ + while (SDL_PollEvent(&e)) + { + if (e.type == SDL_QUIT) + this->setNextState(EXIT); + else if (e.type == SDL_KEYDOWN) + this->setNextState(MENU); + } +} + +void AboutState::logic() {} + +void AboutState::render() +{ + //Clear window + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + SDL_RenderClear(renderer); + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + + for (auto x : texture) + { + x->render(); + } + + SDL_RenderPresent(renderer); +} \ No newline at end of file diff --git a/Tanks/AboutState.h b/Tanks/AboutState.h new file mode 100644 index 0000000..a895802 --- /dev/null +++ b/Tanks/AboutState.h @@ -0,0 +1,17 @@ +#pragma once +#include "State.h" +#include "Game.h" + +class AboutState : public State +{ +public: + AboutState(std::string version, TTF_Font *font72, TTF_Font *font48, TTF_Font *font24, TTF_Font *font18); + ~AboutState(); + virtual void handleEvents(SDL_Event &e); + virtual void logic(); + virtual void render(); + +private: + std::vector texture; +}; + diff --git a/Tanks/Bullet.cpp b/Tanks/Bullet.cpp index 10117c4..babd1d8 100644 --- a/Tanks/Bullet.cpp +++ b/Tanks/Bullet.cpp @@ -179,4 +179,9 @@ void Bullet::init(std::string texturePath, std::string fireSoundPath, Sound* col void Bullet::render() { if(exist) texture.render(x, y, static_cast(dir)); +} + +void Bullet::clearButtonFlag() +{ + fireButtonPressed = false; } \ No newline at end of file diff --git a/Tanks/Bullet.h b/Tanks/Bullet.h index c7a77d6..97ae62c 100644 --- a/Tanks/Bullet.h +++ b/Tanks/Bullet.h @@ -16,10 +16,11 @@ class Bullet : public Object //Render bullet if exist virtual void render(); + virtual void reset(); void handleEvent(SDL_Event &e); - void reset(); void fire(Tank *tank, int delay); void move(); + void clearButtonFlag(); bool doesExist(); direction getDirection(); diff --git a/Tanks/Game.cpp b/Tanks/Game.cpp index 1aaec09..9457749 100644 --- a/Tanks/Game.cpp +++ b/Tanks/Game.cpp @@ -4,7 +4,6 @@ Game::Game() { window = nullptr; renderer = nullptr; - quit = true; initialize(); } @@ -12,15 +11,13 @@ Game::~Game() { freeDynamicAllocatedMemory(); - TTF_CloseFont(bigFont); - bigFont = nullptr; - TTF_CloseFont(normalFont); - normalFont = nullptr; + TTF_CloseFont(font72); + TTF_CloseFont(font48); + TTF_CloseFont(font24); + TTF_CloseFont(font18); SDL_DestroyRenderer(renderer); - renderer = nullptr; SDL_DestroyWindow(window); - window = nullptr; Mix_Quit(); TTF_Quit(); @@ -30,6 +27,7 @@ Game::~Game() void Game::freeDynamicAllocatedMemory() { + delete state; delete collisionSound; delete ui; @@ -51,42 +49,47 @@ void Game::freeDynamicAllocatedMemory() void Game::initialize() { - if (SDL_Init(SDL_INIT_EVERYTHING) < 0) return; + if (SDL_Init(SDL_INIT_EVERYTHING) < 0) State::setCurrentState(EXIT); //Set linear filtering SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1"); window = SDL_CreateWindow(("TANKS " + VERSION_NUMBER).c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN); - if (window == nullptr) return; + if (window == nullptr) State::setCurrentState(EXIT); renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); - if (renderer == nullptr) return; + if (renderer == nullptr) State::setCurrentState(EXIT); //Initialize PNG loading int imgFlags = IMG_INIT_PNG; - if (!(IMG_Init(imgFlags) & imgFlags)) return; + if (!(IMG_Init(imgFlags) & imgFlags)) State::setCurrentState(EXIT); //Initialize TrueTypeFont - if (TTF_Init() == -1) return; - - bigFont = TTF_OpenFont("fonts/TruenoRg.otf", 48); - if (bigFont == nullptr) return; + if (TTF_Init() == -1) State::setCurrentState(EXIT); - normalFont = TTF_OpenFont("fonts/TruenoRg.otf", 24); - if (normalFont == nullptr) return; + font72 = TTF_OpenFont("fonts/TruenoRg.otf", 72); + if (font72 == nullptr) State::setCurrentState(EXIT); + font48 = TTF_OpenFont("fonts/TruenoRg.otf", 48); + if (font48 == nullptr) State::setCurrentState(EXIT); + font24 = TTF_OpenFont("fonts/TruenoRg.otf", 24); + if (font24 == nullptr) State::setCurrentState(EXIT); + font18 = TTF_OpenFont("fonts/TruenoRg.otf", 18); + if (font18 == nullptr) State::setCurrentState(EXIT); //Initialize audio - if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 4096) < 0) return; - quit = false; + if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 4096) < 0) State::setCurrentState(EXIT); collisionSound = new Sound(); collisionSound->loadWAV("sounds/collision.wav"); //Set renderer for classes + State::setRenderer(renderer); Object::setRenderer(renderer); Texture::setRenderer(renderer); HpBar::setRenderer(renderer); + state = new TitleState(font48); + //Init static textures Bullet::init("images/bullet.png", "sounds/fire.wav", collisionSound); Tank::initTexture("images/tank.png"); @@ -108,90 +111,73 @@ void Game::loadMap() void Game::loadUI() { - ui = new UI(bigFont, normalFont); + ui = new UI(font48, font24); } void Game::run() { //Main loop - while (!quit) + while (State::getCurrentState() != EXIT) { - //Checking events - while (SDL_PollEvent(&e) != 0) - { - if (e.type == SDL_QUIT) quit = true; - else if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE) quit = true; - - bullet[0]->handleEvent(e); - tank[0]->handleEvent(e); - bullet[1]->handleEvent(e); - tank[1]->handleEvent(e); - } + state->handleEvents(e); + state->logic(); + changeState(); + state->render(); + } +} - tank[0]->setVelocity(); - tank[1]->setVelocity(); +bool Game::checkCollision(SDL_Rect a, SDL_Rect b) +{ + if (a.y >= b.y + b.h) return false; + if (a.y + a.h <= b.y) return false; + if (a.x >= b.x + b.w) return false; + if (a.x + a.w <= b.x) return false; - //Loop for every tank - for (int i = 0; i < static_cast(tank.size()); i++) - { - bullet[i]->fire(tank[i], 500); - bullet[i]->move(); - tank[i]->move(); + return true; +} - //Check tank with tank collision - if (checkCollision(tank[i]->getCollider(), tank[(i+1)%2]->getCollider())) tank[i]->undo(); +void Game::changeState() +{ + if (State::getNextState() != NONE) + { + if (State::getNextState() != EXIT) + delete state; - //Check bullet with tank collision - if (bullet[i]->doesExist() && checkCollision(bullet[i]->getCollider(), tank[(i+1)%2]->getCollider())) + switch (State::getNextState()) + { + case TITLE: { - tank[(i+1)%2]->decreaseHp(); - bullet[i]->reset(); - collisionSound->play(); - if (tank[(i+1)%2]->getHp() == 0) - { - tank[(i+1)%2]->respawn(); - tank[i]->increaseScore(); - } + state = new TitleState(font48); + break; } - - //Check collision with every piece of wall - for (int j = 0; j < static_cast(wall.size()); j++) + case GAME: { - if (wall[j]->doesExist() && checkCollision(tank[i]->getCollider(), wall[j]->getCollider())) tank[i]->undo(); - if (wall[j]->doesExist() && bullet[i]->doesExist() && checkCollision(bullet[i]->getCollider(), wall[j]->getCollider())) + state = new GameState(this); + + //This loop is needed to stop moving tank or firing bullet after state change + //Without it tank can move or fire without button pressed (after returning from menu state) + //It is caused by flags that cannot be changed after state change + //That is why it have to be manually set + for (int i = 0; i < static_cast(tank.size()); i++) { - if (wall[j]->isDestructable()) wall[j]->destroy(); - bullet[i]->reset(); - collisionSound->play(); + tank[i]->clearButtonFlags(); + bullet[i]->clearButtonFlag(); } + break; + } + case MENU: + { + state = new MenuState(font72, font48); + break; + } + case ABOUT: + { + state = new AboutState(VERSION_NUMBER, font72, font48, font24, font18); + break; } } - //Set current score - ui->setScore(tank[0]->getScore(), tank[1]->getScore()); - ui->setBar(tank[0]->getHp(), tank[1]->getHp()); - - render(); + State::setCurrentState(State::getNextState()); + State::setNextState(NONE); } -} - -void Game::render() -{ - //Clear window - SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); - SDL_RenderClear(renderer); - - Object::renderAll(); - - SDL_RenderPresent(renderer); -} - -bool Game::checkCollision(SDL_Rect a, SDL_Rect b) -{ - if (a.y >= b.y + b.h) return false; - if (a.y + a.h <= b.y) return false; - if (a.x >= b.x + b.w) return false; - if (a.x + a.w <= b.x) return false; - - return true; } \ No newline at end of file diff --git a/Tanks/Game.h b/Tanks/Game.h index ed512bf..699c6c2 100644 --- a/Tanks/Game.h +++ b/Tanks/Game.h @@ -14,6 +14,11 @@ #include "Sound.h" #include "MapLoader.h" #include "UI.h" +#include "State.h" +#include "TitleState.h" +#include "GameState.h" +#include "MenuState.h" +#include "AboutState.h" constexpr int MAP_WIDTH = 768; constexpr int MAP_HEIGHT = 768; @@ -22,7 +27,7 @@ constexpr int WALL_HEIGHT = 64; constexpr int SCREEN_WIDTH = 1024; constexpr int SCREEN_HEIGHT = 768; -const std::string VERSION_NUMBER = "v1.1.0"; +const std::string VERSION_NUMBER = "v1.2.0"; class HpBar; class Wall; @@ -45,20 +50,25 @@ class Game ~Game(); void run(); + friend class GameState; + friend class MenuState; + private: void initialize(); void loadMap(); void loadUI(); - void render(); void freeDynamicAllocatedMemory(); bool checkCollision(SDL_Rect a, SDL_Rect b); + void changeState(); SDL_Window *window; SDL_Renderer *renderer; SDL_Event e; - TTF_Font *bigFont; - TTF_Font *normalFont; - bool quit; + TTF_Font *font72; + TTF_Font *font48; + TTF_Font *font24; + TTF_Font *font18; + State *state; std::vector wall; std::vector tank; diff --git a/Tanks/GameState.cpp b/Tanks/GameState.cpp new file mode 100644 index 0000000..58dc187 --- /dev/null +++ b/Tanks/GameState.cpp @@ -0,0 +1,88 @@ +#include "GameState.h" + + + +GameState::GameState(Game *game) +{ + this->game = game; +} + + +GameState::~GameState() +{ +} + +void GameState::handleEvents(SDL_Event &e) +{ + while (SDL_PollEvent(&e)) + { + if (e.type == SDL_QUIT) + this->setNextState(EXIT); + else if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE) + this->setNextState(MENU); + + game->bullet[0]->handleEvent(e); + game->tank[0]->handleEvent(e); + game->bullet[1]->handleEvent(e); + game->tank[1]->handleEvent(e); + } +} + +void GameState::logic() +{ + game->tank[0]->setVelocity(); + game->tank[1]->setVelocity(); + + //Loop for every tank + for (int i = 0; i < static_cast(game->tank.size()); i++) + { + game->bullet[i]->fire(game->tank[i], 500); + game->bullet[i]->move(); + game->tank[i]->move(); + + //Check tank with tank collision + if (game->checkCollision(game->tank[i]->getCollider(), game->tank[(i + 1) % 2]->getCollider())) game->tank[i]->undo(); + + //Check bullet with tank collision + if (game->bullet[i]->doesExist() && game->checkCollision(game->bullet[i]->getCollider(), game->tank[(i + 1) % 2]->getCollider())) + { + game->tank[(i + 1) % 2]->decreaseHp(); + game->bullet[i]->reset(); + game->collisionSound->play(); + if (game->tank[(i + 1) % 2]->getHp() == 0) + { + game->tank[(i + 1) % 2]->respawn(); + game->tank[i]->increaseScore(); + } + } + + //Check collision with every piece of wall + for (int j = 0; j < static_cast(game->wall.size()); j++) + { + if (game->wall[j]->doesExist() && game->checkCollision(game->tank[i]->getCollider(), game->wall[j]->getCollider())) game->tank[i]->undo(); + if (game->wall[j]->doesExist() && game->bullet[i]->doesExist() && game->checkCollision(game->bullet[i]->getCollider(), game->wall[j]->getCollider())) + { + if (game->wall[j]->isDestructible()) + game->wall[j]->destroy(); + + game->bullet[i]->reset(); + game->collisionSound->play(); + } + } + } + + //Set current score + game->ui->setScore(game->tank[0]->getScore(), game->tank[1]->getScore()); + game->ui->setBar(game->tank[0]->getHp(), game->tank[1]->getHp()); +} + +void GameState::render() +{ + //Clear window + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + SDL_RenderClear(renderer); + + Object::renderAll(); + + SDL_RenderPresent(renderer); +} \ No newline at end of file diff --git a/Tanks/GameState.h b/Tanks/GameState.h new file mode 100644 index 0000000..bd8bc9d --- /dev/null +++ b/Tanks/GameState.h @@ -0,0 +1,18 @@ +#pragma once +#include "State.h" +#include "Game.h" + +class Game; + +class GameState : public State +{ +public: + GameState(Game *game); + ~GameState(); + virtual void handleEvents(SDL_Event &e); + virtual void logic(); + virtual void render(); +private: + Game *game; +}; + diff --git a/Tanks/MenuState.cpp b/Tanks/MenuState.cpp new file mode 100644 index 0000000..92728ff --- /dev/null +++ b/Tanks/MenuState.cpp @@ -0,0 +1,135 @@ +#include "MenuState.h" + + + +MenuState::MenuState(TTF_Font *font72, TTF_Font *font48) +{ + currentChoice = static_cast(Menu::RESUME); + returnPressed = false; + background = { menuBeginX - 50,menuBeginY - 160,320,400 }; + currentChoiceRect = { menuBeginX,menuBeginY+7,230,50 }; + + texture.push_back(new Texture(menuBeginX, menuBeginY)); + texture.push_back(new Texture(menuBeginX, menuBeginY + 50)); + texture.push_back(new Texture(menuBeginX, menuBeginY + 100)); + texture.push_back(new Texture(menuBeginX, menuBeginY + 150)); + texture.push_back(new Texture(menuBeginX, 200)); + + texture[static_cast(Menu::RESUME)]->loadText("RESUME", font48); + texture[static_cast(Menu::RESTART)]->loadText("RESTART", font48); + texture[static_cast(Menu::ABOUT)]->loadText("ABOUT", font48); + texture[static_cast(Menu::EXIT)]->loadText("EXIT", font48); + texture[static_cast(Menu::MENUTITLE)]->loadText("MENU", font72); +} + + +MenuState::~MenuState() +{ + for (int i = 0; i < static_cast(texture.size()); i++) + { + delete texture[i]; + } +} + +void MenuState::handleEvents(SDL_Event &e) +{ + while (SDL_PollEvent(&e)) + { + if (e.type == SDL_QUIT) + this->setNextState(EXIT); + else if (e.type == SDL_KEYDOWN) + { + switch (e.key.keysym.sym) + { + case SDLK_ESCAPE: + { + this->setNextState(GAME); + break; + } + case SDLK_UP: + { + currentChoice--; + break; + } + case SDLK_DOWN: + { + currentChoice++; + break; + } + case SDLK_RETURN: + { + returnPressed = true; + break; + } + } + } + } +} + +void MenuState::logic() +{ + //Correct current element when its out of range + if (currentChoice < 0) + currentChoice = menuElements - 1; + else if (currentChoice >= menuElements) + currentChoice = 0; + + if (returnPressed) + { + switch (currentChoice) + { + case (int)Menu::RESUME: + { + this->setNextState(GAME); + break; + } + case (int)Menu::RESTART: + { + this->setNextState(GAME); + Object::resetAll(); + break; + } + case (int)Menu::ABOUT: + { + this->setNextState(ABOUT); + break; + } + case (int)Menu::EXIT: + { + this->setNextState(EXIT); + break; + } + } + } + + //Change position of the rectangle + currentChoiceRect.y = menuBeginY + 7 + currentChoice * 50; +} + +void MenuState::render() +{ + //Clear window + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + SDL_RenderClear(renderer); + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + + Object::renderAll(); + + SDL_SetRenderDrawColor(renderer, 32, 32, 32, 255); + SDL_RenderFillRect(renderer, &background); + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + SDL_RenderDrawRect(renderer, &background); + + for (auto x : texture) + { + x->render(); + } + + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + SDL_RenderDrawLine(renderer, menuBeginX, 280, menuBeginX + 220, 280); + SDL_RenderDrawLine(renderer, menuBeginX, 283, menuBeginX + 220, 283); + SDL_RenderDrawLine(renderer, menuBeginX, 286, menuBeginX + 220, 286); + SDL_RenderDrawRect(renderer, ¤tChoiceRect); + + SDL_RenderPresent(renderer); +} \ No newline at end of file diff --git a/Tanks/MenuState.h b/Tanks/MenuState.h new file mode 100644 index 0000000..7b63c74 --- /dev/null +++ b/Tanks/MenuState.h @@ -0,0 +1,38 @@ +#pragma once +#include "State.h" +#include "Game.h" + +enum class Menu +{ + RESUME, + RESTART, + ABOUT, + EXIT, + MENUTITLE +}; + +class Game; + +class MenuState : public State +{ +public: + MenuState(TTF_Font *font72, TTF_Font *font48); + ~MenuState(); + + virtual void handleEvents(SDL_Event &e); + virtual void logic(); + virtual void render(); + +private: + std::vector texture; + SDL_Rect currentChoiceRect; + SDL_Rect background; + + int currentChoice; + bool returnPressed; + const int menuElements = 4; + + int menuBeginX = 400; + int menuBeginY = 350; +}; + diff --git a/Tanks/Object.cpp b/Tanks/Object.cpp index 6f0ab30..7f0de6f 100644 --- a/Tanks/Object.cpp +++ b/Tanks/Object.cpp @@ -24,4 +24,12 @@ void Object::renderAll() { x->render(); } +} + +void Object::resetAll() +{ + for (auto x : object) + { + x->reset(); + } } \ No newline at end of file diff --git a/Tanks/Object.h b/Tanks/Object.h index f1c7868..91bc331 100644 --- a/Tanks/Object.h +++ b/Tanks/Object.h @@ -6,11 +6,13 @@ class Object { public: Object(); - ~Object(); + virtual ~Object(); static void setRenderer(SDL_Renderer *r); static void renderAll(); + static void resetAll(); virtual void render() = 0; + virtual void reset() = 0; protected: int x, y, width, height; diff --git a/Tanks/State.cpp b/Tanks/State.cpp new file mode 100644 index 0000000..eb005f2 --- /dev/null +++ b/Tanks/State.cpp @@ -0,0 +1,30 @@ +#include "State.h" + +SDL_Renderer* State::renderer{}; +StateEnum State::currentState = TITLE; +StateEnum State::nextState = NONE; + +void State::setRenderer(SDL_Renderer *r) +{ + renderer = r; +} + +void State::setCurrentState(StateEnum arg) +{ + currentState = arg; +} + +void State::setNextState(StateEnum arg) +{ + nextState = arg; +} + +StateEnum State::getCurrentState() +{ + return currentState; +} + +StateEnum State::getNextState() +{ + return nextState; +} \ No newline at end of file diff --git a/Tanks/State.h b/Tanks/State.h new file mode 100644 index 0000000..3dbec9b --- /dev/null +++ b/Tanks/State.h @@ -0,0 +1,34 @@ +#pragma once +#include + +enum StateEnum +{ + NONE, + TITLE, + GAME, + MENU, + ABOUT, + EXIT +}; + +class State +{ +public: + virtual ~State() {}; + virtual void handleEvents(SDL_Event &e) = 0; + virtual void logic() = 0; + virtual void render() = 0; + + static void setRenderer(SDL_Renderer *r); + static void setCurrentState(StateEnum arg); + static void setNextState(StateEnum arg); + + static StateEnum getCurrentState(); + static StateEnum getNextState(); + +protected: + static SDL_Renderer *renderer; + static StateEnum currentState; + static StateEnum nextState; +}; + diff --git a/Tanks/Tank.cpp b/Tanks/Tank.cpp index 8303c4b..88ccb8a 100644 --- a/Tanks/Tank.cpp +++ b/Tanks/Tank.cpp @@ -9,7 +9,7 @@ Tank::Tank(int x, int y, direction d, int up, int down, int left, int right) { respawnX = x; respawnY = y; - respawn(); + reset(); width = 60; height = 60; @@ -22,18 +22,13 @@ Tank::Tank(int x, int y, direction d, int up, int down, int left, int right) dir = d; - score = 0; - //Set steering keys this->up = up; this->down = down; this->left = left; this->right = right; - upButtonPressed = false; - downButtonPressed = false; - leftButtonPressed = false; - rightButtonPressed = false; + clearButtonFlags(); upTicks = 0; downTicks = 0; @@ -169,6 +164,12 @@ void Tank::respawn() hp = maxHp; } +void Tank::reset() +{ + respawn(); + score = 0; +} + int Tank::getX() { return x; @@ -232,4 +233,12 @@ void Tank::initTexture(std::string path) void Tank::render() { texture.render(x, y, static_cast(dir)); +} + +void Tank::clearButtonFlags() +{ + upButtonPressed = false; + downButtonPressed = false; + leftButtonPressed = false; + rightButtonPressed = false; } \ No newline at end of file diff --git a/Tanks/Tank.h b/Tanks/Tank.h index e128d85..fdba05c 100644 --- a/Tanks/Tank.h +++ b/Tanks/Tank.h @@ -14,12 +14,14 @@ class Tank : public Object static int getMaxHp(); virtual void render(); + virtual void reset(); void handleEvent(SDL_Event &e); void move(); void undo(); void respawn(int x, int y); void respawn(); void setVelocity(); + void clearButtonFlags(); int getX(); int getY(); diff --git a/Tanks/Tanks.vcxproj b/Tanks/Tanks.vcxproj index 34c0337..4db6930 100644 --- a/Tanks/Tanks.vcxproj +++ b/Tanks/Tanks.vcxproj @@ -86,7 +86,7 @@ SDL2.lib;SDL2main.lib;SDL2_image.lib;SDL2_mixer.lib;SDL2_ttf.lib;%(AdditionalDependencies) - Windows + Console @@ -128,30 +128,43 @@ + + + + + + + + + + + + + diff --git a/Tanks/Tanks.vcxproj.filters b/Tanks/Tanks.vcxproj.filters index c8fbb8d..1806894 100644 --- a/Tanks/Tanks.vcxproj.filters +++ b/Tanks/Tanks.vcxproj.filters @@ -1,84 +1,131 @@  - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - + {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;ipp;xsd - + + {777a1a18-4c88-45a0-8cc6-dcce0457213b} + + + {445d7475-5c92-4da6-b08b-3dd395eb017b} + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {3634a274-ff85-488f-ac04-26b1d5a55aaa} + + + {259bddab-59f6-4f34-b82d-0e26a8f6af12} + - - Pliki nagłówkowe - - Pliki nagłówkowe + Header Files - Pliki nagłówkowe + Header Files - Pliki nagłówkowe - - - Pliki nagłówkowe + Header Files - Pliki nagłówkowe + Header Files - - Pliki nagłówkowe + + Header Files + + + Header Files\StateMachine + + + Header Files\StateMachine + + + Header Files\StateMachine + + + Header Files\Objects - Pliki nagłówkowe + Header Files\Objects - - Pliki nagłówkowe + + Header Files\Objects - Pliki nagłówkowe + Header Files\Objects + + + Header Files\Objects + + + Header Files + + + Header Files\StateMachine - - Pliki źródłowe - - Pliki źródłowe + Source Files - Pliki źródłowe + Source Files - Pliki źródłowe + Source Files - Pliki źródłowe - - - Pliki źródłowe + Source Files - Pliki źródłowe + Source Files - - Pliki źródłowe + + Source Files - - Pliki źródłowe + + Source Files\StateMachine - - Pliki źródłowe + + Source Files\StateMachine + + + Source Files\StateMachine + + + Source Files\Objects + + + Source Files\Objects - Pliki źródłowe + Source Files\Objects + + + Source Files\Objects + + Source Files\Objects + + + Source Files + + + Source Files\StateMachine + + + + + Resource Files + \ No newline at end of file diff --git a/Tanks/TitleState.cpp b/Tanks/TitleState.cpp new file mode 100644 index 0000000..61e32e5 --- /dev/null +++ b/Tanks/TitleState.cpp @@ -0,0 +1,46 @@ +#include "TitleState.h" + + + +TitleState::TitleState(TTF_Font *font) +{ + background = new Texture(); + background->loadPNG("images/title.png"); + + info = new Texture(); + info->loadText("Press any key to start", font); + info->setPosition(250, 550); +} + + +TitleState::~TitleState() +{ + delete background; + delete info; +} + +void TitleState::handleEvents(SDL_Event &e) +{ + while (SDL_PollEvent(&e)) + { + if (e.type == SDL_QUIT) + this->setNextState(EXIT); + else if (e.type == SDL_KEYDOWN) + this->setNextState(GAME); + } +} + +void TitleState::logic() {} + +void TitleState::render() +{ + //Clear window + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + SDL_RenderClear(renderer); + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + + background->render(); + info->render(); + + SDL_RenderPresent(renderer); +} \ No newline at end of file diff --git a/Tanks/TitleState.h b/Tanks/TitleState.h new file mode 100644 index 0000000..c196410 --- /dev/null +++ b/Tanks/TitleState.h @@ -0,0 +1,19 @@ +#pragma once +#include "State.h" +#include "Texture.h" + +class Texture; + +class TitleState : public State +{ +public: + TitleState(TTF_Font *font); + ~TitleState(); + virtual void handleEvents(SDL_Event &e); + virtual void logic(); + virtual void render(); +private: + Texture *background; + Texture *info; +}; + diff --git a/Tanks/UI.cpp b/Tanks/UI.cpp index c307b83..36d633b 100644 --- a/Tanks/UI.cpp +++ b/Tanks/UI.cpp @@ -25,16 +25,15 @@ UI::UI(TTF_Font *bigFont, TTF_Font *normalFont) texture.push_back(new Texture(786, 200)); texture.push_back(new Texture(786, 587)); - texture[static_cast(textureUI::PLAYER1)]->loadText("PLAYER 1", bigFont); - texture[static_cast(textureUI::PLAYER2)]->loadText("PLAYER 2", bigFont); - texture[static_cast(textureUI::PLAYER1MOVE)]->loadText("Move: arrows", normalFont); - texture[static_cast(textureUI::PLAYER2MOVE)]->loadText("Move: W S A D", normalFont); - texture[static_cast(textureUI::PLAYER1FIRE)]->loadText("Fire: RETURN", normalFont); - texture[static_cast(textureUI::PLAYER2FIRE)]->loadText("Fire: SPACE", normalFont); - texture[static_cast(textureUI::HP1)]->loadText("HP:", normalFont); - texture[static_cast(textureUI::HP2)]->loadText("HP:", normalFont); - texture[static_cast(textureUI::SCORETANK1)]->loadText("SCORE: 0", normalFont); - texture[static_cast(textureUI::SCORETANK2)]->loadText("SCORE: 0", normalFont); + texture[static_cast(TextureUI::PLAYER1)]->loadText("PLAYER 1", bigFont); + texture[static_cast(TextureUI::PLAYER2)]->loadText("PLAYER 2", bigFont); + texture[static_cast(TextureUI::PLAYER1MOVE)]->loadText("Move: arrows", normalFont); + texture[static_cast(TextureUI::PLAYER2MOVE)]->loadText("Move: W S A D", normalFont); + texture[static_cast(TextureUI::PLAYER1FIRE)]->loadText("Fire: RETURN", normalFont); + texture[static_cast(TextureUI::PLAYER2FIRE)]->loadText("Fire: SPACE", normalFont); + texture[static_cast(TextureUI::HP1)]->loadText("HP:", normalFont); + texture[static_cast(TextureUI::HP2)]->loadText("HP:", normalFont); + reset(); bar1 = new HpBar(Tank::getMaxHp(), 150, 30, 836, 157); bar2 = new HpBar(Tank::getMaxHp(), 150, 30, 836, 544); @@ -71,6 +70,12 @@ void UI::render() bar2->render(); } +void UI::reset() +{ + texture[static_cast(TextureUI::SCORETANK1)]->loadText("SCORE: 0", normalFont); + texture[static_cast(TextureUI::SCORETANK2)]->loadText("SCORE: 0", normalFont); +} + void UI::setBar(int player1, int player2) { bar1->setHp(player1); @@ -81,6 +86,6 @@ void UI::setScore(int player1, int player2) { score1 = "SCORE: " + std::to_string(player1); score2 = "SCORE: " + std::to_string(player2); - texture[static_cast(textureUI::SCORETANK1)]->loadText(score1.c_str(), normalFont); - texture[static_cast(textureUI::SCORETANK2)]->loadText(score2.c_str(), normalFont); + texture[static_cast(TextureUI::SCORETANK1)]->loadText(score1.c_str(), normalFont); + texture[static_cast(TextureUI::SCORETANK2)]->loadText(score2.c_str(), normalFont); } \ No newline at end of file diff --git a/Tanks/UI.h b/Tanks/UI.h index f4cd3f8..6a0c3bd 100644 --- a/Tanks/UI.h +++ b/Tanks/UI.h @@ -1,7 +1,7 @@ #pragma once #include "Game.h" -enum class textureUI +enum class TextureUI { PLAYER1, PLAYER2, @@ -24,6 +24,7 @@ class UI : public Object ~UI(); virtual void render(); + virtual void reset(); void setBar(int player1, int player2); void setScore(int player1, int player2); diff --git a/Tanks/Wall.cpp b/Tanks/Wall.cpp index 1298dca..54c61fb 100644 --- a/Tanks/Wall.cpp +++ b/Tanks/Wall.cpp @@ -3,14 +3,14 @@ Texture Wall::wallTexture{}; Texture Wall::solidWallTexture{}; -Wall::Wall(int x, int y, bool destructable) +Wall::Wall(int x, int y, bool destructible) { width = WALL_WIDTH; height = WALL_HEIGHT; this->x = x; this->y = y; - this->destructable = destructable; + this->destructible = destructible; exist = true; //Set collider box @@ -35,7 +35,7 @@ void Wall::render() { if (exist) { - if (destructable) wallTexture.render(x, y); + if (destructible) wallTexture.render(x, y); else solidWallTexture.render(x, y); } } @@ -60,12 +60,17 @@ void Wall::destroy() exist = false; } +void Wall::reset() +{ + exist = true; +} + SDL_Rect Wall::getCollider() { return collider; } -bool Wall::isDestructable() +bool Wall::isDestructible() { - return destructable; + return destructible; } \ No newline at end of file diff --git a/Tanks/Wall.h b/Tanks/Wall.h index ccc7566..5a1d533 100644 --- a/Tanks/Wall.h +++ b/Tanks/Wall.h @@ -4,23 +4,24 @@ class Wall : public Object { public: - Wall(int x, int y, bool destructable = true); + Wall(int x, int y, bool destructible = true); ~Wall(); static void initTextures(std::string wallTexturePath, std::string solidWallTexturePath); virtual void render(); + virtual void reset(); void destroy(); int getX(); int getY(); bool doesExist(); - bool isDestructable(); + bool isDestructible(); SDL_Rect getCollider(); private: bool exist; - bool destructable; + bool destructible; SDL_Rect collider; static Texture wallTexture; diff --git a/Tanks/images/title.png b/Tanks/images/title.png new file mode 100644 index 0000000000000000000000000000000000000000..f5d909b41b79540b55f3dd0ec25fd1032464b66a GIT binary patch literal 46577 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 literal 0 HcmV?d00001 diff --git a/Tanks/main.cpp b/Tanks/main.cpp index d8016fd..a276c41 100644 --- a/Tanks/main.cpp +++ b/Tanks/main.cpp @@ -3,7 +3,9 @@ int main(int argc, char* argv[]) { - Game game; - game.run(); + Game *game = new Game(); + game->run(); + delete game; + return 0; } \ No newline at end of file diff --git a/Tanks/map.txt b/Tanks/map.txt index 03b87f0..4461600 100644 --- a/Tanks/map.txt +++ b/Tanks/map.txt @@ -1,4 +1,4 @@ -v X X +> X X X X XX X X XX X#X X @@ -9,4 +9,4 @@ v X X X X X X#X X XX X X XX - X X < \ No newline at end of file + X X ^ \ No newline at end of file