diff --git a/.gitignore b/.gitignore index 50ca99b..e12a977 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ -.idea/**/workspace.xml -.idea/**/tasks.xml +.idea/** /cmake-build-*/ diff --git a/CMakeLists.txt b/CMakeLists.txt index b6c9ede..fae5755 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,20 +1,55 @@ cmake_minimum_required(VERSION 3.6) + project(TowerDefense) +project(server) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME} src/main.cpp src/Game.cpp src/Game.h src/ResourceManager/ResourcesHolder.h +add_executable(server src/server_main.cpp + src/GameOverState.h src/GameOverState.cpp src/WinState.cpp src/WinState.h + src/Game.cpp src/Game.h src/ResourceManager/ResourcesHolder.h + src/ResourceManager/ResourcesIdentifier.h src/Graphics/Button.cpp src/Graphics/Button.h src/GameContext.h + src/GameState.cpp src/GameState.h src/GameStates.h src/Graphics/Gui.cpp src/Graphics/Gui.h src/Graphics/HUD.cpp src/Graphics/HUD.h + src/Graphics/Icon.h src/Graphics/Icon.cpp src/Graphics/Label.cpp src/Graphics/Label.h src/MenuState.cpp src/MenuState.h + src/PauseState.cpp src/PauseState.h src/State.cpp src/State.h src/StateManager.cpp + src/StateManager.h src/Graphics/Widget.h src/Map.h src/Map.cpp src/Constants.h src/Tile.h src/Tile.cpp + src/Units/Warrior/Warrior.cpp src/Units/Warrior/Warrior.h src/Units/Warrior/WarriorLvlOne.cpp + src/Units/Warrior/WarriorLvlOne.h + src/Units/Warrior/WarriorLvlTwo.cpp src/Units/Warrior/WarriorLvlTwo.h src/Units/Tower/Tower.cpp src/Units/Tower/Tower.h + src/Units/GameUnit.cpp src/Units/GameUnit.h src/Units/Tower/TowerLvlZero.cpp src/Units/Tower/TowerLvlZero.h + src/Units/Tower/TowerLvlOne.cpp src/Units/Tower/TowerLvlOne.h src/Units/Tower/TowerLvlTwo.cpp src/Units/Tower/TowerLvlTwo.h + src/Units/Bullet/Bullet.cpp src/Units/Bullet/Bullet.h src/Units/Bullet/BulletLvlOne.cpp src/Units/Bullet/BulletLvlOne.h + src/Units/Bullet/BulletLvlTwo.h src/Units/Bullet/BulletLvlTwo.cpp src/Units/Tower/TowerLvlThree.cpp src/Units/Tower/TowerLvlThree.h + src/Graphics/TextBox.h src/Graphics/TextBox.cpp src/ConnectGameState.h src/ConnectGameState.cpp + src/Units/Bullet/BulletLvlTwo.h src/Units/Bullet/BulletLvlTwo.cpp src/Units/Tower/TowerLvlThree.cpp src/Units/Tower/TowerLvlThree.h src/Castle/Castle.cpp src/Castle/Castle.h src/Castle/Building/Building.cpp src/Castle/Building/Building.h src/Castle/Building/Farm.cpp src/Castle/Building/Farm.h src/Castle/Building/Barracks.cpp src/Castle/Building/Barracks.h src/Castle/Building/Weapons.cpp src/Castle/Building/Weapons.h + src/Graphics/GraphicsUnits/GraphicsCastle.cpp src/Graphics/GraphicsUnits/GraphicsCastle.h src/Graphics/GraphicsUnits/GraphicsTower.cpp src/Graphics/GraphicsUnits/GraphicsTower.h src/Graphics/GraphicsUnits/GraphicsWarrior.cpp src/Graphics/GraphicsUnits/GraphicsWarrior.h src/Graphics/GraphicsUnits/GraphicsBullet.cpp src/Graphics/GraphicsUnits/GraphicsBullet.h src/Units/Bullet/BulletLvlThree.cpp src/Units/Bullet/BulletLvlThree.h src/Graphics/GraphicsUnits/GraphicsUnitManager.cpp src/Graphics/GraphicsUnits/GraphicsUnitManager.h src/Units/LogicUnitsManager.cpp src/Units/LogicUnitsManager.h src/GameConstants.cpp src/GameConstants.h + src/Multiplayer/MultiplayerFacade/AbstractMultiplayerFacade.cpp src/Multiplayer/MultiplayerFacade/AbstractMultiplayerFacade.h src/Multiplayer/MultiplayerFacade/ClientMultiplayerFacade.cpp src/Multiplayer/MultiplayerFacade/ClientMultiplayerFacade.h src/Multiplayer/MultiplayerFacade/ServerMultiplayerFacade.cpp src/Multiplayer/MultiplayerFacade/ServerMultiplayerFacade.h src/Multiplayer/ConnectionFacade/AbstractConnectionFacade.cpp src/Multiplayer/ConnectionFacade/AbstractConnectionFacade.h src/Multiplayer/ConnectionFacade/ServerConnectionFacade.cpp src/Multiplayer/ConnectionFacade/ServerConnectionFacade.h src/Multiplayer/ConnectionFacade/ClientConnectionFacade.cpp src/Multiplayer/ConnectionFacade/ClientConnectionFacade.h src/Multiplayer/Entities/Event.cpp src/Multiplayer/Entities/Event.h src/Multiplayer/Entities/Entity.cpp src/Multiplayer/Entities/Entity.h src/Multiplayer/Entities/Player.cpp src/Multiplayer/Entities/Player.h src/Multiplayer/Entities/Game.cpp src/Multiplayer/Entities/Game.h src/Multiplayer/Manager/Manager.cpp src/Multiplayer/Manager/Manager.h src/Multiplayer/Manager/PlayerManager.cpp src/Multiplayer/Manager/PlayerManager.h src/Multiplayer/Worker.cpp src/Multiplayer/Worker.h src/Multiplayer/Master.cpp src/Multiplayer/Master.h) + + +add_executable(TowerDefense src/main.cpp src/GameOverState.h src/GameOverState.cpp src/WinState.cpp src/WinState.h src/Game.cpp src/Game.h src/ResourceManager/ResourcesHolder.h src/ResourceManager/ResourcesIdentifier.h src/Graphics/Button.cpp src/Graphics/Button.h src/GameContext.h src/GameState.cpp src/GameState.h src/GameStates.h src/Graphics/Gui.cpp src/Graphics/Gui.h src/Graphics/HUD.cpp src/Graphics/HUD.h src/Graphics/Icon.h src/Graphics/Icon.cpp src/Graphics/Label.cpp src/Graphics/Label.h src/MenuState.cpp src/MenuState.h src/PauseState.cpp src/PauseState.h src/State.cpp src/State.h src/StateManager.cpp - src/StateManager.h src/Graphics/Widget.h) + src/StateManager.h src/Graphics/Widget.h src/Map.h src/Map.cpp src/Constants.h src/Tile.h src/Tile.cpp + src/Units/Warrior/Warrior.cpp src/Units/Warrior/Warrior.h src/Units/Warrior/WarriorLvlOne.cpp + src/Units/Warrior/WarriorLvlOne.h + src/Units/Warrior/WarriorLvlTwo.cpp src/Units/Warrior/WarriorLvlTwo.h src/Units/Tower/Tower.cpp src/Units/Tower/Tower.h + src/Units/GameUnit.cpp src/Units/GameUnit.h src/Units/Tower/TowerLvlZero.cpp src/Units/Tower/TowerLvlZero.h + src/Units/Tower/TowerLvlOne.cpp src/Units/Tower/TowerLvlOne.h src/Units/Tower/TowerLvlTwo.cpp src/Units/Tower/TowerLvlTwo.h + src/Units/Bullet/Bullet.cpp src/Units/Bullet/Bullet.h src/Units/Bullet/BulletLvlOne.cpp src/Units/Bullet/BulletLvlOne.h + src/Units/Bullet/BulletLvlTwo.h src/Units/Bullet/BulletLvlTwo.cpp src/Units/Tower/TowerLvlThree.cpp src/Units/Tower/TowerLvlThree.h + src/Graphics/TextBox.h src/Graphics/TextBox.cpp src/ConnectGameState.h src/ConnectGameState.cpp + src/Units/Bullet/BulletLvlTwo.h src/Units/Bullet/BulletLvlTwo.cpp src/Units/Tower/TowerLvlThree.cpp src/Units/Tower/TowerLvlThree.h src/Castle/Castle.cpp src/Castle/Castle.h src/Castle/Building/Building.cpp src/Castle/Building/Building.h src/Castle/Building/Farm.cpp src/Castle/Building/Farm.h src/Castle/Building/Barracks.cpp src/Castle/Building/Barracks.h src/Castle/Building/Weapons.cpp src/Castle/Building/Weapons.h + src/Graphics/GraphicsUnits/GraphicsCastle.cpp src/Graphics/GraphicsUnits/GraphicsCastle.h src/Graphics/GraphicsUnits/GraphicsTower.cpp src/Graphics/GraphicsUnits/GraphicsTower.h src/Graphics/GraphicsUnits/GraphicsWarrior.cpp src/Graphics/GraphicsUnits/GraphicsWarrior.h src/Graphics/GraphicsUnits/GraphicsBullet.cpp src/Graphics/GraphicsUnits/GraphicsBullet.h src/Units/Bullet/BulletLvlThree.cpp src/Units/Bullet/BulletLvlThree.h src/Graphics/GraphicsUnits/GraphicsUnitManager.cpp src/Graphics/GraphicsUnits/GraphicsUnitManager.h src/Units/LogicUnitsManager.cpp src/Units/LogicUnitsManager.h src/GameConstants.cpp src/GameConstants.h + src/Multiplayer/MultiplayerFacade/AbstractMultiplayerFacade.cpp src/Multiplayer/MultiplayerFacade/AbstractMultiplayerFacade.h src/Multiplayer/MultiplayerFacade/ClientMultiplayerFacade.cpp src/Multiplayer/MultiplayerFacade/ClientMultiplayerFacade.h src/Multiplayer/MultiplayerFacade/ServerMultiplayerFacade.cpp src/Multiplayer/MultiplayerFacade/ServerMultiplayerFacade.h src/Multiplayer/ConnectionFacade/AbstractConnectionFacade.cpp src/Multiplayer/ConnectionFacade/AbstractConnectionFacade.h src/Multiplayer/ConnectionFacade/ServerConnectionFacade.cpp src/Multiplayer/ConnectionFacade/ServerConnectionFacade.h src/Multiplayer/ConnectionFacade/ClientConnectionFacade.cpp src/Multiplayer/ConnectionFacade/ClientConnectionFacade.h src/Multiplayer/Entities/Event.cpp src/Multiplayer/Entities/Event.h src/Multiplayer/Entities/Entity.cpp src/Multiplayer/Entities/Entity.h src/Multiplayer/Entities/Player.cpp src/Multiplayer/Entities/Player.h src/Multiplayer/Entities/Game.cpp src/Multiplayer/Entities/Game.h src/Multiplayer/Manager/Manager.cpp src/Multiplayer/Manager/Manager.h src/Multiplayer/Manager/PlayerManager.cpp src/Multiplayer/Manager/PlayerManager.h src/Multiplayer/Worker.cpp src/Multiplayer/Worker.h src/Multiplayer/Master.cpp src/Multiplayer/Master.h) -SET (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/") +SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/") FIND_PACKAGE(SFML 2 REQUIRED system window graphics network audio) #INCLUDE(FindPkgConfig) #PKG_SEARCH_MODULE(SFML REQUIRED sfml) INCLUDE_DIRECTORIES(${SFML_INCLUDE_DIR}) -TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${SFML_LIBRARIES}) +TARGET_LINK_LIBRARIES(server ${SFML_LIBRARIES}) +TARGET_LINK_LIBRARIES(TowerDefense ${SFML_LIBRARIES}) file(COPY Resources DESTINATION .) \ No newline at end of file diff --git a/README.md b/README.md index ddd9be7..33039c0 100644 --- a/README.md +++ b/README.md @@ -10,15 +10,3 @@ Константин Митраков github.com/ConstaConst Сергей Ломачев github.com/Silvman - -Илья Тюнькин github.com/tyunkinilya - -

Напоминание команде:

- -Создайте свои ветки! - -Если кто-то раньше с этим не сталкивался, то вот неплохая шпаргалка: -https://git-scm.com/book/ru/v1/Ветвление-в-Git-Основы-ветвления-и-слияния -Если пользуетесь GitHub Desktop, то там это делается достаточно просто: -сверху есть кнопочка с разветвлением, нажимаем на неё и называем ветку своей фамилией. -
diff --git a/Resources/BlueCastle.png b/Resources/BlueCastle.png new file mode 100644 index 0000000..1d85387 Binary files /dev/null and b/Resources/BlueCastle.png differ diff --git a/Resources/RedCastle.png b/Resources/RedCastle.png new file mode 100644 index 0000000..7387361 Binary files /dev/null and b/Resources/RedCastle.png differ diff --git a/Resources/addBarraks.png b/Resources/addBarraks.png new file mode 100644 index 0000000..7c65ca8 Binary files /dev/null and b/Resources/addBarraks.png differ diff --git a/Resources/addFarm.png b/Resources/addFarm.png new file mode 100644 index 0000000..844a7cf Binary files /dev/null and b/Resources/addFarm.png differ diff --git a/Resources/addWarrior.png b/Resources/addWarrior.png new file mode 100644 index 0000000..e440548 Binary files /dev/null and b/Resources/addWarrior.png differ diff --git a/Resources/addWarriorOne.png b/Resources/addWarriorOne.png new file mode 100644 index 0000000..3da0a85 Binary files /dev/null and b/Resources/addWarriorOne.png differ diff --git a/Resources/addWeapons.png b/Resources/addWeapons.png new file mode 100644 index 0000000..2ac66f6 Binary files /dev/null and b/Resources/addWeapons.png differ diff --git a/Resources/audioOff.png b/Resources/audioOff.png old mode 100755 new mode 100644 diff --git a/Resources/audioOn.png b/Resources/audioOn.png old mode 100755 new mode 100644 diff --git a/Resources/barraks.png b/Resources/barraks.png new file mode 100644 index 0000000..9c77879 Binary files /dev/null and b/Resources/barraks.png differ diff --git a/Resources/blood.png b/Resources/blood.png new file mode 100644 index 0000000..6620a9f Binary files /dev/null and b/Resources/blood.png differ diff --git a/Resources/blueTarget.png b/Resources/blueTarget.png new file mode 100644 index 0000000..87919b2 Binary files /dev/null and b/Resources/blueTarget.png differ diff --git a/Resources/bulletThree.png b/Resources/bulletThree.png new file mode 100644 index 0000000..83ffbae Binary files /dev/null and b/Resources/bulletThree.png differ diff --git a/Resources/bulletTwo.png b/Resources/bulletTwo.png index 83ffbae..510e2b6 100644 Binary files a/Resources/bulletTwo.png and b/Resources/bulletTwo.png differ diff --git a/Resources/button.png b/Resources/button.png old mode 100755 new mode 100644 index 4cd391f..bf3c933 Binary files a/Resources/button.png and b/Resources/button.png differ diff --git a/Resources/click4.wav b/Resources/click4.wav old mode 100755 new mode 100644 diff --git a/Resources/cursor.png b/Resources/cursor.png old mode 100755 new mode 100644 diff --git a/Resources/decoration.csv b/Resources/decoration.csv index 062d578..174948b 100644 --- a/Resources/decoration.csv +++ b/Resources/decoration.csv @@ -1,12 +1,12 @@ -3,2,1,3,4,2,0,6,0,0,0,0,0,0,0, -1,1,4,2,4,2,0,0,0,1,0,4,0,0,0, -3,2,2,4,1,0,0,2,0,0,0,0,0,0,0, -3,2,3,1,0,0,0,0,0,0,0,2,0,0,0, -1,3,4,0,0,0,0,0,0,0,0,0,0,0,0, -2,1,2,0,0,0,0,0,5,0,4,0,0,0,0, -4,3,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,3,0,0,0, -0,0,0,0,0,0,0,0,0,4,0,0,0,0,0, -0,0,0,2,2,0,6,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,1,0,7,0,4,0,0,0,0,0,0,4, \ No newline at end of file +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file diff --git a/Resources/diamond.png b/Resources/diamond.png old mode 100755 new mode 100644 diff --git a/Resources/exit.png b/Resources/exit.png old mode 100755 new mode 100644 diff --git a/Resources/explosionOne.png b/Resources/explosionOne.png new file mode 100644 index 0000000..c3dce2b Binary files /dev/null and b/Resources/explosionOne.png differ diff --git a/Resources/explosion.png b/Resources/explosionThree.png similarity index 100% rename from Resources/explosion.png rename to Resources/explosionThree.png diff --git a/Resources/explosionTwo.png b/Resources/explosionTwo.png new file mode 100644 index 0000000..460cb74 Binary files /dev/null and b/Resources/explosionTwo.png differ diff --git a/Resources/farm.png b/Resources/farm.png new file mode 100644 index 0000000..67601af Binary files /dev/null and b/Resources/farm.png differ diff --git a/Resources/fastForward.mp3 b/Resources/fastForward.mp3 index b9b8422..e69de29 100644 Binary files a/Resources/fastForward.mp3 and b/Resources/fastForward.mp3 differ diff --git a/Resources/fastForward.wav b/Resources/fastForward.wav index 9736c97..e69de29 100644 Binary files a/Resources/fastForward.wav and b/Resources/fastForward.wav differ diff --git a/Resources/fastForwardOff.png b/Resources/fastForwardOff.png old mode 100755 new mode 100644 diff --git a/Resources/fastForwardOn.png b/Resources/fastForwardOn.png old mode 100755 new mode 100644 diff --git a/Resources/fight.png b/Resources/fight.png old mode 100755 new mode 100644 diff --git a/Resources/forwardOff.png b/Resources/forwardOff.png old mode 100755 new mode 100644 diff --git a/Resources/forwardOn.png b/Resources/forwardOn.png old mode 100755 new mode 100644 diff --git a/Resources/grey_panel.png b/Resources/grey_panel.png old mode 100755 new mode 100644 diff --git a/Resources/heart.png b/Resources/heart.png old mode 100755 new mode 100644 diff --git a/Resources/hexagonVector_objects.svg b/Resources/hexagonVector_objects.svg new file mode 100755 index 0000000..4681873 --- /dev/null +++ b/Resources/hexagonVector_objects.svg @@ -0,0 +1,1149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Resources/hexagonVector_objects.swf b/Resources/hexagonVector_objects.swf new file mode 100755 index 0000000..8453505 Binary files /dev/null and b/Resources/hexagonVector_objects.swf differ diff --git a/Resources/iconSheet.png b/Resources/iconSheet.png old mode 100755 new mode 100644 diff --git a/Resources/logo.png b/Resources/logo.png new file mode 100644 index 0000000..9d52bcf Binary files /dev/null and b/Resources/logo.png differ diff --git a/Resources/map.csv b/Resources/map.csv old mode 100755 new mode 100644 index 547b624..c918b9e --- a/Resources/map.csv +++ b/Resources/map.csv @@ -1,12 +1,20 @@ -16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, -16,16,16,16,16,16,16,16,16,16,16,16,3 ,31,31, -16,16,16,16,16,16,16,16,16,16,16,16,17, 0 ,1 , -16,16,16,16,16,16,16,16,16,16,16,16,17,15,16, -16,16,16,16,3 ,31,31,31,4 ,16,16,16,17,15,16, -16,16,16,16,17,0 ,1 ,2 ,15,16,16,16,17,15,16, -16,16,16,16,17,15,16,17,15,16,16,16,17,15,16, -16,3 ,31,31,32,15,16,17,15,16,16,16,17,15,16, -16,17,0 ,1 ,1 ,19,16,17,15,16,16,16,17,15,16, -16,17,15,16,16,16,16,17,30,31,31,31,32,15,16, -16,17,15,16,16,16,16,18,1 ,1 ,1 ,1 ,1 ,19 ,16, -16,17,15,16,16,16,16,16,16,16,16,16,16,16,16 +2 +12 19 + +16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 +3 31 31 31 4 16 3 31 31 31 31 4 16 16 3 31 31 31 4 +17 0 1 2 15 14 17 0 1 1 2 15 16 16 17 0 1 2 15 +17 15 16 17 30 31 32 15 14 14 17 15 14 14 17 15 16 17 15 +16 16 16 18 1 1 1 19 16 16 17 30 31 31 32 15 16 16 16 +16 16 16 16 14 13 14 16 16 16 18 1 1 1 1 19 16 16 16 + +16 16 16 3 31 31 31 31 4 16 16 16 13 14 13 16 16 16 16 +16 16 16 17 0 1 1 2 15 16 16 3 31 31 31 4 16 16 16 +17 15 16 17 15 13 13 17 15 13 13 17 0 1 2 15 16 17 15 +17 30 31 32 15 16 16 17 30 31 31 32 15 13 17 30 31 32 15 +18 1 1 1 19 16 16 18 1 1 1 1 19 16 18 1 1 1 19 +16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 + +3 0 + +8 17 diff --git a/Resources/map.png b/Resources/map.png old mode 100755 new mode 100644 diff --git a/Resources/map1.png b/Resources/map1.png old mode 100755 new mode 100644 diff --git a/Resources/musicOff.png b/Resources/musicOff.png old mode 100755 new mode 100644 diff --git a/Resources/musicOn.png b/Resources/musicOn.png old mode 100755 new mode 100644 diff --git a/Resources/panel.png b/Resources/panel.png old mode 100755 new mode 100644 diff --git a/Resources/pauseOff.png b/Resources/pauseOff.png old mode 100755 new mode 100644 diff --git a/Resources/pauseOn.png b/Resources/pauseOn.png old mode 100755 new mode 100644 diff --git a/Resources/redTarget.png b/Resources/redTarget.png new file mode 100644 index 0000000..e657c8d Binary files /dev/null and b/Resources/redTarget.png differ diff --git a/Resources/star.png b/Resources/star.png old mode 100755 new mode 100644 diff --git a/Resources/tank_explosion3.png b/Resources/tank_explosion3.png deleted file mode 100644 index 71ce43b..0000000 Binary files a/Resources/tank_explosion3.png and /dev/null differ diff --git a/Resources/target.png b/Resources/target.png old mode 100755 new mode 100644 index a33c2ee..46bb1b3 Binary files a/Resources/target.png and b/Resources/target.png differ diff --git a/Resources/towerOneBase.png b/Resources/towerOneBase.png old mode 100755 new mode 100644 diff --git a/Resources/towerOneTop.png b/Resources/towerOneTop.png old mode 100755 new mode 100644 diff --git a/Resources/towerThreeBase.png b/Resources/towerThreeBase.png new file mode 100644 index 0000000..c60b8f5 Binary files /dev/null and b/Resources/towerThreeBase.png differ diff --git a/Resources/towerTopTwo.png b/Resources/towerThreeTop.png similarity index 100% rename from Resources/towerTopTwo.png rename to Resources/towerThreeTop.png diff --git a/Resources/towerBaseTwo.png b/Resources/towerTwoBase.png similarity index 100% rename from Resources/towerBaseTwo.png rename to Resources/towerTwoBase.png diff --git a/Resources/towerTwoTop.png b/Resources/towerTwoTop.png new file mode 100644 index 0000000..eca7a82 Binary files /dev/null and b/Resources/towerTwoTop.png differ diff --git a/Resources/warriorExplosion.png b/Resources/warriorExplosion.png new file mode 100644 index 0000000..945b4cf Binary files /dev/null and b/Resources/warriorExplosion.png differ diff --git a/Resources/warriorOne.png b/Resources/warriorOne.png new file mode 100644 index 0000000..5806990 Binary files /dev/null and b/Resources/warriorOne.png differ diff --git a/Resources/warriorTwo.png b/Resources/warriorTwo.png new file mode 100644 index 0000000..a7ddf6c Binary files /dev/null and b/Resources/warriorTwo.png differ diff --git a/Resources/weapons.png b/Resources/weapons.png new file mode 100644 index 0000000..a000596 Binary files /dev/null and b/Resources/weapons.png differ diff --git a/cmake/Modules/FindSFML.cmake b/cmake/Modules/FindSFML.cmake old mode 100755 new mode 100644 diff --git a/src/Castle/Building/Barracks.cpp b/src/Castle/Building/Barracks.cpp new file mode 100644 index 0000000..1dd37f5 --- /dev/null +++ b/src/Castle/Building/Barracks.cpp @@ -0,0 +1,18 @@ +#include "Barracks.h" + +Barracks::Barracks() + : Building(GameConstants::instance().cBARRACKS_1_COST()) { +} + +int Barracks::upgrade() { + if (lvl_ >= 2) { + return 0; + } + int minusGold = upgradeCost_; + ++lvl_; + if (lvl_ == 1) { + upgradeCost_ = GameConstants::instance().cBARRACKS_2_COST(); + } + + return minusGold; +} diff --git a/src/Castle/Building/Barracks.h b/src/Castle/Building/Barracks.h new file mode 100644 index 0000000..e28da4b --- /dev/null +++ b/src/Castle/Building/Barracks.h @@ -0,0 +1,15 @@ +#ifndef TOWERDEFENSE_BARRACKS_H +#define TOWERDEFENSE_BARRACKS_H + + +#include "Building.h" + +class Barracks: public Building { +public: + Barracks(); + + int upgrade() override; +}; + + +#endif //TOWERDEFENSE_BARRACKS_H diff --git a/src/Castle/Building/Building.cpp b/src/Castle/Building/Building.cpp new file mode 100644 index 0000000..96db708 --- /dev/null +++ b/src/Castle/Building/Building.cpp @@ -0,0 +1,14 @@ +#include "Building.h" + +Building::Building(int upgradeCost) + : upgradeCost_(upgradeCost), + lvl_(0) { +} + +unsigned char Building::getLvl() const { + return lvl_; +} + +int Building::getUpgradeCost() const { + return upgradeCost_; +} diff --git a/src/Castle/Building/Building.h b/src/Castle/Building/Building.h new file mode 100644 index 0000000..9ee2ce0 --- /dev/null +++ b/src/Castle/Building/Building.h @@ -0,0 +1,24 @@ +#ifndef TOWERDEFENSE_BUILDING_H +#define TOWERDEFENSE_BUILDING_H + + +#include "../../GameContext.h" +#include "../../GameConstants.h" + +class Building { +public: + virtual ~Building() = default; + + virtual int upgrade() = 0; + unsigned char getLvl() const; + int getUpgradeCost() const; + +protected: + explicit Building(int upgradeCost); + + int upgradeCost_; + unsigned char lvl_; +}; + + +#endif //TOWERDEFENSE_BUILDING_H diff --git a/src/Castle/Building/Farm.cpp b/src/Castle/Building/Farm.cpp new file mode 100644 index 0000000..d5633ca --- /dev/null +++ b/src/Castle/Building/Farm.cpp @@ -0,0 +1,26 @@ +#include +#include "Farm.h" +#include "../../GameConstants.h" + +Farm::Farm() + : Building(GameConstants::instance().cFARM_COST()), + working(GameConstants::instance().cFARM_TIME_CYCLE()) { + lvl_ = 1; +} + +int Farm::getBenefits(const sf::Time& dt) { + working -= dt.asMilliseconds(); + if (working <= 0) { + working = GameConstants::instance().cFARM_TIME_CYCLE(); + return lvl_ * GameConstants::instance().cFARM_LVL_BENEFITS(); + } + return 0; +} + +int Farm::upgrade() { + int minusGold = upgradeCost_; + ++lvl_; + upgradeCost_ = static_cast(log2(GameConstants::instance().cFARM_INC_COST_BASE() + lvl_) * + GameConstants::instance().cFARM_COST()); + return minusGold; +} diff --git a/src/Castle/Building/Farm.h b/src/Castle/Building/Farm.h new file mode 100644 index 0000000..c550ed5 --- /dev/null +++ b/src/Castle/Building/Farm.h @@ -0,0 +1,19 @@ +#ifndef TOWERDEFENSE_FARM_H +#define TOWERDEFENSE_FARM_H + + +#include +#include "Building.h" + +class Farm: public Building { +public: + Farm(); + int getBenefits(const sf::Time& dt); + int upgrade() override; + +private: + sf::Int32 working; +}; + + +#endif //TOWERDEFENSE_FARM_H diff --git a/src/Castle/Building/Weapons.cpp b/src/Castle/Building/Weapons.cpp new file mode 100644 index 0000000..0776bf5 --- /dev/null +++ b/src/Castle/Building/Weapons.cpp @@ -0,0 +1,19 @@ +#include "Weapons.h" + +Weapons::Weapons() + : Building(GameConstants::instance().cWEAPONS_1_COST()) { +} + +int Weapons::upgrade() { + if (lvl_ >= 3) { + return 0; + } + int minusGold = upgradeCost_; + ++lvl_; + if (lvl_ == 1) { + upgradeCost_ = GameConstants::instance().cWEAPONS_2_COST(); + } else if (lvl_ == 2) { + upgradeCost_ = GameConstants::instance().cWEAPONS_3_COST(); + } + return minusGold; +} diff --git a/src/Castle/Building/Weapons.h b/src/Castle/Building/Weapons.h new file mode 100644 index 0000000..dcff3b6 --- /dev/null +++ b/src/Castle/Building/Weapons.h @@ -0,0 +1,15 @@ +#ifndef TOWERDEFENSE_WEAPONS_H +#define TOWERDEFENSE_WEAPONS_H + + +#include "Building.h" + +class Weapons: public Building { +public: + Weapons(); + + int upgrade() override; +}; + + +#endif //TOWERDEFENSE_WEAPONS_H diff --git a/src/Castle/Castle.cpp b/src/Castle/Castle.cpp new file mode 100644 index 0000000..744cb58 --- /dev/null +++ b/src/Castle/Castle.cpp @@ -0,0 +1,183 @@ +#include "Castle.h" +#include "../Units/Warrior/WarriorLvlOne.h" +#include "../Units/Warrior/WarriorLvlTwo.h" +#include "../Units/Tower/TowerLvlZero.h" + +Castle::Castle() + : enemy_(nullptr), + gold_(GameConstants::instance().cCASTLE_INIT_GOLD()), + health_(GameConstants::instance().cCASTLE_HP()), + towers_(), + warriors_(), + numWarriorsToWave_(0), + numWarriorsInBuffer_(0), + forDurationState_(0), + warriorsBuffer_(), + farm_(), + barracks_(), + weapons_(), + makingWave_(false), + waveDuration_(0) {} + +int Castle::getGold() const { + return gold_; +} + +int Castle::getHealth() const { + return health_; +} + +const std::vector>& Castle::getTowers() const { + return towers_; +} + +std::list>& Castle::getWarriors() { + return warriors_; +} + +const std::list>& Castle::getWarriorsBuffer() const { + return warriorsBuffer_; +} + +void Castle::upgradeTower(int index) { + gold_ -= Tower::upgrade(towers_[index]); +} + +void Castle::upgradeBuilding(char type) { + switch (type) { + case 'f': + gold_ -= farm_.upgrade(); + break; + case 'b': + gold_ -= barracks_.upgrade(); + break; + case 'w': + gold_ -= weapons_.upgrade(); + break; + } +} + +void Castle::addWarrior(Type type, const Map::LogicMap& logicMap) { + if (numWarriorsInBuffer_ >= GameConstants::instance().cWARRIORS_BUFFER_SIZE()) { + return; + } + switch (type) { + case Type::lvlOne: + warriorsBuffer_.push_back(std::make_shared(logicMap.start, logicMap)); + break; + case Type::lvlTwo: + warriorsBuffer_.push_back(std::make_shared(logicMap.start, logicMap)); + break; + } + gold_ -= warriorsBuffer_.back()->getCost(); + ++numWarriorsInBuffer_; +} + +void Castle::updateCastle(const sf::Time& dTime) { + gold_ += farm_.getBenefits(dTime); + + for (auto warrior = warriors_.begin(); warrior != warriors_.end();) { + (*warrior)->update(dTime); + if (!(*warrior)->isAlive() || (*warrior)->isFinished()) { + if ((*warrior)->isFinished()) { + enemy_->takeDamage((*warrior)->getHp()); + } + warrior = warriors_.erase(warrior); + } + else { + ++warrior; + } + } + + for (const auto& tower : towers_) { + tower->update(dTime); + } + if (makingWave_) { + makeWave(dTime); + } +} + +void Castle::takeDamage(int damage) { + health_ -= damage; +} + +void Castle::setEnemy(const std::shared_ptr& castle) { + enemy_ = castle; +} + +void Castle::addTower(const sf::Vector2f& position, std::list>& warriors, std::vector>& bullets) { + towers_.push_back(std::make_shared(position, warriors, bullets)); +} + +void Castle::makeWave(const sf::Time& dTime) { + waveDuration_ -= dTime.asMilliseconds(); + if (waveDuration_ <= 0) { + waveDuration_ = GameConstants::instance().cCASTLE_WAVE_DURATION(); + if (numWarriorsToWave_ > 0) { + --numWarriorsToWave_; + warriors_.push_back(warriorsBuffer_.front()); + warriorsBuffer_.pop_front(); + } else { + makingWave_ = false; + } + } +} + +void Castle::letsMakingWave() { + numWarriorsToWave_ += forDurationState_; + forDurationState_ = 0; + makingWave_ = true; +} + +void Castle::dropBuffer() { + forDurationState_ += numWarriorsInBuffer_; + numWarriorsInBuffer_ = 0; +} + +std::string Castle::generateWaveString(const Castle& player) { + std::string value; + + auto buffIterator = player.warriorsBuffer_.begin(); + for (size_t i = 0; i < player.numWarriorsToWave_; i++) { + buffIterator++; + } + + for (;buffIterator != player.warriorsBuffer_.end(); buffIterator++) { + if ((*buffIterator) != nullptr) { + switch ((*buffIterator)->getType()) { + case Type::lvlOne: + value.push_back('1'); + break; + case Type::lvlTwo: + value.push_back('2'); + break; + } + } + } + + return value; +} + +size_t Castle::getWarriorsInBuffer() const { + return numWarriorsInBuffer_; +} + +bool Castle::checkValidUpgradeTower(const Type& towerLvl, unsigned char weaponsLvl) { + return ((weaponsLvl == 3) || (towerLvl == Type::lvlZero && weaponsLvl >= 1) || + (towerLvl == Type::lvlOne && weaponsLvl >= 2)); +} + +const Farm& Castle::getFarm() const { + return farm_; +} + +const Barracks& Castle::getBarracks() const { + return barracks_; +} +const Weapons& Castle::getWeapons() const { + return weapons_; +} + +size_t Castle::getWarriorsToWave() const { + return numWarriorsToWave_; +} diff --git a/src/Castle/Castle.h b/src/Castle/Castle.h new file mode 100644 index 0000000..bf0d0d4 --- /dev/null +++ b/src/Castle/Castle.h @@ -0,0 +1,65 @@ +#ifndef TOWERDEFENSE_CASTLE_H +#define TOWERDEFENSE_CASTLE_H + +#include +#include +#include "../Units/Tower/Tower.h" +#include "../Units/Warrior/Warrior.h" +#include "Building/Farm.h" +#include "Building/Barracks.h" +#include "Building/Weapons.h" +#include "../GameConstants.h" + + +class Castle { +public: + Castle(); + + void updateCastle(const sf::Time& dTime); + void upgradeTower(int index); + void upgradeBuilding(char type); + void addWarrior(Type type, const Map::LogicMap& logicMap); + void addTower(const sf::Vector2f& position, std::list>& warriors, std::vector>& bullets); + void takeDamage(int damage); + void setEnemy(const std::shared_ptr& castle); + void letsMakingWave(); + void dropBuffer(); + void makeWave(const sf::Time& dTime); + + static std::string generateWaveString(const Castle& player); + static bool checkValidUpgradeTower(const Type& towerLvl, unsigned char weaponsLvl); + + int getGold() const; + int getHealth() const; + const std::vector>& getTowers() const; + std::list>& getWarriors(); + const std::list>& getWarriorsBuffer() const; + size_t getWarriorsInBuffer() const; + size_t getWarriorsToWave() const; + const Farm& getFarm() const; + const Barracks& getBarracks() const; + const Weapons& getWeapons() const; + +private: + int gold_; + int health_; + std::shared_ptr enemy_; + std::vector> towers_; + std::list> warriors_; + size_t numWarriorsInBuffer_; + size_t numWarriorsToWave_; + size_t forDurationState_; + std::list> warriorsBuffer_; + + Farm farm_; + Barracks barracks_; + Weapons weapons_; + + bool makingWave_; + sf::Int32 waveDuration_; + + +}; + + +#endif //TOWERDEFENSE_CASTLE_H diff --git a/src/ConnectGameState.cpp b/src/ConnectGameState.cpp new file mode 100644 index 0000000..97942e8 --- /dev/null +++ b/src/ConnectGameState.cpp @@ -0,0 +1,90 @@ +#include "ConnectGameState.h" +#include "Graphics/Button.h" +#include "Graphics/TextBox.h" +#include "Graphics/Label.h" +#include "Game.h" +#include "Constants.h" + +ConnectGameState::ConnectGameState(StateManager &stack, States::Context context) : State(stack, context) { + mapSprite.setTileNumber(16); + texture.loadFromFile("Resources/map1.png"); + texture.setSmooth(true); + sf::IntRect rect{ TILE_SIZE * (16 % 15), TILE_SIZE * (16 / 15), TILE_SIZE, TILE_SIZE }; + mapSprite.setTexture(texture, rect); + + context.multiplayer->connect(); + + if (!context.multiplayer->isConnected()) { + std::cout << "[warning] no server connection" << std::endl; + } + + auto textbox_new = std::make_shared(getContext().fontHolder->get(Fonts::font1)); + auto textbox_join = std::make_shared(getContext().fontHolder->get(Fonts::font1)); + + textNew.setFont(context.fontHolder->get(Fonts::font1)); + textJoin.setFont(context.fontHolder->get(Fonts::font1)); + textNew.setString("New game:"); + textJoin.setString("Joind game:"); + textNew.setPosition(350, 150); + textJoin.setPosition(350, 250); + + container.addWidget(textbox_new); + container.addWidget(textbox_join); + + textbox_new->setDimensons(350, 200, 500, 50); + textbox_new->setInd(0); + textbox_new->setString("Game name"); + textbox_join->setDimensons(350, 300, 500, 50); + textbox_join->setInd(0); + textbox_join->setString("Game id"); + + textbox_new->setCallback([this, textbox_new](int ind) { + getContext().multiplayer->outcoming.emplace_back(0, 'n', textbox_new->getString(), sf::microseconds(0)); + }); + + textbox_join->setCallback([this, textbox_join](int ind) { + getContext().multiplayer->outcoming.emplace_back(0, 'j', textbox_join->getString(), sf::microseconds(0)); + }); +} + +bool ConnectGameState::handleEvent(const sf::Event &event) { + container.handleWidgetsEvent(event); + return false; +} + +bool ConnectGameState::update(sf::Time dt) { + container.updateWidgets(dt); + for (auto &&event: getContext().multiplayer->incoming) { + switch (event.type) { + case 'n': { + std::cout << "[success] game id " << event.value << std::endl; + gameID = event.value; + break; + } + + case 'j': { + *getContext().p_id = atoi(event.value.c_str()); + std::cout << "[success] in game. your id " << *getContext().p_id << std::endl; + popState(); + pushState(States::ID::Game); + break; + } + + default: + break; + } + } + +} + +void ConnectGameState::draw() { + getContext().window->clear(sf::Color(0, 165, 80, 0)); + for (int i = 0; i < 20; i++) + for (int j = 0; j < 20; j++) + { + mapSprite.setPosition(static_cast(j * TILE_SIZE), static_cast(i * TILE_SIZE)); + getContext().window->draw(mapSprite); + } + + getContext().window->draw(container); +} \ No newline at end of file diff --git a/src/ConnectGameState.h b/src/ConnectGameState.h new file mode 100644 index 0000000..a950a21 --- /dev/null +++ b/src/ConnectGameState.h @@ -0,0 +1,29 @@ +#ifndef TOWERDEFENSE_CONNECTGAMESTATE_H +#define TOWERDEFENSE_CONNECTGAMESTATE_H + +#include "Graphics/Gui.h" +#include "State.h" +#include "Tile.h" + +class ConnectGameState: public State { +public: + explicit ConnectGameState(StateManager& stack, States::Context context); + + bool handleEvent(const sf::Event& event) override ; + bool update(sf::Time dt) override; + void draw() override; + + void initButtons(); + +private: + sf::Texture texture; + Tile mapSprite; + + std::string gameID; + gui::Gui container; + sf::Text textNew; + sf::Text textJoin; +}; + + +#endif //TOWERDEFENSE_CONNECTGAMESTATE_H \ No newline at end of file diff --git a/src/Constants.h b/src/Constants.h new file mode 100644 index 0000000..674db96 --- /dev/null +++ b/src/Constants.h @@ -0,0 +1,10 @@ +// +// Created by Falcon on 20.04.2018. +// + +#ifndef TOWERDEFENSE_CONSTANTS_H +#define TOWERDEFENSE_CONSTANTS_H + +#define TILE_SIZE 64 + +#endif //TOWERDEFENSE_CONSTANTS_H diff --git a/src/Game.cpp b/src/Game.cpp index ce4827d..bdee769 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -2,24 +2,68 @@ #include "MenuState.h" #include "PauseState.h" #include "GameState.h" +#include "ConnectGameState.h" +#include "Multiplayer/MultiplayerFacade/ClientMultiplayerFacade.h" +#include "Multiplayer/MultiplayerFacade/ServerMultiplayerFacade.h" +#include "GameOverState.h" +#include "WinState.h" +#include -Game::Game() : window({1000, 1000}, "Tower Defense", sf::Style::Titlebar | - sf::Style::Default, sf::ContextSettings{0, 0, 8, 1, 1, 0, false}), - context(window, font, textureHolder, fontHolder, cursor), +Game::Game() : window({1216, 768}, "Tower Defense", sf::Style::Titlebar | + sf::Style::Default, sf::ContextSettings{0, 0, 8, 1, 1, 0}), + context(window, font, textureHolder, fontHolder, cursor, new mp::ClientMultiplayerFacade), stateManager(context) { + std::cout << "start game constructor" << std::endl; loadAllResources(); + std::cout << "load resources" << std::endl; registerStates(); - stateManager.pushState(States::ID::Game); + std::cout << "register state" << std::endl; + stateManager.pushState(States::ID::Menu); + std::cout << "start game" << std::endl; + +// window.setVerticalSyncEnabled(true); +} + + +Game::Game(mp::player &first, mp::player &second) + : context(window, font, textureHolder, fontHolder, cursor, new mp::ServerMultiplayerFacade(first, second)), + stateManager(context) +{ + registerStates(); + stateManager.pushState(States::ID::Game); // TODO MultiplayerGame } void Game::run() { - const sf::Time frameTime = sf::seconds(1.f / 30.f); + const sf::Time frameTime = sf::seconds(1.f / 60.f); sf::Clock clock; - sf::Time passedTIme = sf::Time::Zero; + sf::Time passedTime = sf::Time::Zero; + auto mp = context.multiplayer; while (window.isOpen()) { - input(); - update(frameTime); + sf::Time elapsedTime = clock.restart(); + passedTime += elapsedTime ; + while (passedTime > frameTime) { + passedTime -= frameTime; + input(); + update(frameTime); + + mp->incoming.clear(); + if (mp->isConnected()) { + try { + mp->sendEvents(); + mp->askEvents(); + for (auto &&item : mp->incoming) { + if (item.type == 's' && item.value == "stop") + window.close(); + } + } catch (const std::exception &e) { + std::cout << e.what() << std::endl; + } + } else { + mp->outcoming.clear(); + } + } + draw(); } } @@ -35,7 +79,54 @@ void Game::input() { } void Game::loadAllResources() { - fontHolder.load(Fonts::font1, "../Resources/sansation.ttf"); + fontHolder.load(Fonts::font1, "Resources/sansation.ttf"); + + textureHolder.load(Textures::cursor, "Resources/cursor.png"); + textureHolder.load(Textures::panel, "Resources/panel.png"); + textureHolder.load(Textures::button, "Resources/button.png"); + textureHolder.load(Textures::map, "Resources/map1.png"); + textureHolder.load(Textures::target, "Resources/target.png"); + textureHolder.load(Textures::gold, "Resources/diamond.png"); + textureHolder.load(Textures::star, "Resources/star.png"); + textureHolder.load(Textures::exit, "Resources/exit.png"); + textureHolder.load(Textures::lives, "Resources/heart.png"); + textureHolder.load(Textures::pauseOn, "Resources/pauseOn.png"); + textureHolder.load(Textures::pauseOff, "Resources/pauseOff.png"); + textureHolder.load(Textures::audioOff, "Resources/audioOff.png"); + textureHolder.load(Textures::audioOn, "Resources/audioOn.png"); + textureHolder.load(Textures::musicOff, "Resources/musicOff.png"); + textureHolder.load(Textures::musicOn, "Resources/musicOn.png"); + textureHolder.load(Textures::warriorOne, "Resources/enemyOne.png"); + textureHolder.load(Textures::warriorTwo, "Resources/enemy.png"); + textureHolder.load(Textures::blood, "Resources/blood.png"); + textureHolder.load(Textures::warriorExplosion, "Resources/warriorExplosion.png"); + textureHolder.load(Textures::towerZeroRed, "Resources/redTarget.png"); + textureHolder.load(Textures::towerZeroBlue, "Resources/blueTarget.png"); + textureHolder.load(Textures::castle1, "Resources/RedCastle.png"); + textureHolder.load(Textures::castle2, "Resources/BlueCastle.png"); + textureHolder.load(Textures::towerOneTop, "Resources/towerOneTop.png"); + textureHolder.load(Textures::towerOneBase, "Resources/towerOneBase.png"); + textureHolder.load(Textures::towerTwoTop, "Resources/towerTwoTop.png"); + textureHolder.load(Textures::towerTwoBase, "Resources/towerTwoBase.png"); + textureHolder.load(Textures::towerThreeTop, "Resources/towerThreeTop.png"); + textureHolder.load(Textures::towerThreeBase, "Resources/towerThreeBase.png"); + textureHolder.load(Textures::bulletOne, "Resources/bulletOne.png"); + textureHolder.load(Textures::bulletTwo, "Resources/bulletTwo.png"); + textureHolder.load(Textures::bulletThree, "Resources/bulletThree.png"); + textureHolder.load(Textures::explosionOne, "Resources/explosionOne.png"); + textureHolder.load(Textures::explosionTwo, "Resources/explosionTwo.png"); + textureHolder.load(Textures::explosionThree, "Resources/explosionThree.png"); + textureHolder.load(Textures::warriorIconOne, "Resources/warriorOne.png"); + textureHolder.load(Textures::warriorIconTwo, "Resources/warriorTwo.png"); + textureHolder.load(Textures::addWarriorOne, "Resources/addWarriorOne.png"); + textureHolder.load(Textures::addWarriorTwo, "Resources/addWarrior.png"); + textureHolder.load(Textures::addBarraks, "Resources/addBarraks.png"); + textureHolder.load(Textures::addFarm, "Resources/addFarm.png"); + textureHolder.load(Textures::addWeapons, "Resources/addWeapons.png"); + textureHolder.load(Textures::farm, "Resources/farm.png"); + textureHolder.load(Textures::weapons, "Resources/weapons.png"); + textureHolder.load(Textures::barraks, "Resources/barraks.png"); + textureHolder.load(Textures::logo, "Resources/logo.png"); } @@ -45,10 +136,60 @@ void Game::update(sf::Time frameTime) { void Game::draw() { window.clear(sf::Color(210, 210, 210)); +// std::thread t1(&StateManager::draw, stateManager); +// t1.join(); stateManager.draw(); window.display(); } void Game::registerStates() { + stateManager.registerState(States::ID::Menu); + stateManager.registerState(States::ID::ConnectGame); stateManager.registerState(States::ID::Game); -} \ No newline at end of file + stateManager.registerState(States::ID::GameOverState); + stateManager.registerState(States::ID::WinState); +} + +void Game::server_run(bool use_validation) { + const sf::Time frameTime = sf::seconds(1.f / 60.f); + sf::Clock clock; + sf::Time passedTime = sf::Time::Zero; + + std::cout << "start multi game" << std::endl; + + auto& mp = context.multiplayer; + while (true) { + if (!mp->isConnected()) { + mp->outcoming.emplace_back(0, 's', "stop", sf::microseconds(0)); + mp->sendEvents(); + + break; + } + + if (use_validation) { + sf::Time elapsedTime = clock.restart(); + passedTime += elapsedTime ; + while (passedTime > frameTime) { + passedTime -= frameTime; + update(frameTime); + + try { + mp->incoming.clear(); + mp->sendEvents(); + mp->askEvents(); + } catch (const std::exception &e) { + std::cout << e.what() << std::endl; + } + } + } else { + try { + mp->incoming.clear(); + mp->askEvents(); + mp->outcoming = mp->incoming; + mp->sendEvents(); + } catch (const std::exception &e) { + std::cout << e.what() << std::endl; + } + } + } +} diff --git a/src/Game.h b/src/Game.h index ac59af5..b32f393 100644 --- a/src/Game.h +++ b/src/Game.h @@ -8,13 +8,18 @@ #include "GameContext.h" #include "ResourceManager/ResourcesHolder.h" #include "ResourceManager/ResourcesIdentifier.h" +#include "Multiplayer/Entities/Player.h" +//std::vector& incoming_events; +//std::vector& outcoming_events; class Game { public: Game(); + Game(mp::player &first, mp::player &second); void run(); + void server_run(bool use_validation); private: void input(); @@ -26,7 +31,6 @@ class Game { TextureHolder textureHolder; FontHolder fontHolder; - int color; sf::Font font; sf::Sprite cursor; sf::RenderWindow window; diff --git a/src/GameConstants.cpp b/src/GameConstants.cpp new file mode 100644 index 0000000..6a939ba --- /dev/null +++ b/src/GameConstants.cpp @@ -0,0 +1,276 @@ +#include +#include +#include "GameConstants.h" + +bool GameConstants::initialized_ = false; + +GameConstants &GameConstants::instance() { + + static GameConstants gameConstants; + if (initialized_) { + return gameConstants; + } + initialized_ = true; + + std::ifstream fin("../src/game_config.cfg"); + if (!fin.is_open()) { + throw std::runtime_error(std::string("Config file doesn't open.")); + } + + std::string name; + while (fin >> name) { + if (name == "BARRACKS_1_COST") { + fin >> gameConstants.BARRACKS_1_COST; + } else if (name == "BARRACKS_2_COST") { + fin >> gameConstants.BARRACKS_2_COST; + } else if (name == "BARRACKS_3_COST") { + fin >> gameConstants.BARRACKS_3_COST; + } else if (name == "FARM_COST") { + fin >> gameConstants.FARM_COST; + } else if (name == "FARM_INC_COST_BASE") { + fin >> gameConstants.FARM_INC_COST_BASE; + } else if (name == "FARM_LVL_BENEFITS") { + fin >> gameConstants.FARM_LVL_BENEFITS; + } else if (name == "FARM_TIME_CYCLE") { + fin >> gameConstants.FARM_TIME_CYCLE; + } else if (name == "WEAPONS_1_COST") { + fin >> gameConstants.WEAPONS_1_COST; + } else if (name == "WEAPONS_2_COST") { + fin >> gameConstants.WEAPONS_2_COST; + } else if (name == "WEAPONS_3_COST") { + fin >> gameConstants.WEAPONS_3_COST; + } else if (name == "CASTLE_HP") { + fin >> gameConstants.CASTLE_HP; + } else if (name == "CASTLE_INIT_GOLD") { + fin >> gameConstants.CASTLE_INIT_GOLD; + } else if (name == "CASTLE_WAVE_DURATION") { + fin >> gameConstants.CASTLE_WAVE_DURATION; + } else if (name == "WARRIORS_BUFFER_SIZE") {/*____________________________________*/ + fin >> gameConstants.WARRIORS_BUFFER_SIZE; + } else if (name == "BULLET_1_DAMAGE") { + fin >> gameConstants.BULLET_1_DAMAGE; + } else if (name == "BULLET_1_VELOCITY") { + fin >> gameConstants.BULLET_1_VELOCITY; + } else if (name == "BULLET_2_DAMAGE") { + fin >> gameConstants.BULLET_2_DAMAGE; + } else if (name == "BULLET_2_VELOCITY") { + fin >> gameConstants.BULLET_2_VELOCITY; + } else if (name == "BULLET_3_DAMAGE") { + fin >> gameConstants.BULLET_3_DAMAGE; + } else if (name == "BULLET_3_VELOCITY") { + fin >> gameConstants.BULLET_3_VELOCITY; + } else if (name == "BULLET_3_AOE") { + fin >> gameConstants.BULLET_3_AOE;/*___________________________________*/ + } else if (name == "TOWER_0_UP_COST") { + fin >> gameConstants.TOWER_0_UP_COST; + } else if (name == "TOWER_1_UP_COST") { + fin >> gameConstants.TOWER_1_UP_COST; + } else if (name == "TOWER_1_RANGE") { + fin >> gameConstants.TOWER_1_RANGE; + } else if (name == "TOWER_1_COOLDOWN") { + fin >> gameConstants.TOWER_1_COOLDOWN; + } else if (name == "TOWER_2_UP_COST") { + fin >> gameConstants.TOWER_2_UP_COST; + } else if (name == "TOWER_2_RANGE") { + fin >> gameConstants.TOWER_2_RANGE; + } else if (name == "TOWER_2_COOLDOWN") { + fin >> gameConstants.TOWER_2_COOLDOWN; + } else if (name == "TOWER_3_RANGE") { + fin >> gameConstants.TOWER_3_RANGE; + } else if (name == "TOWER_3_COOLDOWN") { + fin >> gameConstants.TOWER_3_COOLDOWN; + } else if (name == "WARRIOR_1_COST") { + fin >> gameConstants.WARRIOR_1_COST; + } else if (name == "WARRIOR_1_VELOCITY") { + fin >> gameConstants.WARRIOR_1_VELOCITY; + } else if (name == "WARRIOR_1_HP") { + fin >> gameConstants.WARRIOR_1_HP; + } else if (name == "WARRIOR_2_COST") { + fin >> gameConstants.WARRIOR_2_COST; + } else if (name == "WARRIOR_2_VELOCITY") { + fin >> gameConstants.WARRIOR_2_VELOCITY; + } else if (name == "WARRIOR_2_HP") { + fin >> gameConstants.WARRIOR_2_HP; + } else if (name == "WAVE_TIMER") { + fin >> gameConstants.WAVE_TIMER; + } else if (name == "SELECTOR_WAIT_TIME") { + fin >> gameConstants.SELECTOR_WAIT_TIME; + } else if (name == "DEBUG_MODE") { + fin >> gameConstants.DEBUG_MODE; + } else if (name == "CONNECTION_PORT") { + fin >> gameConstants.CONNECTION_PORT; + } else if (name == "IP_ADDR_SERVER") { + fin >> gameConstants.IP_ADDR_SERVER; + } else { + throw std::runtime_error(std::string("Unknown config parameter")); + } + + } + fin.close(); + + return gameConstants; +} + +int GameConstants::cBARRACKS_1_COST() const { + return BARRACKS_1_COST; +} + +int GameConstants::cBARRACKS_2_COST() const { + return BARRACKS_2_COST; +} + +int GameConstants::cBARRACKS_3_COST() const { + return BARRACKS_3_COST; +} + +int GameConstants::cFARM_COST() const { + return FARM_COST; +} + +int GameConstants::cFARM_INC_COST_BASE() const { + return FARM_INC_COST_BASE; +} + +int GameConstants::cFARM_LVL_BENEFITS() const { + return FARM_LVL_BENEFITS; +} + +int GameConstants::cFARM_TIME_CYCLE() const { + return FARM_TIME_CYCLE; +} + +int GameConstants::cWEAPONS_1_COST() const { + return WEAPONS_1_COST; +} + +int GameConstants::cWEAPONS_2_COST() const { + return WEAPONS_2_COST; +} + +int GameConstants::cWEAPONS_3_COST() const { + return WEAPONS_3_COST; +} + +int GameConstants::cCASTLE_HP() const { + return CASTLE_HP; +} + +int GameConstants::cCASTLE_INIT_GOLD() const { + return CASTLE_INIT_GOLD; +} + +int GameConstants::cCASTLE_WAVE_DURATION() const { + return CASTLE_WAVE_DURATION; +} + +int GameConstants::cWARRIORS_BUFFER_SIZE() const { + return WARRIORS_BUFFER_SIZE; +} + +int GameConstants::cBULLET_1_DAMAGE() const { + return BULLET_1_DAMAGE; +} + +int GameConstants::cBULLET_1_VELOCITY() const { + return BULLET_1_VELOCITY; +} + +int GameConstants::cBULLET_2_DAMAGE() const { + return BULLET_2_DAMAGE; +} + +int GameConstants::cBULLET_2_VELOCITY() const { + return BULLET_2_VELOCITY; +} + +int GameConstants::cBULLET_3_DAMAGE() const { + return BULLET_3_DAMAGE; +} + +int GameConstants::cBULLET_3_VELOCITY() const { + return BULLET_3_VELOCITY; +} + +int GameConstants::cBULLET_3_AOE() const { + return BULLET_3_AOE; +} + +int GameConstants::cTOWER_0_UP_COST() const { + return TOWER_0_UP_COST; +} + +int GameConstants::cTOWER_1_UP_COST() const { + return TOWER_1_UP_COST; +} + +int GameConstants::cTOWER_1_RANGE() const { + return TOWER_1_RANGE; +} + +int GameConstants::cTOWER_1_COOLDOWN() const { + return TOWER_1_COOLDOWN; +} + +int GameConstants::cTOWER_2_UP_COST() const { + return TOWER_2_UP_COST; +} + +int GameConstants::cTOWER_2_RANGE() const { + return TOWER_2_RANGE; +} + +int GameConstants::cTOWER_2_COOLDOWN() const { + return TOWER_2_COOLDOWN; +} + +int GameConstants::cTOWER_3_RANGE() const { + return TOWER_3_RANGE; +} + +int GameConstants::cTOWER_3_COOLDOWN() const { + return TOWER_3_COOLDOWN; +} + +int GameConstants::cWARRIOR_1_COST() const { + return WARRIOR_1_COST; +} + +int GameConstants::cWARRIOR_1_VELOCITY() const { + return WARRIOR_1_VELOCITY; +} + +int GameConstants::cWARRIOR_1_HP() const { + return WARRIOR_1_HP; +} + +int GameConstants::cWARRIOR_2_COST() const { + return WARRIOR_2_COST; +} + +int GameConstants::cWARRIOR_2_VELOCITY() const { + return WARRIOR_2_VELOCITY; +} + +int GameConstants::cWARRIOR_2_HP() const { + return WARRIOR_2_HP; +} + +int GameConstants::cWAVE_TIMER() const { + return WAVE_TIMER; +} + +int GameConstants::cSELECTOR_WAIT_TIME() const { + return SELECTOR_WAIT_TIME; +} + +int GameConstants::cDEBUG_MODE() const { + return DEBUG_MODE; +} + +int GameConstants::cCONNECTION_PORT() const { + return CONNECTION_PORT; +} + +const std::string &GameConstants::cIP_ADDR_SERVER() const { + return IP_ADDR_SERVER; +} diff --git a/src/GameConstants.h b/src/GameConstants.h new file mode 100644 index 0000000..3186764 --- /dev/null +++ b/src/GameConstants.h @@ -0,0 +1,111 @@ +#ifndef SERVER_GAMECONSTANTS_H +#define SERVER_GAMECONSTANTS_H + + +class GameConstants { +public: + static GameConstants& instance(); + + int cBARRACKS_1_COST() const; + int cBARRACKS_2_COST() const; + int cBARRACKS_3_COST() const; + int cFARM_COST() const; + int cFARM_INC_COST_BASE() const; + int cFARM_LVL_BENEFITS() const; + int cFARM_TIME_CYCLE() const; + int cWEAPONS_1_COST() const; + int cWEAPONS_2_COST() const; + int cWEAPONS_3_COST() const; + int cCASTLE_HP() const; + int cCASTLE_INIT_GOLD() const; + int cCASTLE_WAVE_DURATION() const; + int cWARRIORS_BUFFER_SIZE() const; + int cBULLET_1_DAMAGE() const; + int cBULLET_1_VELOCITY() const; + int cBULLET_2_DAMAGE() const; + int cBULLET_2_VELOCITY() const; + int cBULLET_3_DAMAGE() const; + int cBULLET_3_VELOCITY() const; + int cBULLET_3_AOE() const; + int cTOWER_0_UP_COST() const; + int cTOWER_1_UP_COST() const; + int cTOWER_1_RANGE() const; + int cTOWER_1_COOLDOWN() const; + int cTOWER_2_UP_COST() const; + int cTOWER_2_RANGE() const; + int cTOWER_2_COOLDOWN() const; + int cTOWER_3_RANGE() const; + int cTOWER_3_COOLDOWN() const; + int cWARRIOR_1_COST() const; + int cWARRIOR_1_VELOCITY() const; + int cWARRIOR_1_HP() const; + int cWARRIOR_2_COST() const; + int cWARRIOR_2_VELOCITY() const; + int cWARRIOR_2_HP() const; + int cWAVE_TIMER() const; + + // server + + int cSELECTOR_WAIT_TIME() const; + int cDEBUG_MODE() const; + int cCONNECTION_PORT() const; + const std::string &cIP_ADDR_SERVER() const; + +private: + GameConstants(){}; + GameConstants(const GameConstants&) = delete; + GameConstants& operator=(const GameConstants&) = delete; + + static bool initialized_; + + int BARRACKS_1_COST; + int BARRACKS_2_COST; + int BARRACKS_3_COST; + int FARM_COST; + int FARM_INC_COST_BASE; + int FARM_LVL_BENEFITS; + int FARM_TIME_CYCLE; + int WEAPONS_1_COST; + int WEAPONS_2_COST; + int WEAPONS_3_COST; + int CASTLE_HP; + int CASTLE_INIT_GOLD; + int CASTLE_WAVE_DURATION; + int WARRIORS_BUFFER_SIZE; + + int BULLET_1_DAMAGE; + int BULLET_1_VELOCITY; + int BULLET_2_DAMAGE; + int BULLET_2_VELOCITY; + int BULLET_3_DAMAGE; + int BULLET_3_VELOCITY; + int BULLET_3_AOE; + + int TOWER_0_UP_COST; + int TOWER_1_UP_COST; + int TOWER_1_RANGE; + int TOWER_1_COOLDOWN; + int TOWER_2_UP_COST; + int TOWER_2_RANGE; + int TOWER_2_COOLDOWN; + int TOWER_3_RANGE; + int TOWER_3_COOLDOWN; + + int WARRIOR_1_COST; + int WARRIOR_1_VELOCITY; + int WARRIOR_1_HP; + int WARRIOR_2_COST; + int WARRIOR_2_VELOCITY; + int WARRIOR_2_HP; + + int WAVE_TIMER; + + int SELECTOR_WAIT_TIME; + int DEBUG_MODE; + int CONNECTION_PORT; + std::string IP_ADDR_SERVER; +}; + + + +#endif //SERVER_GAMECONSTANTS_H diff --git a/src/GameContext.h b/src/GameContext.h index 525cc44..6af7e26 100644 --- a/src/GameContext.h +++ b/src/GameContext.h @@ -3,11 +3,13 @@ #include "ResourceManager/ResourcesIdentifier.h" #include "ResourceManager/ResourcesHolder.h" +#include "Multiplayer/MultiplayerFacade/AbstractMultiplayerFacade.h" enum class Type { lvlZero, lvlOne, lvlTwo, + lvlThree, }; namespace sf { @@ -31,17 +33,22 @@ namespace Player { namespace States { struct Context { - explicit Context(sf::RenderWindow &window - , sf::Font &font - , TextureHolder &textureHolder - , FontHolder &fontHolder - , sf::Sprite &cursor) - - : window(&window) - , font(&font) - , textureHolder(&textureHolder) - , fontHolder(&fontHolder) - , cursor(&cursor) + explicit Context( + sf::RenderWindow &window, + sf::Font &font, + TextureHolder &textureHolder, + FontHolder &fontHolder, + sf::Sprite &cursor, + mp::AbstractMultiplayerFacade *p_mult + ) + + : window(&window), + font(&font), + textureHolder(&textureHolder), + fontHolder(&fontHolder), + cursor(&cursor), + p_id(new int(2)), + multiplayer(p_mult) {}; @@ -51,7 +58,10 @@ namespace States { FontHolder *fontHolder; SoundManager *soundManager; sf::Sprite *cursor; + + std::shared_ptr p_id; + std::shared_ptr multiplayer; }; } -#endif //TOWERDEFENSE_GAMECONTEXT_H +#endif //TOWERDEFENSE_GAMECONTEXT_H \ No newline at end of file diff --git a/src/GameOverState.cpp b/src/GameOverState.cpp new file mode 100644 index 0000000..a9675d5 --- /dev/null +++ b/src/GameOverState.cpp @@ -0,0 +1,66 @@ +#include "GameOverState.h" +#include "Constants.h" + +#include +#include + +GameOverState::GameOverState(StateManager &stack, States::Context context) + : State(stack, context) +{ + + texture.loadFromFile("Resources/map1.png"); + texture.setSmooth(true); + sf::IntRect rect{ TILE_SIZE * (16 % 15), TILE_SIZE * (16 / 15), TILE_SIZE, TILE_SIZE }; + mapSprite.setTexture(texture, rect); + + sf::RenderWindow &window = *context.window; + sf::Font &font = *context.font; + +// sf::RenderWindow &window = *context.window; +// sf::Font &font = *context.font; + + gameOvetText.setString("YOU LOSE"); + gameOvetText.setColor(sf::Color::White); + gameOvetText.setCharacterSize(100); + gameOvetText.setFont(context.fontHolder->get(Fonts::font1)); + gameOvetText.setPosition(350.f, 200.f); + + enterText.setString("ENTER Menu"); + enterText.setColor(sf::Color::Black); + enterText.setCharacterSize(30); + enterText.setFont(context.fontHolder->get(Fonts::font1)); + enterText.setPosition(500.f, 400.f); +} + +bool GameOverState::handleEvent(const sf::Event &event) +{ + if (event.type == sf::Event::KeyPressed + && event.key.code == sf::Keyboard::Return) + { + popState(); + pushState(States::ID::Menu); + } + + return false; +} + +bool GameOverState::update(sf::Time dt) +{ + return false; +} + +void GameOverState::draw() +{ + getContext().window->clear(sf::Color(0, 165, 80, 0)); + for (int i = 0; i < 20; i++) + for (int j = 0; j < 20; j++) + { + mapSprite.setPosition(static_cast(j * TILE_SIZE), static_cast(i * TILE_SIZE)); + getContext().window->draw(mapSprite); + } + + sf::RenderWindow &window = *getContext().window; + window.setView(window.getDefaultView()); + window.draw(gameOvetText); + window.draw(enterText); +} \ No newline at end of file diff --git a/src/GameOverState.h b/src/GameOverState.h new file mode 100644 index 0000000..52820c1 --- /dev/null +++ b/src/GameOverState.h @@ -0,0 +1,21 @@ +#pragma once + +#include "State.h" +#include +#include "Tile.h" + +class GameOverState : public State +{ +public: + explicit GameOverState(StateManager &stack, States::Context context); + + bool handleEvent(const sf::Event &event) override; + bool update(sf::Time dt) override; + void draw() override; + +private: + sf::Text gameOvetText, enterText, scoreText; + sf::Texture texture; + Tile mapSprite; +}; + diff --git a/src/GameState.cpp b/src/GameState.cpp index 478d63b..4e8782f 100644 --- a/src/GameState.cpp +++ b/src/GameState.cpp @@ -1,22 +1,506 @@ #include "GameState.h" #include "Game.h" +#include "Units/Warrior/WarriorLvlTwo.h" +#include "Units/Tower/TowerLvlOne.h" +#include "Graphics/Gui.h" +#include "Graphics/Button.h" +#include "Graphics/HUD.h" +#include "Graphics/GraphicsUnits/GraphicsCastle.h" +#include "Graphics/GraphicsUnits/GraphicsBullet.h" + +#define DELAY 300 GameState::GameState(StateManager &stack, States::Context context) : + lComponent(), State(stack, context), - gameData() + gameData(), + map(*context.window), + clock(sf::Time::Zero), + gComponent(context, *lComponent.getPlayer1(), *lComponent.getPlayer2()), + hud(context, lComponent.getPlayer1(), lComponent.getPlayer2()), + printCost(false){ + std::cout << "start counstructor" << std::endl; + you.setString("You"); + you.setFont(context.fontHolder->get(Fonts::font1)); + you.setCharacterSize(50); + foe.setString("Foe"); + foe.setFont(context.fontHolder->get(Fonts::font1)); + foe.setCharacterSize(50); + if (*context.p_id == 1) { + curPlayer = lComponent.getPlayer1(); + curPlayerRoad = 0; + you.setColor(sf::Color(215, 50, 50)); + foe.setColor(sf::Color(40, 146, 224)); + you.setPosition(10.f, 350.f); + foe.setPosition(1120.f, 350.f); + } else { + curPlayer = lComponent.getPlayer2(); + curPlayerRoad = 1; + foe.setPosition(10.f, 350.f); + foe.setColor(sf::Color(215, 50, 50)); + you.setColor(sf::Color(40, 146, 224)); + you.setPosition(1120.f, 350.f); + } + timer.setFont(context.fontHolder->get(Fonts::font1)); + timer.setPosition(990.f, 715.f); + map.analyze(towers1, towers2); + std::cout << "Map analyze" << std::endl; + map.getRoadRect(roadRect); + std::cout << "Get road rect" << std::endl; + initTower(); + std::cout << "Init Tower" << std::endl; + initHUD(); + std::cout << "Init HUD" << std::endl; + castle1.setTexture(context.textureHolder->get(Textures::castle1)); + castle1.setScale(1.1, 1.1); + castle1.setPosition(-180.f, 173.f); + castle2.setTexture(context.textureHolder->get(Textures::castle2)); + castle2.setScale(1.1, 1.1); + castle2.setPosition(940.f ,173.f); +} -{ +void GameState::initTower() { + sf::Texture b = getContext().textureHolder->get(Textures::target); + sf::IntRect rect{ TILE_SIZE, TILE_SIZE, TILE_SIZE, TILE_SIZE}; + sf::Vector2f p; + for (int i = 0; i < towers1.size(); i++) { + lComponent.getPlayer1()->addTower(towers1[i], lComponent.getPlayer2()->getWarriors(), lComponent.getBullets()); + if (*getContext().p_id == 1) { + auto bt = std::make_shared(); + bt->setTexture(b); + bt->setTextureRect(rect); + p = towers1[i]; + p.x -= TILE_SIZE / 2; + p.y -= TILE_SIZE / 2; + bt->setPosition(p); + bt->setCost(true); + bt->setInd(i); + bt->setCallback([this](int ind) { + if ((lComponent.getPlayer1()->getGold() >= lComponent.getPlayer1()->getTowers().at(ind)->getPrice()) && + (Castle::checkValidUpgradeTower(lComponent.getPlayer1()->getTowers().at(ind)->getType(), + lComponent.getPlayer1()->getWeapons().getLvl()))) { + getContext().multiplayer->outcoming.emplace_back(1, 't', std::to_string(ind), + clock + sf::milliseconds(DELAY)); + std::cout << ind << std::endl; + } + }); + bt->setCostCallback([this](int ind) { + printCost = true; + if (lComponent.getPlayer1()->getTowers().at(ind)->getPrice() == -1) { + printCost = false; + } + sf::Vector2f pos = lComponent.getPlayer1()->getTowers().at(ind)->getPosition(); + cost.setFont(getContext().fontHolder->get(Fonts::font1)); + cost.setString(std::to_string(lComponent.getPlayer1()->getTowers().at(ind)->getPrice())); + cost.setPosition(pos.x - TILE_SIZE, pos.y - TILE_SIZE); +// cost.setOutlineThickness(1.f); + if (lComponent.getPlayer1()->getGold() >= lComponent.getPlayer1()->getTowers().at(ind)->getPrice() && + (Castle::checkValidUpgradeTower(lComponent.getPlayer1()->getTowers().at(ind)->getType(), + lComponent.getPlayer1()->getWeapons().getLvl()))) { + cost.setColor(sf::Color::Green); + } else { + cost.setColor(sf::Color::Red); + } + }); + container.addWidget(bt); + } + } + + for (int i = 0; i < towers2.size(); i++) { + lComponent.getPlayer2()->addTower(towers2[i], lComponent.getPlayer1()->getWarriors(), lComponent.getBullets()); + auto bt = std::make_shared(); + if (*getContext().p_id == 2) { + bt->setTexture(b); + bt->setTextureRect(rect); + p = towers2[i]; + p.x -= TILE_SIZE / 2; + p.y -= TILE_SIZE / 2; + bt->setPosition(p); + bt->setInd(i); + bt->setCost(true); + bt->setCallback([this](int ind) { + if ((lComponent.getPlayer2()->getGold() >= lComponent.getPlayer2()->getTowers().at(ind)->getPrice()) && + (Castle::checkValidUpgradeTower(lComponent.getPlayer2()->getTowers().at(ind)->getType(), + lComponent.getPlayer2()->getWeapons().getLvl()))) { + getContext().multiplayer->outcoming.emplace_back(2, 't', std::to_string(ind), + clock + sf::milliseconds(DELAY)); + std::cout << ind << std::endl; + } + }); + bt->setCostCallback([this](int ind) { + std::cout << ind << std::endl; + printCost = true; + if (lComponent.getPlayer2()->getTowers().at(ind)->getPrice() == -1) { + printCost = false; + } +// cost.setOutlineThickness(1.f); + sf::Vector2f pos = lComponent.getPlayer2()->getTowers().at(ind)->getPosition(); + cost.setFont(getContext().fontHolder->get(Fonts::font1)); + cost.setString(std::to_string(lComponent.getPlayer2()->getTowers().at(ind)->getPrice())); + cost.setPosition(pos.x - TILE_SIZE / 2, pos.y - TILE_SIZE); + if (lComponent.getPlayer2()->getGold() >= lComponent.getPlayer2()->getTowers().at(ind)->getPrice() && + (Castle::checkValidUpgradeTower(lComponent.getPlayer2()->getTowers().at(ind)->getType(), + lComponent.getPlayer2()->getWeapons().getLvl()))) { + cost.setColor(sf::Color::Green); + } else { + cost.setColor(sf::Color::Red); + } + getContext().window->draw(cost); + }); + container.addWidget(bt); + } + } } -bool GameState::handleEvent(const sf::Event &event) { +void GameState::initHUD() { + std::cout << "start init HUD" << std::endl; + hud.init(); + sf::IntRect rect{0, 0, TILE_SIZE, TILE_SIZE}; + auto addLvlOne = std::make_shared(); + auto addLvlTwo = std::make_shared(); + addLvlOne->setCost(true); + addLvlTwo->setCost(true); + + std::cout << "1" << std::endl; + + addLvlOne->setCallback([this](int ind) { + + if (curPlayer->getBarracks().getLvl() >= 1 + && curPlayer->getGold() >= GameConstants::instance().cWARRIOR_1_COST()) { + std::cout << "button warrior id 1" << std::endl; + curPlayer->addWarrior(Type::lvlOne, roadRect[curPlayerRoad]); + } + }); + + addLvlOne->setCostCallback([this](int ind){ + printCost = true; + cost.setFont(getContext().fontHolder->get(Fonts::font1)); + cost.setString(std::to_string(GameConstants::instance().cWARRIOR_1_COST())); + cost.setPosition(860.f, 705.f - TILE_SIZE / 2); +// cost.setOutlineThickness(1.f); + if (curPlayer->getGold() >= GameConstants::instance().cWARRIOR_1_COST() && + (curPlayer->getBarracks().getLvl() >= 1)) { + cost.setColor(sf::Color::Green); + } else { + cost.setColor(sf::Color::Red); + } + }); + + std::cout << "2" << std::endl; + + addLvlOne->setTexture(getContext().textureHolder->get(Textures::addWarriorOne)); + addLvlOne->setTextureRect(rect); + addLvlOne->setPosition(860.f, 705.f); + addLvlOne->setCost(true); + + addLvlTwo->setCallback([this](int ind) { + if (curPlayer->getBarracks().getLvl() >= 2 + && curPlayer->getGold() >= GameConstants::instance().cWARRIOR_2_COST()) { + std::cout << "button warrior id 2" << std::endl; + curPlayer->addWarrior(Type::lvlTwo, roadRect[curPlayerRoad]); + } + }); + + addLvlTwo->setCostCallback([this](int ind){ + printCost = true; + cost.setFont(getContext().fontHolder->get(Fonts::font1)); + cost.setString(std::to_string(GameConstants::instance().cWARRIOR_2_COST())); + cost.setPosition(920.f, 705.f - TILE_SIZE / 2); +// cost.setOutlineThickness(1.f); + if (curPlayer->getGold() >= GameConstants::instance().cWARRIOR_2_COST() && + (curPlayer->getBarracks().getLvl() >= 2)) { + cost.setColor(sf::Color::Green); + } else { + cost.setColor(sf::Color::Red); + } + }); + + std::cout << "3" << std::endl; + + addLvlTwo->setTexture(getContext().textureHolder->get(Textures::addWarriorTwo)); + addLvlTwo->setTextureRect(rect); + addLvlTwo->setPosition(920.f, 705.f); + + std::cout << "4" << std::endl; + + buttons.addWidget(addLvlOne); + buttons.addWidget(addLvlTwo); + + std::cout << "5" << std::endl; + + auto addFarm = std::make_shared(); + auto addBarraks = std::make_shared(); + auto addWeapons = std::make_shared(); + + std::cout << "6" << std::endl; + + addFarm->setTexture(getContext().textureHolder->get(Textures::addFarm)); + addFarm->setTextureRect(rect); + addFarm->setPosition(280.f, 705.f); + + std::cout << "7" << std::endl; + + addBarraks->setTexture(getContext().textureHolder->get(Textures::addBarraks)); + addBarraks->setTextureRect(rect); + addBarraks->setPosition(220.f, 705.f); + + std::cout << "8" << std::endl; + + addWeapons->setTexture(getContext().textureHolder->get(Textures::addWeapons)); + addWeapons->setTextureRect(rect); + addWeapons->setPosition(160.f, 705.f); + + addWeapons->setCost(true); + addBarraks->setCost(true); + addFarm->setCost(true); + + std::cout << "9" << std::endl; + + addFarm->setCallback([this](int ind) { + if (curPlayer->getGold() >= curPlayer->getFarm().getUpgradeCost()) { + std::cout << "farm" << std::endl; + getContext().multiplayer->outcoming.emplace_back(*getContext().p_id, 'c', "f", + clock + sf::milliseconds(DELAY)); + } + }); + addFarm->setCostCallback([this](int ind) { + printCost = true; + cost.setFont(getContext().fontHolder->get(Fonts::font1)); + cost.setString(std::to_string(curPlayer->getFarm().getUpgradeCost())); + cost.setPosition(290.f, 705.f - TILE_SIZE / 2); +// cost.setOutlineThickness(1.f); + if (curPlayer->getGold() >= curPlayer->getFarm().getUpgradeCost()) { + cost.setColor(sf::Color::Green); + } else { + cost.setColor(sf::Color::Red); + } + }); + + std::cout << "10" << std::endl; + + addBarraks->setCallback([this](int ind) { + if (curPlayer->getGold() >= curPlayer->getBarracks().getUpgradeCost()) { + std::cout << "barraks" << std::endl; + getContext().multiplayer->outcoming.emplace_back(*getContext().p_id, 'c', "b", + clock + sf::milliseconds(DELAY)); + } + }); + + addBarraks->setCostCallback([this](int ind) { + printCost = true; + if (curPlayer->getBarracks().getLvl() == 2) { + printCost = false; + } + cost.setFont(getContext().fontHolder->get(Fonts::font1)); + cost.setString(std::to_string(curPlayer->getBarracks().getUpgradeCost())); + + cost.setPosition(220.f, 705.f - TILE_SIZE / 2); +// cost.setOutlineThickness(1.f); + if (curPlayer->getGold() >= curPlayer->getBarracks().getUpgradeCost()) { + cost.setColor(sf::Color::Green); + } else { + cost.setColor(sf::Color::Red); + } + }); + + std::cout << "11" << std::endl; + + addWeapons->setCallback([this](int ind) { + + if (curPlayer->getGold() >= curPlayer->getWeapons().getUpgradeCost()) { + std::cout << "weapons" << std::endl; + getContext().multiplayer->outcoming.emplace_back(*getContext().p_id, 'c', "w", + clock + sf::milliseconds(DELAY)); + } + }); + + + addWeapons->setCostCallback([this](int ind) { + printCost = true; + if (curPlayer->getWeapons().getLvl() == 3) { + printCost = false; + } + cost.setFont(getContext().fontHolder->get(Fonts::font1)); + cost.setString(std::to_string(curPlayer->getWeapons().getUpgradeCost())); + cost.setPosition(160.f, 705.f - TILE_SIZE / 2); +// cost.setOutlineThickness(1.f); + if (curPlayer->getGold() >= curPlayer->getWeapons().getUpgradeCost()) { + cost.setColor(sf::Color::Green); + } else { + cost.setColor(sf::Color::Red); + } + }); + + std::cout << "12" << std::endl; + + buttons.addWidget(addFarm); + buttons.addWidget(addBarraks); + buttons.addWidget(addWeapons); + std::cout << "end init hud" << std::endl; +} + +bool GameState::handleEvent(const sf::Event& event) { +// std::cout << "handle event" << std::endl; + printCost = false; + container.handleWidgetsEvent(event); + buttons.handleWidgetsEvent(event); + hud.handleEvent(event); + auto action = hud.getAction(); + + if (action == gui::HUD::Action::Exit) { + popState(); + pushState(States::ID::GameOverState); + hud.setAction(gui::HUD::Action::None); + } } bool GameState::update(sf::Time dt) { + timer.setString("00:" + std::to_string(int(waveTimer - clock.asSeconds()) / 10) + std::to_string(int(waveTimer - clock.asSeconds()) % 10)); + for (auto&& event : getContext().multiplayer->incoming) { + events.emplace_back(event.id, event.type, event.value, event.time); + } + + int id = *getContext().p_id; + if (id == 1) { + if (lComponent.getPlayer1()->getHealth() < 0) { + popState(); + pushState(States::ID::GameOverState); // Win Game + } + + if (lComponent.getPlayer2()->getHealth() < 0) { + popState(); + pushState(States::ID::WinState); + } + } + + if (id == 2) { + if (lComponent.getPlayer2()->getHealth() < 0) { + popState(); + pushState(States::ID::GameOverState); // Win Game + } + + if (lComponent.getPlayer1()->getHealth() < 0) { + popState(); + pushState(States::ID::WinState); + } + } + + if (waveTimer <= clock.asSeconds()) { + waveTimer += gameConst.cWAVE_TIMER(); + if (curPlayer->getWarriorsInBuffer() > 0) { + getContext().multiplayer->outcoming.emplace_back(*getContext().p_id, 'w', + Castle::generateWaveString(*curPlayer), + clock + sf::milliseconds(DELAY)); + curPlayer->dropBuffer(); + } + } + + for (auto&& event : getContext().multiplayer->outcoming) { + events.emplace_back(event.id, event.type, event.value, event.time); + } + + if (!getContext().multiplayer->isConnected()) + getContext().multiplayer->outcoming.clear(); + clock += dt; + manageEvents(); + hud.update(dt); + lComponent.update(dt); + gComponent.update(dt, getContext(), lComponent.getBullets()); } void GameState::draw() { + map.draw(); + getContext().window->draw(hud); + getContext().window->draw(buttons); + gComponent.draw(getContext()); + getContext().window->draw(castle1); + getContext().window->draw(castle2); + if (printCost) { + getContext().window->draw(cost); + } + getContext().window->draw(timer); + getContext().window->draw(you); + getContext().window->draw(foe); +} + +void GameState::manageEvents() { + Castle* player = nullptr; + + for(auto event = events.begin(); event != events.end();) { + if (event->time > clock) { + ++event; + continue; + } + std::cout << "pr event " << event->id << " " << event->type << " " << event->value << std::endl; + if (event->id == 1) { + player = lComponent.getPlayer1().get(); + } else { + player = lComponent.getPlayer2().get(); + } + switch (event->type) { + case 't': { + int index = stoi(event->value); + if (player->getGold() >= player->getTowers().at(index).get()->getPrice()) { + if (Castle::checkValidUpgradeTower(player->getTowers().at(index).get()->getType(), + player->getWeapons().getLvl())) { + std::cout << "gold: " << player->getGold() << " |cost: " << player->getTowers().at(index).get()->getPrice() << std::endl; + player->upgradeTower(index); + } + } + break; + } + case 'w': + std::cout << "Wave go!" << std::endl; + if (event->id != *getContext().p_id) { + int rect_num = 0; + if (*getContext().p_id == 2) { + rect_num = 0; + } else { + rect_num = 1; + } + for (auto type : event->value) { + switch (type) { + case '1': + if (player->getGold() >= gameConst.cWARRIOR_1_COST() && player->getBarracks().getLvl() >= 1) { + player->addWarrior(Type::lvlOne, roadRect[rect_num]); + } + break; + + case '2': + if (player->getGold() >= gameConst.cWARRIOR_2_COST() && player->getBarracks().getLvl() >= 2) { + player->addWarrior(Type::lvlTwo, roadRect[rect_num]); + } + break; + } + } + player->dropBuffer(); + } + player->letsMakingWave(); + break; + + case 'c': + int upgradeCost = 0; + switch (event->value[0]) { + case 'f': + upgradeCost = player->getFarm().getUpgradeCost(); + break; + case 'b': + upgradeCost = player->getBarracks().getUpgradeCost(); + break; + case 'w': + upgradeCost = player->getWeapons().getUpgradeCost(); + break; + } + if (upgradeCost != 0 && player->getGold() >= upgradeCost) { + player->upgradeBuilding(event->value[0]); + } + break; + } + event = events.erase(event); + } } + diff --git a/src/GameState.h b/src/GameState.h index 390c917..4dd4403 100644 --- a/src/GameState.h +++ b/src/GameState.h @@ -2,27 +2,66 @@ #define TOWERDEFENSE_GAMESTATE_H #include - +#include #include "ResourceManager/ResourcesHolder.h" #include "ResourceManager/ResourcesIdentifier.h" - #include "State.h" #include "Graphics/Gui.h" +#include "Map.h" +#include "Units/Warrior/Warrior.h" +#include "Graphics/Button.h" +#include "Graphics/HUD.h" +#include "Graphics/GraphicsUnits/GraphicsUnitManager.h" +#include "Units/LogicUnitsManager.h" +#include "GameConstants.h" + class GameState : public State { public: explicit GameState(StateManager& stack, States::Context context); - ~GameState() = default; bool handleEvent(const sf::Event &event) override; bool update(sf::Time dt) override; void draw() override; + void manageEvents(); + + GameConstants& gameConst = GameConstants::instance(); + private: + void initTower(); + void initHUD(); + + std::vector events; + sf::Time clock; + + float waveTimer; + Player::GameData gameData; gui::Gui containter; + Map map; + + LogicUnitsManager lComponent; + GraphicsUnitManager gComponent; + + gui::HUD hud; + std::vector towers1; + std::vector towers2; + gui::Gui container; + gui::Gui buttons; + std::vector roadRect; + + std::shared_ptr curPlayer; + int curPlayerRoad; + sf::Sprite castle1; + sf::Sprite castle2; + sf::Text cost; + bool printCost; + sf::Text timer; + sf::Text you; + sf::Text foe; }; -#endif //TOWERDEFENSE_GAMESTATE_H +#endif //TOWERDEFENSE_GAMESTATE_H \ No newline at end of file diff --git a/src/GameStates.h b/src/GameStates.h index 8f3c4f6..23f9a0a 100644 --- a/src/GameStates.h +++ b/src/GameStates.h @@ -5,10 +5,12 @@ namespace States { enum class ID { None = 0, Game, + MultiplayerGame, + ConnectGame, Menu, Pause, - GameOver, - Win + GameOverState, + WinState }; } diff --git a/src/Graphics/Button.cpp b/src/Graphics/Button.cpp index ae75ed7..de7e950 100644 --- a/src/Graphics/Button.cpp +++ b/src/Graphics/Button.cpp @@ -4,21 +4,48 @@ using namespace gui; Button::Button() : callback(), toggle(false), - selected(false) + selected(false), + isCost(false) {} +void Button::setSprite(sf::Sprite newSprite) { + this->sprite = newSprite; +} + void Button::setCallback(Callback callback) { this->callback = std::move(callback); } +void Button::setCostCallback(Callback callback) { + this->cost = std::move(callback); +} + + +void Button::setCost(bool cost) { + isCost = cost; +} + +void Button::setPrintCost(bool print) { + printCost = print; +} + +void Button::setCostText(sf::Text cost) { + costText = cost; +} + void Button::setTexture(const sf::Texture& texture) { sprite.setTexture(texture); changeTexture(Type::Normal); centerText(); } +void Button::setTextureRect(sf::IntRect rect) { + sprite.setTextureRect(rect); +} + void Button::setText(const std::string& text) { this->text.setString(text); + this->text.setScale(2.f, 2.f); centerText(); } @@ -27,12 +54,16 @@ void Button::setFont(const sf::Font& font) { centerText(); } +void Button::setInd(const int i) { + ind = i; +} + void Button::handleEvent(const sf::Event& event) { sf::FloatRect rect; rect.left = getPosition().x; rect.top = getPosition().y; - rect.width = sprite.getLocalBounds().width * 2; - rect.height = sprite.getLocalBounds().height * 2; + rect.width = sprite.getLocalBounds().width * sprite.getScale().x; + rect.height = sprite.getLocalBounds().height * sprite.getScale().y; switch (event.type) { case sf::Event::MouseButtonPressed: @@ -49,12 +80,11 @@ void Button::handleEvent(const sf::Event& event) { case sf::Event::MouseMoved: if (rect.contains(static_cast(event.mouseMove.x), static_cast(event.mouseMove.y))) { - if (!selected) { - select(); - } - } else { - if (selected) { - deselect(); + if (isCost) { +// std::cout << "Tower " << ind << std::endl; + cost(ind); + } else { +// std::cout << "Not is cost" << std::endl; } } break; @@ -64,7 +94,7 @@ void Button::handleEvent(const sf::Event& event) { void Button::update(sf::Time dt) {} void Button::select() { - changeTexture(Type::Selected); + changeTexture(Type::Normal); selected = true; } @@ -74,17 +104,14 @@ void Button::deselect() { } void Button::activate() { - changeTexture(Type::Pressed); - if (callback) { - callback(); + callback(ind); } deactivate(); } void Button::deactivate() { - changeTexture(Type::Selected); } void Button::draw(sf::RenderTarget& target, sf::RenderStates states) const { @@ -101,7 +128,7 @@ void Button::changeTexture(Type type) { void Button::centerText() { sf::FloatRect rect = text.getGlobalBounds(); text.setOrigin(rect.left, rect.top); - text.setPosition({sprite.getLocalBounds().width + rect.width, - sprite.getLocalBounds().height + rect.height / 2}); + text.setPosition({sprite.getLocalBounds().width + 35, + sprite.getLocalBounds().height + rect.height}); } \ No newline at end of file diff --git a/src/Graphics/Button.h b/src/Graphics/Button.h index 248299c..ab73014 100644 --- a/src/Graphics/Button.h +++ b/src/Graphics/Button.h @@ -8,7 +8,7 @@ namespace gui { class Button : public Widget { public: - using Callback = std::function; + using Callback = std::function; enum Type { Normal = 0, @@ -18,13 +18,19 @@ namespace gui { explicit Button(); + void setSprite(sf::Sprite newSprite); void setCallback(Callback callback); void setTexture(const sf::Texture& texture); + void setTextureRect(sf::IntRect rect); void setText(const std::string& text); void setFont(const sf::Font& font); - + void setInd(const int i); void handleEvent(const sf::Event& event) override ; void update(sf::Time dt) override ; + void setCostCallback(Callback callback); + void setCost(bool cost); + void setPrintCost(bool print); + void setCostText(sf::Text cost); private: void select(); @@ -37,13 +43,18 @@ namespace gui { void centerText(); Callback callback; + Callback cost; sf::Sprite sprite; sf::Text text; + sf::Text costText; + bool printCost; + bool isCost; bool selected; bool toggle; + int ind; }; } -#endif //TOWERDEFENSE_BUTTON_H +#endif //TOWERDEFENSE_BUTTON_H \ No newline at end of file diff --git a/src/Graphics/GraphicsUnits/GraphicsBullet.cpp b/src/Graphics/GraphicsUnits/GraphicsBullet.cpp new file mode 100644 index 0000000..ad3a893 --- /dev/null +++ b/src/Graphics/GraphicsUnits/GraphicsBullet.cpp @@ -0,0 +1,71 @@ +#include "GraphicsBullet.h" +#include + +#define RAD_IN_DEGREE (180 / M_PI) + +GraphicsBullet::GraphicsBullet(std::shared_ptr bullet, States::Context& context) + : explosionTime_(100), + exploded_(false), + finished_(false), + bullet_(bullet) { + switch (bullet->getType()) { + case Type::lvlOne: + sprite_.setTexture(context.textureHolder->get(Textures::bulletOne)); + explosion_.setTexture(context.textureHolder->get(Textures::explosionOne)); + explosion_.setScale({0.5, 0.5}); + break; + case Type::lvlTwo: + sprite_.setTexture(context.textureHolder->get(Textures::bulletTwo)); + sprite_.setScale({0.75, 0.75}); + explosion_.setTexture(context.textureHolder->get(Textures::explosionTwo)); + explosion_.setScale({0.75, 0.75}); + break; + case Type::lvlThree: + sprite_.setTexture(context.textureHolder->get(Textures::bulletThree)); + explosion_.setTexture(context.textureHolder->get(Textures::explosionThree)); + break; + } + sprite_.setOrigin(sprite_.getTextureRect().width / 2, sprite_.getTextureRect().height / 2); + explosion_.setOrigin(explosion_.getTextureRect().width / 2, explosion_.getTextureRect().height / 2); +} + +bool GraphicsBullet::update(const sf::Time& dTime) { + if (bullet_ == nullptr) { + return false; + } + if (bullet_->isDisappeared()) { + finished_ = true; + return true; + } + if (!exploded_) { + if (bullet_->isExploded()) { + exploded_ = true; + explosion_.setPosition(bullet_->getPosition()); + return true; + } + sprite_.setPosition(bullet_->getPosition()); + sprite_.setRotation(static_cast(-bullet_->getAngle() * RAD_IN_DEGREE + 180)); + } else { + explosionTime_ -= dTime.asMilliseconds(); + if (explosionTime_ < 0) { + finished_ = true; + } + } + return false; +} + +void GraphicsBullet::draw(States::Context& context) { + if (!exploded_) { + context.window->draw(sprite_); + } else { + context.window->draw(explosion_); + } +} + +bool GraphicsBullet::isFinished() const { + return finished_; +} + +bool GraphicsBullet::isExploded() const { + return exploded_; +} diff --git a/src/Graphics/GraphicsUnits/GraphicsBullet.h b/src/Graphics/GraphicsUnits/GraphicsBullet.h new file mode 100644 index 0000000..cf2f070 --- /dev/null +++ b/src/Graphics/GraphicsUnits/GraphicsBullet.h @@ -0,0 +1,27 @@ +#ifndef SERVER_GRAPHICSBULLET_H +#define SERVER_GRAPHICSBULLET_H + + +#include "../../GameContext.h" +#include "../../Units/Bullet/Bullet.h" + +class GraphicsBullet { +public: + GraphicsBullet(std::shared_ptr bullet, States::Context& context); + bool update(const sf::Time& dTime); + void draw(States::Context& context); + + bool isFinished() const; + bool isExploded() const; + +private: + std::shared_ptr bullet_; + sf::Sprite sprite_; + sf::Sprite explosion_; + sf::Int32 explosionTime_; + bool exploded_; + bool finished_; +}; + + +#endif //SERVER_GRAPHICSBULLET_H diff --git a/src/Graphics/GraphicsUnits/GraphicsCastle.cpp b/src/Graphics/GraphicsUnits/GraphicsCastle.cpp new file mode 100644 index 0000000..00e595e --- /dev/null +++ b/src/Graphics/GraphicsUnits/GraphicsCastle.cpp @@ -0,0 +1,47 @@ +#include "GraphicsCastle.h" +#include "../../Castle/Castle.h" + +GraphicsCastle::GraphicsCastle(States::Context& context, Castle& castle) + : castle_(castle), + gWarriors_(), + gTower_(std::make_unique(context)) { + for (auto warrior: castle.getWarriors()) { + gWarriors_.push_back(std::make_shared(warrior, context)); + } + numAliveWarriors_ = gWarriors_.size(); +} + +void GraphicsCastle::update(const sf::Time& dTime, States::Context& context) { + size_t numRealWarriors = castle_.getWarriors().size(); + if (numRealWarriors != 0 || numAliveWarriors_ != 0) { + } + if (numRealWarriors > numAliveWarriors_) { + auto realWarriorsIterator = castle_.getWarriors().end(); + size_t i = 0; + for (; i < numRealWarriors - numAliveWarriors_; ++i) { + realWarriorsIterator--; + gWarriors_.push_back(std::make_shared(*realWarriorsIterator, context)); + } + numAliveWarriors_ += i; + } + for (auto gWarrior = gWarriors_.begin(); gWarrior != gWarriors_.end();) { + if ((*gWarrior)->update(dTime)) { + --numAliveWarriors_; + } + + if ((*gWarrior)->isFinished()) { + gWarrior = gWarriors_.erase(gWarrior); + } else { + ++gWarrior; + } + } +} + +void GraphicsCastle::draw(States::Context& context, int id) { + for (const auto &gWarrior: gWarriors_) { + gWarrior->draw(context); + } + for (const auto &tower: castle_.getTowers()) { + gTower_->draw(context, tower, id); + } +} \ No newline at end of file diff --git a/src/Graphics/GraphicsUnits/GraphicsCastle.h b/src/Graphics/GraphicsUnits/GraphicsCastle.h new file mode 100644 index 0000000..6fe1d03 --- /dev/null +++ b/src/Graphics/GraphicsUnits/GraphicsCastle.h @@ -0,0 +1,26 @@ +#ifndef SERVER_GRAPHICSCASTLE_H +#define SERVER_GRAPHICSCASTLE_H + + +#include +#include "../../GameContext.h" +#include "GraphicsWarrior.h" +#include "GraphicsTower.h" + +class Castle; + +class GraphicsCastle { +public: + GraphicsCastle(States::Context& context, Castle& castle); + void update(const sf::Time& dTime, States::Context& context); + void draw(States::Context& context, int id); + +private: + Castle& castle_; + std::list> gWarriors_; + std::unique_ptr gTower_; + size_t numAliveWarriors_; +}; + + +#endif //SERVER_GRAPHICSCASTLE_H diff --git a/src/Graphics/GraphicsUnits/GraphicsTower.cpp b/src/Graphics/GraphicsUnits/GraphicsTower.cpp new file mode 100644 index 0000000..f84abc7 --- /dev/null +++ b/src/Graphics/GraphicsUnits/GraphicsTower.cpp @@ -0,0 +1,78 @@ +#include +#include +#include "GraphicsTower.h" + +GraphicsTower::GraphicsTower(States::Context &context) { + towerZeroRed_.setTexture(context.textureHolder->get(Textures::towerZeroRed)); + towerZeroRed_.setOrigin(towerZeroRed_.getTextureRect().width / 2, towerZeroRed_.getTextureRect().height / 2); + towerZeroBlue_.setTexture(context.textureHolder->get(Textures::towerZeroBlue)); + towerZeroBlue_.setOrigin(towerZeroBlue_.getTextureRect().width / 2, towerZeroBlue_.getTextureRect().height / 2); + + towerTopLvlOne_.setTexture(context.textureHolder->get(Textures::towerOneTop)); + towerTopLvlOne_.setOrigin(towerTopLvlOne_.getTextureRect().width / 2, towerTopLvlOne_.getTextureRect().height / 2); + towerBaseLvlOne_.setTexture(context.textureHolder->get(Textures::towerOneBase)); + towerBaseLvlOne_.setOrigin(towerBaseLvlOne_.getTextureRect().width / 2, towerBaseLvlOne_.getTextureRect().height / 2); + + towerTopLvlTwo_.setTexture(context.textureHolder->get(Textures::towerTwoTop)); + towerTopLvlTwo_.setOrigin(towerTopLvlTwo_.getTextureRect().width / 2, towerTopLvlTwo_.getTextureRect().height / 2); + towerBaseLvlTwo_.setTexture(context.textureHolder->get(Textures::towerTwoBase)); + towerBaseLvlTwo_.setOrigin(towerBaseLvlTwo_.getTextureRect().width / 2, towerBaseLvlTwo_.getTextureRect().height / 2); + + towerTopLvlThree_.setTexture(context.textureHolder->get(Textures::towerThreeTop)); + towerTopLvlThree_.setOrigin(towerTopLvlThree_.getTextureRect().width / 2, towerTopLvlThree_.getTextureRect().height / 2); + towerBaseLvlThree_.setTexture(context.textureHolder->get(Textures::towerThreeBase)); + towerBaseLvlThree_.setOrigin(towerBaseLvlThree_.getTextureRect().width / 2, towerBaseLvlThree_.getTextureRect().height / 2); +} + +void GraphicsTower::draw(States::Context& context, const std::shared_ptr& tower, int id) { + if (tower == nullptr) { + return; + } + switch (tower->getType()) { + case Type::lvlZero: + if (id == 1) { + towerZeroRed_.setPosition(tower->getPosition()); + context.window->draw(towerZeroRed_); + } else { + towerZeroBlue_.setPosition(tower->getPosition()); + context.window->draw(towerZeroBlue_); + } + break; + case Type::lvlOne: + towerBaseLvlOne_.setPosition(tower->getPosition()); + if (id == 1) { + towerBaseLvlOne_.setColor(red_); + } else { + towerBaseLvlOne_.setColor(blue_); + } + towerTopLvlOne_.setPosition(tower->getPosition()); + towerTopLvlOne_.setRotation(tower->getAngle()); + context.window->draw(towerBaseLvlOne_); + context.window->draw(towerTopLvlOne_); + break; + case Type::lvlTwo: + towerBaseLvlTwo_.setPosition(tower->getPosition()); + if (id == 1) { + towerBaseLvlTwo_.setColor(red_); + } else { + towerBaseLvlTwo_.setColor(blue_); + } + towerTopLvlTwo_.setPosition(tower->getPosition()); + towerTopLvlTwo_.setRotation(tower->getAngle()); + context.window->draw(towerBaseLvlTwo_); + context.window->draw(towerTopLvlTwo_); + break; + case Type::lvlThree: + towerBaseLvlThree_.setPosition(tower->getPosition()); + if (id == 1) { + towerBaseLvlThree_.setColor(red_); + } else { + towerBaseLvlThree_.setColor(blue_); + } + towerTopLvlThree_.setPosition(tower->getPosition()); + towerTopLvlThree_.setRotation(tower->getAngle()); + context.window->draw(towerBaseLvlThree_); + context.window->draw(towerTopLvlThree_); + break; + } +} \ No newline at end of file diff --git a/src/Graphics/GraphicsUnits/GraphicsTower.h b/src/Graphics/GraphicsUnits/GraphicsTower.h new file mode 100644 index 0000000..d6d0d3c --- /dev/null +++ b/src/Graphics/GraphicsUnits/GraphicsTower.h @@ -0,0 +1,29 @@ +#ifndef SERVER_GRAPHICSTOWER_H +#define SERVER_GRAPHICSTOWER_H + + +#include +#include "../../GameContext.h" +#include "../../Units/Tower/Tower.h" + +class GraphicsTower { +public: + explicit GraphicsTower(States::Context& context); + void draw(States::Context& context, const std::shared_ptr& tower, int id); + +private: + sf::Sprite towerZeroRed_; + sf::Sprite towerZeroBlue_; + sf::Sprite towerTopLvlOne_; + sf::Sprite towerBaseLvlOne_; + sf::Sprite towerTopLvlTwo_; + sf::Sprite towerBaseLvlTwo_; + sf::Sprite towerTopLvlThree_; + sf::Sprite towerBaseLvlThree_; + + const sf::Color red_ = sf::Color(255, 136, 138); + const sf::Color blue_ = sf::Color(91, 171, 232); +}; + + +#endif //SERVER_GRAPHICSTOWER_H diff --git a/src/Graphics/GraphicsUnits/GraphicsUnitManager.cpp b/src/Graphics/GraphicsUnits/GraphicsUnitManager.cpp new file mode 100644 index 0000000..89a276f --- /dev/null +++ b/src/Graphics/GraphicsUnits/GraphicsUnitManager.cpp @@ -0,0 +1,42 @@ +#include "GraphicsUnitManager.h" + + +GraphicsUnitManager::GraphicsUnitManager(States::Context& context ,Castle& castle1, Castle& castle2) + : gCastle1(std::make_shared(GraphicsCastle(context, castle1))), + gCastle2(std::make_shared(GraphicsCastle(context, castle2))), + gBullets(), + intactBulletsCounter(0) {} + +void GraphicsUnitManager::update(const sf::Time& dt, States::Context& context, const std::vector>& bullets) { + gCastle1->update(dt, context); + gCastle2->update(dt, context); + + if (bullets.size() > intactBulletsCounter) { + auto realBulletsIterator = bullets.end(); + for (size_t i = 0; i < bullets.size() - intactBulletsCounter; ++i) { + realBulletsIterator--; + gBullets.push_back(std::make_shared(GraphicsBullet(*realBulletsIterator, context))); + } + intactBulletsCounter = bullets.size(); + } + + for (auto gBullet = gBullets.begin(); gBullet != gBullets.end();) { + if ((*gBullet)->isFinished()) { + gBullet = gBullets.erase(gBullet); + } else { + + if ((*gBullet)->update(dt)) { + --intactBulletsCounter; + } + ++gBullet; + } + } +} + +void GraphicsUnitManager::draw(States::Context& context) { + gCastle1->draw(context, 1); + gCastle2->draw(context, 2); + for (const auto &gBullet: gBullets) { + gBullet->draw(context); + } +} \ No newline at end of file diff --git a/src/Graphics/GraphicsUnits/GraphicsUnitManager.h b/src/Graphics/GraphicsUnits/GraphicsUnitManager.h new file mode 100644 index 0000000..c2087f5 --- /dev/null +++ b/src/Graphics/GraphicsUnits/GraphicsUnitManager.h @@ -0,0 +1,25 @@ +#ifndef SERVER_GRAPHICSUNITMANAGER_H +#define SERVER_GRAPHICSUNITMANAGER_H + + +#include "../../Castle/Castle.h" +#include "GraphicsCastle.h" +#include "GraphicsBullet.h" + +class GraphicsUnitManager { +public: + GraphicsUnitManager(States::Context& context, Castle& castle1, Castle& castle2); + + void update(const sf::Time &dt, States::Context& context, const std::vector>& bullets); + void draw(States::Context& context); + +private: + std::shared_ptr gCastle1; + std::shared_ptr gCastle2; + + std::vector> gBullets; + size_t intactBulletsCounter; +}; + + +#endif //SERVER_GRAPHICSUNITMANAGER_H diff --git a/src/Graphics/GraphicsUnits/GraphicsWarrior.cpp b/src/Graphics/GraphicsUnits/GraphicsWarrior.cpp new file mode 100644 index 0000000..f9da614 --- /dev/null +++ b/src/Graphics/GraphicsUnits/GraphicsWarrior.cpp @@ -0,0 +1,106 @@ +#include +#include +#include "GraphicsWarrior.h" + +#define FRAMES 4 +#define DEATH_DURATION 2000 //msec +#define FINISHING_DURATION 200 //msec +#define ANIMATION_SPEED 10 + + +GraphicsWarrior::GraphicsWarrior(std::shared_ptr& warrior, States::Context& context) + : warrior_(warrior), + deathDuration_(DEATH_DURATION), + finishedDuration_(FINISHING_DURATION), + died_(false), + finishing_(false), + finished_(false) { + switch (warrior_->getType()) { + case Type::lvlOne: + sprite_.setTexture(context.textureHolder->get(Textures::warriorOne)); + break; + case Type::lvlTwo: + sprite_.setTexture(context.textureHolder->get(Textures::warriorTwo)); + break; + } + sprite_.setScale({0.5, 0.5}); + warriorSpriteRect_.first = sprite_.getTextureRect().width / FRAMES; + warriorSpriteRect_.second = sprite_.getTextureRect().height; + sprite_.setTextureRect(sf::IntRect(0, 0, warriorSpriteRect_.first, warriorSpriteRect_.second)); + sprite_.setOrigin(warriorSpriteRect_.first / 2, warriorSpriteRect_.second / 2); + deadSprite_.setTexture(context.textureHolder->get(Textures::blood)); + deadSprite_.setOrigin(deadSprite_.getTextureRect().width / 2, deadSprite_.getTextureRect().height / 2); + explosionSprite_.setTexture(context.textureHolder->get(Textures::warriorExplosion)); + explosionSprite_.setOrigin(deadSprite_.getTextureRect().width / 2, deadSprite_.getTextureRect().height / 2); +} + +bool GraphicsWarrior::update(const sf::Time& dTime) { + if (!finishing_ && !died_ && warrior_ != nullptr) { + if (!warrior_->isAlive()) { + deadSprite_.setPosition(warrior_->getPosition()); + died_ = true; + warrior_.reset(); + return true; + } + if (warrior_->isFinished()) { + explosionSprite_.setPosition(warrior_->getPosition()); + if (warrior_.get()->getType() == Type::lvlTwo) { + explosionSprite_.setScale({1.5, 1.5}); + } + finishing_ = true; + warrior_.reset(); + return true; + } + lifeAnimation(dTime); + } else if (died_) { + deathAnimation(dTime); + } else { + finishedAnimation(dTime); + } + return false; + +} + +void GraphicsWarrior::draw(const States::Context& context) { + if (died_) { + context.window->draw(deadSprite_); + } else if (finishing_) { + context.window->draw(explosionSprite_); + } else { + context.window->draw(sprite_); + } +} + +bool GraphicsWarrior::isFinished() const { + return finished_; +} + +void GraphicsWarrior::lifeAnimation(const sf::Time& dTime) { + currentFrame_ += ANIMATION_SPEED * dTime.asSeconds(); + if (currentFrame_ >= FRAMES) + currentFrame_ -= FRAMES; + sprite_.setTextureRect(sf::IntRect(warriorSpriteRect_.first * static_cast(currentFrame_), 0, + warriorSpriteRect_.first, warriorSpriteRect_.second)); + sprite_.setPosition(warrior_->getPosition()); + sprite_.setRotation(warrior_->getDirection()); +} + +void GraphicsWarrior::deathAnimation(const sf::Time& dTime) { + deathDuration_ -= dTime.asMilliseconds(); + if (deathDuration_ <= 0) { + finished_ = true; + return; + } +} + +bool GraphicsWarrior::isDied() const { + return died_; +} + +void GraphicsWarrior::finishedAnimation(const sf::Time& dTime) { + finishedDuration_ -= dTime.asMilliseconds(); + if (finishedDuration_ <= 0) { + finished_ = true; + return; + } +} diff --git a/src/Graphics/GraphicsUnits/GraphicsWarrior.h b/src/Graphics/GraphicsUnits/GraphicsWarrior.h new file mode 100644 index 0000000..656b238 --- /dev/null +++ b/src/Graphics/GraphicsUnits/GraphicsWarrior.h @@ -0,0 +1,37 @@ +#ifndef SERVER_GRAPHICSWARRIOR_H +#define SERVER_GRAPHICSWARRIOR_H + + +#include +#include +#include "../../GameContext.h" +#include "../../Units/Warrior/Warrior.h" + +class GraphicsWarrior { +public: + explicit GraphicsWarrior(std::shared_ptr& warrior, States::Context& context); + bool update(const sf::Time& dTime); + void draw(const States::Context& context); + + bool isFinished() const; + bool isDied() const; + +private: + void lifeAnimation(const sf::Time& dTime); + void deathAnimation(const sf::Time& dTime); + void finishedAnimation(const sf::Time& dTime); + + std::shared_ptr warrior_; + sf::Sprite sprite_; + std::pair warriorSpriteRect_;// + sf::Sprite deadSprite_; + sf::Sprite explosionSprite_; + sf::Int32 deathDuration_; + sf::Int32 finishedDuration_; + float currentFrame_; + bool died_; + bool finishing_; + bool finished_; +}; + +#endif //SERVER_GRAPHICSWARRIOR_H diff --git a/src/Graphics/HUD.cpp b/src/Graphics/HUD.cpp index 99044b7..98b23e3 100644 --- a/src/Graphics/HUD.cpp +++ b/src/Graphics/HUD.cpp @@ -1,5 +1,179 @@ +#include "HUD.h" +#include "../StateManager.h" +#include "../ResourceManager/ResourcesHolder.h" +#include "../ResourceManager/ResourcesIdentifier.h" + +using namespace gui; + +HUD::HUD(States::Context context, std::shared_ptr player1, std::shared_ptr player2) + : context(context), + gold(context.textureHolder->get(Textures::gold), context.fontHolder->get(Fonts::font1)), + livePlayer(context.textureHolder->get(Textures::lives), context.fontHolder->get(Fonts::font1)), + liveFoe(context.textureHolder->get(Textures::lives), context.fontHolder->get(Fonts::font1)), + levelBarraks(context.textureHolder->get(Textures::barraks), context.fontHolder->get(Fonts::font1)), + levelFarm(context.textureHolder->get(Textures::farm), context.fontHolder->get(Fonts::font1)), + levelWeapons(context.textureHolder->get(Textures::weapons), context.fontHolder->get(Fonts::font1)){ + + if (*context.p_id == 1) { + player = player1; + foe = player2; + } else { + player = player2; + foe = player1; + } + + auto exit = std::make_shared(); + + exit->setTexture(context.textureHolder->get(Textures::exit), context.textureHolder->get(Textures::exit)); + exit->setPosition({1120.f, 5.f}); + exit->setCallback([this] + { + action = Action::Exit; + + }); + + container.addWidget(exit); +} + +void HUD::init() +{ + std::cout << "HUD::init()" << std::endl; + + sf::IntRect rect{ TILE_SIZE * (15), TILE_SIZE * (0), TILE_SIZE, TILE_SIZE }; + for (int i = 0; i < 10; i++) { + sf::RectangleShape tmp; + tmp.setPosition(350.f + i * 50.f, 710.f); + tmp.setSize(sf::Vector2f(50, 50)); + tmp.setTexture(&context.textureHolder->get(Textures::map)); + tmp.setTextureRect(rect); + buffer.push_back(tmp); + } + + gold.setTexture(context.textureHolder->get(Textures::gold)); + gold.setPosition(785.f, 0.f); + + if (*context.p_id == 1) { + livePlayer.setPosition(0.f, 5.f); + liveFoe.setPosition(970.f, 5.f); + } else { + liveFoe.setPosition(0.f, 5.f); + livePlayer.setPosition(970.f, 5.f); + } + + livePlayer.setTexture(context.textureHolder->get(Textures::lives)); + livePlayer.setScale({1.f / 3.f, 1.f / 3.f}); + liveFoe.setTexture(context.textureHolder->get(Textures::lives)); + liveFoe.setScale({1.f / 3.f, 1.f / 3.f}); + + totalGold.setFont(context.fontHolder->get(Fonts::font1)); + totalGold.setString(std::to_string(player->getGold())); + totalGold.setPosition(835.f, 10.f); // -// Created by Falcon on 11.04.2018. -// + totalPlayerLives.setFont(context.fontHolder->get(Fonts::font1)); + totalFoeLives.setFont(context.fontHolder->get(Fonts::font1)); + totalPlayerLives.setString(std::to_string(player->getHealth())); + totalFoeLives.setString(std::to_string(foe->getHealth())); + totalLevelFarm.setFont(context.fontHolder->get(Fonts::font1)); + totalLevelBarraks.setFont(context.fontHolder->get(Fonts::font1)); + totalLevelWeapons.setFont(context.fontHolder->get(Fonts::font1)); -#include "HUD.h" + totalLevelBarraks.setString(std::to_string(player->getBarracks().getLvl())); + totalLevelFarm.setString(std::to_string(player->getFarm().getLvl())); + totalLevelWeapons.setString(std::to_string(player->getWeapons().getLvl())); + + totalLevelWeapons.setPosition(285.f, 10.f); + totalLevelFarm.setPosition(590.f, 10.f); + totalLevelBarraks.setPosition(425.f, 10.f); + + levelFarm.setTexture(context.textureHolder->get(Textures::farm)); + levelBarraks.setTexture(context.textureHolder->get(Textures::barraks)); + levelWeapons.setTexture(context.textureHolder->get(Textures::weapons)); + + levelBarraks.setPosition(370.f, 5.f); + levelFarm.setPosition(520.f, 5.f); + levelWeapons.setPosition(220.f, 5.f); + + totalLevelFarm.setString(std::to_string(player->getFarm().getLvl())); + totalLevelWeapons.setString(std::to_string(player->getWeapons().getLvl())); + + if (*context.p_id == 1) { + totalFoeLives.setPosition(50.f, 10.f); + totalPlayerLives.setPosition(1020.f, 10.f); + } else { + totalPlayerLives.setPosition(50.f, 10.f); + totalFoeLives.setPosition(1020.f, 10.f); + } +} + +void HUD::handleEvent(const sf::Event &event) +{ + container.handleWidgetsEvent(event); +} + +void HUD::update(sf::Time dt) +{ + totalGold.setString(std::to_string(player->getGold())); + totalPlayerLives.setString(std::to_string(foe->getHealth())); + totalFoeLives.setString(std::to_string(player->getHealth())); + + totalLevelBarraks.setString(std::to_string(player->getBarracks().getLvl())); + totalLevelFarm.setString(std::to_string(player->getFarm().getLvl())); + totalLevelWeapons.setString(std::to_string(player->getWeapons().getLvl())); +} + + + + +void gui::HUD::setAction(Action action) +{ + this->action = action; +} + +const HUD::Action HUD::getAction() const +{ + return action; +} + +void HUD::draw(sf::RenderTarget &target, sf::RenderStates states) const +{ + states.transform *= getTransform(); + target.draw(gold); + target.draw(livePlayer); + target.draw(liveFoe); + target.draw(totalGold); + target.draw(totalPlayerLives); + target.draw(totalFoeLives); + target.draw(container); + target.draw(totalLevelWeapons); + target.draw(totalLevelBarraks); + target.draw(totalLevelFarm); + target.draw(levelFarm); + target.draw(levelWeapons); + target.draw(levelBarraks); + + for (auto i : buffer) { + target.draw(i); + } + + auto p = 0.f; + + size_t i = 0; + for (auto warrior : player->getWarriorsBuffer()) { + if (i++ < player->getWarriorsToWave()) { + continue; + } + sf::Sprite tmp; + sf::IntRect rect{ 0, 0, TILE_SIZE, TILE_SIZE }; + tmp.setTextureRect(rect); + if (warrior->getType() == Type::lvlOne) { + tmp.setTexture(context.textureHolder->get(Textures::warriorIconOne)); + } else { + tmp.setTexture(context.textureHolder->get(Textures::warriorIconTwo)); + } + tmp.setPosition(355.f + p, 715.f); + + tmp.setScale(1.f / 2.f, 1.f / 2.f); + p += 50.f; + target.draw(tmp); + } +} \ No newline at end of file diff --git a/src/Graphics/HUD.h b/src/Graphics/HUD.h index 5da6a90..37f0bfd 100644 --- a/src/Graphics/HUD.h +++ b/src/Graphics/HUD.h @@ -1,14 +1,75 @@ -// -// Created by Falcon on 11.04.2018. -// +#pragma once -#ifndef TOWERDEFENSE_HUD_H -#define TOWERDEFENSE_HUD_H +#include "Widget.h" +#include "Button.h" +#include "Icon.h" +#include "Gui.h" +#include "../GameContext.h" +//#include "Tower.h" +#include "../Castle/Castle.h" +#include "Label.h" +namespace gui +{ + class HUD : public Widget + { + public: + enum class Action + { + None, + Audio, + Music, + Pause, + Forward, + Upgrade, + Sell, + Exit + }; -class HUD { + HUD(States::Context context, std::shared_ptr player1, std::shared_ptr player2); -}; + void init(); + void handleEvent(const sf::Event &event) override; + void update(sf::Time dt) override; + + void setAction(Action action); + const Action getAction() const; + + private: + virtual void draw(sf::RenderTarget &target, sf::RenderStates states) const override; + + Action action; + + Gui container; + States::Context context; + //Player::GameData *gameData; + std::shared_ptr player; + std::shared_ptr foe; + sf::Texture texture; + sf::Font font; + + + Label gold; + Label livePlayer; + Label liveFoe; + + Label levelBarraks; + Label levelFarm; + Label levelWeapons; + +// Label star; + + sf::Text totalGold; + sf::Text totalPlayerLives; + sf::Text totalFoeLives; + sf::Text totalLevelBarraks; + sf::Text totalLevelFarm; + sf::Text totalLevelWeapons; + sf::Text currentLevel; + sf::Text score; + std::vector buffer; + sf::RectangleShape background; + }; +} -#endif //TOWERDEFENSE_HUD_H diff --git a/src/Graphics/Icon.cpp b/src/Graphics/Icon.cpp index d7fd193..99e4234 100644 --- a/src/Graphics/Icon.cpp +++ b/src/Graphics/Icon.cpp @@ -2,69 +2,85 @@ using namespace gui; -Icon::Icon() : callback(), - toggle(false), - selected(false) -{} +Icon::Icon() + : callback() + , toggle(false) + , selected(false) +{ +} -void Icon::setCallback(Callback callback) { +void Icon::setCallback(Callback callback) +{ this->callback = std::move(callback); } -void Icon::setTexture(const sf::Texture& texture1, const sf::Texture& texture2) { +void Icon::setTexture(const sf::Texture &texture1, const sf::Texture &texture2) +{ sprite1.setTexture(texture1); sprite2.setTexture(texture2); sprite = sprite1; changeTexture(Type::Normal); } -void Icon::handleEvent(const sf::Event &event) { + + +void Icon::handleEvent(const sf::Event &event) +{ sf::FloatRect rect; rect.left = getPosition().x; - rect.top = getPosition().y; - rect.width = sprite.getLocalBounds().width; + rect.top = getPosition().y; + rect.width = sprite.getLocalBounds().width; rect.height = sprite.getLocalBounds().height; - switch (event.type) { + switch (event.type) + { case sf::Event::MouseButtonPressed: case sf::Event::MouseButtonReleased: - if (rect.contains(static_cast(event.mouseButton.x), - static_cast(event.mouseButton.y))) { - if (event.type == sf::Event::MouseButtonPressed) { + if (rect.contains(static_cast(event.mouseButton.x), static_cast(event.mouseButton.y))) + { + if (event.type == sf::Event::MouseButtonPressed) + { activate(); } } break; } - } -void Icon::update(sf::Time dt) {} +void Icon::update(sf::Time dt) +{ +} -void Icon::activate() { - if (callback) { +void Icon::activate() +{ + if (callback) callback(); - } - if (toggle) { + if (toggle) + { deactivate(); - } else { + } else + { sprite = sprite2; toggle = true; } } -void Icon::deactivate() { +void Icon::deactivate() +{ sprite = sprite1; toggle = false; } -void Icon::draw(sf::RenderTarget &target, sf::RenderStates states) const { +void Icon::draw(sf::RenderTarget &target, sf::RenderStates states) const +{ states.transform *= getTransform(); target.draw(sprite, states); target.draw(text, states); } -void Icon::changeTexture(Type type) { +void Icon::changeTexture(Type type) +{ sf::IntRect textureRect(190 * type, 0, 50, 50); sprite.setTextureRect(textureRect); -} \ No newline at end of file +} + diff --git a/src/Graphics/Icon.h b/src/Graphics/Icon.h index 4a90ba4..219966b 100644 --- a/src/Graphics/Icon.h +++ b/src/Graphics/Icon.h @@ -1,15 +1,18 @@ -#ifndef TOWERDEFENSE_ICON_H -#define TOWERDEFENSE_ICON_H +#pragma once #include #include "Widget.h" -namespace gui { - class Icon : public Widget { +namespace gui +{ + class Icon : public Widget + { + public: using Callback = std::function; - enum Type { + enum Type + { Normal = 0, Selected, Pressed @@ -18,29 +21,25 @@ namespace gui { explicit Icon(); void setCallback(Callback callback); - void setTexture(const sf::Texture& texture1, - const sf::Texture& texture2); - void handleEvent(const sf::Event& event) override ; + void setTexture(const sf::Texture &texture1, const sf::Texture &texture2); + void handleEvent(const sf::Event &event) override; void update(sf::Time dt) override; private: void activate(); void deactivate(); - virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override; + virtual void draw(sf::RenderTarget &target, sf::RenderStates states) const override; void changeTexture(Type type); - Callback callback; + + Callback callback; sf::Sprite sprite; sf::Sprite sprite1; sf::Sprite sprite2; - sf::Text text; + sf::Text text; bool selected; bool toggle; - }; -} - - -#endif //TOWERDEFENSE_ICON_H +} \ No newline at end of file diff --git a/src/Graphics/Label.cpp b/src/Graphics/Label.cpp index 9231da1..9c9ac43 100644 --- a/src/Graphics/Label.cpp +++ b/src/Graphics/Label.cpp @@ -2,7 +2,10 @@ using namespace gui; -Label::Label() {} +Label::Label(sf::Texture texture, sf::Font &font) { + sprite.setTexture(texture); + text.setFont(font); +} void Label::handleEvent(const sf::Event &event) { sf::FloatRect rect = sprite.getGlobalBounds(); diff --git a/src/Graphics/Label.h b/src/Graphics/Label.h index b913512..db9d045 100644 --- a/src/Graphics/Label.h +++ b/src/Graphics/Label.h @@ -5,8 +5,8 @@ namespace gui { class Label : public Widget { - Label(); - + public: + Label(sf::Texture texture, sf::Font &font); void handleEvent(const sf::Event& event) override; void update(sf::Time dt) override ; diff --git a/src/Graphics/TextBox.cpp b/src/Graphics/TextBox.cpp new file mode 100644 index 0000000..812883f --- /dev/null +++ b/src/Graphics/TextBox.cpp @@ -0,0 +1,83 @@ +#include "TextBox.h" + +#include + +using namespace gui; + +Textbox::Textbox(sf::Font &font): font(font), is_focused(false) { + text = sf::Text("", font); + background.setFillColor(sf::Color::White); + text.setColor(sf::Color::Black); +} + +void Textbox::update(sf::Time dt) { } + +void Textbox::draw(sf::RenderTarget& target, sf::RenderStates states) const { + target.draw(background, states); + target.draw(text, states); +} + +void Textbox::setDimensons(float newX, float newY, float newWidth, float newHeight) { + x = newX; + y = newY; + width = newWidth; + height = newHeight; + text.setPosition(x, y-height/5); + text.setCharacterSize(height); + background.setPosition(x, y); + background.setSize(sf::Vector2f(width, height)); +} + +void Textbox::setString(const std::string &newString) { + string = newString; + text.setString(string); +} + +const std::string & Textbox::getString() { + return string; +} + +void Textbox::handleEvent(const sf::Event &event) { + sf::FloatRect rect; + rect.left = x; + rect.top = y; + rect.width = width; + rect.height = height; + + if (event.type == sf::Event::MouseButtonPressed) + is_focused = rect.contains(event.mouseButton.x, event.mouseButton.y); + + if (is_focused && !string.empty() && event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Return) { + is_focused = false; + // todo прочекать строку, чтобы не было пробелов и прочих гадостей + callback(ind); + string.clear(); + } + + if (is_focused && event.type == sf::Event::TextEntered) { + enterText(event.text.unicode); + } + + +} + +bool Textbox::enterText(sf::Uint32 unicode) { + if(unicode == 8) + string = string.substr(0, string.length()-1); // delete key + else if(unicode == 10) + return true; // return key + else + if (string.size() <= 10) { + string += (char) unicode; + } + text.setString(string); + return false; +} + +void Textbox::setCallback(Textbox::Callback callback) { + this->callback = std::move(callback); +} + +void Textbox::setInd(const int i) { + ind = i; +} diff --git a/src/Graphics/TextBox.h b/src/Graphics/TextBox.h new file mode 100644 index 0000000..c3632eb --- /dev/null +++ b/src/Graphics/TextBox.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include +#include +#include +#include "Widget.h" +namespace gui { + class Textbox : public Widget { + public: + using Callback = std::function; + + explicit Textbox(sf::Font &font); + + void draw(sf::RenderTarget& target, sf::RenderStates states) const override; + void update(sf::Time dt) override ; + void handleEvent(const sf::Event& event) override ; + + void setDimensons(float newX, float newY, float newWidth, float newHeight); + void setString(const std::string &newString); + void setInd(int i); + void setCallback(Callback callback); + + const std::string & getString(); + + private: + bool is_focused; + + float x; + float y; + float width; + float height; + std::string string; + sf::Font &font; + sf::RectangleShape background; + sf::Text text; + + int ind; + Callback callback; + + bool enterText(sf::Uint32 unicode); + }; +} \ No newline at end of file diff --git a/src/Map.cpp b/src/Map.cpp new file mode 100644 index 0000000..7505594 --- /dev/null +++ b/src/Map.cpp @@ -0,0 +1,316 @@ +#include "Map.h" +#include + + +Map::Map(sf::RenderWindow &window) : window(window) { + std::ifstream fin("Resources/map.csv"); + texture.loadFromFile("Resources/map1.png"); + fin >> count; + fin >> height >> width; + map.resize(height, std::vector(width)); + int tileNumber; + + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + fin >> tileNumber; + map[i][j].setTileNumber(tileNumber); + if (tileNumber == 13 || tileNumber == 14) { + map[i][j].setTileNumber(tileNumber); + tileNumber = 16; + } + sf::IntRect rect{ TILE_SIZE * (tileNumber % 15), TILE_SIZE * (tileNumber / 15), TILE_SIZE, TILE_SIZE }; + map[i][j].setTexture(texture, rect); + map[i][j].setPosition(static_cast(j * TILE_SIZE), static_cast(i * TILE_SIZE)); + } + } + + for (int i = 0; i < count; i++) { + std::pair tmp; + fin >> tmp.second >> tmp.first; + start.push_back(tmp); + } + fin.close(); +} + + +void Map::analyze(std::vector& towers1, std::vector& towers2) { + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + if (map[i][j].getTileNumber() == 13 || map[i][j].getTileNumber() == 14) { + sf::Vector2f tmp((j + 0.5) * TILE_SIZE, (i + 0.5) * TILE_SIZE); + if (map[i][j].getTileNumber() == 13) { + towers1.push_back(tmp); + } else { + towers2.push_back(tmp); + } + } + } + } + + //std::cout << width << " " << height << " " << start.first << " " << start.second << std::endl; + int move = 0; // 1 - down, 2 - up, 3 - right, 4 - left, 0 - default + + for (auto s: start) { + std::cout << "start.x "<< s.first << " start.y " << s.second << ";" << std::endl; + LogicMap tmpRoadRect; + if (s.first == 0) { + move = 3; + } else if (s.first == (width - 1)) { + move = 4; + } else if (s.second == 0) { + move = 1; + } else if (s.second == (height - 1)) { + move = 2; + } + if ((s.first == 0) && (s.second == 3)) { + move = 2; + } + + if ((s.first == 17) && (s.second == 8)) { + move = 1; + } + + std::cout << move << std::endl; + + std::pair this1, this2; + this1.first = s.second; + this1.second = s.first; + this2.first = s.second; + this2.second = s.first; + + std::pair rect; + rect.first.height = 0; + rect.first.width = 0; + + + std::cout << s.first << " " << s.second << " " << move << std::endl; + if (move == 1 || move == 2) { + this2.second = this1.second + 1; + rect.first.width = TILE_SIZE; + sf::Vector2f st((s.first + 1) * TILE_SIZE, (s.second) * TILE_SIZE); + if (move == 1) { + rect.first.top = (s.second) * TILE_SIZE; + rect.first.left = (s.first + 0.5) * TILE_SIZE; + rect.first.width = TILE_SIZE; + rect.second = DOWN; + } + tmpRoadRect.start = st; + } else if (move == 3 || move == 4) { + if (move == 3) { + rect.first.top = (s.second + 0.5) * TILE_SIZE; + rect.first.left = (s.first - 0.5) * TILE_SIZE; + rect.first.width = 0.5 * TILE_SIZE; + } + this2.first = s.second + 1; + rect.first.height = TILE_SIZE; + sf::Vector2f st((s.first) * TILE_SIZE, (s.second + 1) * TILE_SIZE); + tmpRoadRect.start = st; + } + + std::pair point; +// sf::Vector2f s((start.first + 1) * TILE_SIZE, (start.second) * TILE_SIZE); +// roadRect.start = s; + while ((this1.first == s.second || (this1.first != height && this1.first != -1)) && + (this1.second == s.first || (this1.second != width && this1.second != -1)) && + (map[this1.first][this1.second].getTileNumber() != 16 || map[this2.first][this2.second].getTileNumber() != 16)) { + //std::cout << "(" << this1.first + 1 << ";" << this1.second + 1 << ") " << " (" << this2.first + 1 << ";" + // << this2.second + 1 << ")" << std::endl; + switch (move) { + case 1: + if (map[this1.first][this1.second].getTileNumber() == 18) { + std::cout << "!1!" << std::endl; + rect.second = DOWN; + tmpRoadRect.road.push_back(rect); + rect.first.top = (this1.first - 0.5) * TILE_SIZE; + rect.first.left = (this1.second + 0.5) * TILE_SIZE; + this1.first--; + this1.second++; + move = 3; + rect.first.width = 0.5 * TILE_SIZE; + rect.first.height = TILE_SIZE; + } else if (map[this2.first][this2.second].getTileNumber() == 19) { + std::cout << "!2!" << std::endl; + rect.second = DOWN; + tmpRoadRect.road.push_back(rect); + this1.first--; + this2.second--; + move = 4; + rect.first.width = 0.5 * TILE_SIZE; + rect.first.height = TILE_SIZE; + } else { + std::cout << "!3!" << std::endl; + rect.first.height += TILE_SIZE; + this1.first++; + this2.first++; + } + break; + case 2: + if (map[this1.first][this1.second].getTileNumber() == 3) { + std::cout << "!4!" << std::endl; + rect.second = UP; + rect.first.top = (this1.first + 1) * TILE_SIZE; + rect.first.left = (this1.second + 0.5) * TILE_SIZE; + tmpRoadRect.road.push_back(rect); + rect.first.top = (this1.first + 0.5) * TILE_SIZE; + rect.first.left = (this1.second + 0.5) * TILE_SIZE; + this2.first++; + this1.second++; + move = 3; + rect.first.width = 0.5 * TILE_SIZE; + rect.first.height = TILE_SIZE; + } else if (map[this2.first][this2.second].getTileNumber() == 4) { + std::cout << "!5!" << std::endl; + rect.second = UP; + rect.first.top = (this1.first + 1) * TILE_SIZE; + rect.first.left = (this1.second + 0.5) * TILE_SIZE; + tmpRoadRect.road.push_back(rect); + this2.first++; + this2.second--; + move = 4; + rect.first.width = 0.5 * TILE_SIZE; + rect.first.height = TILE_SIZE; + } else { + std::cout << "!6!" << std::endl; + rect.first.height += TILE_SIZE; + this1.first--; + this2.first--; + } + break; + + case 3: + if (map[this1.first][this1.second].getTileNumber() == 4) { + std::cout << "!7!" << std::endl; + rect.second = RIGHT; + tmpRoadRect.road.push_back(rect); + this1.first++; + this1.second--; + rect.first.left = (this1.second + 0.5) * TILE_SIZE; + rect.first.top = (this1.first - 0.5) * TILE_SIZE; + move = 1; + rect.first.width = TILE_SIZE; + rect.first.height = 0.5 * TILE_SIZE; + } else if (map[this2.first][this2.second].getTileNumber() == 19) { + std::cout << "!8!" << std::endl; + rect.second = RIGHT; + tmpRoadRect.road.push_back(rect); + this1.second--; + this2.first--; + move = 2; + rect.first.width = TILE_SIZE; + rect.first.height = 0.5 * TILE_SIZE; + } else { + std::cout << "!9!" << std::endl; + rect.first.width += TILE_SIZE; + this1.second++; + this2.second++; + } + break; + case 4: + if (map[this1.first][this1.second].getTileNumber() == 3) { + std::cout << "!10!" << std::endl; + rect.first.top = (this1.first + 0.5) * TILE_SIZE; + rect.first.left = (this1.second + 1) * TILE_SIZE; + rect.second = LEFT; + tmpRoadRect.road.push_back(rect); + rect.first.top = (this1.first + 0.5) * TILE_SIZE; + rect.first.left = (this1.second + 0.5) * TILE_SIZE; + this1.first++; + this2.second++; + move = 1; + rect.first.width = TILE_SIZE; + rect.first.height = 0.5 * TILE_SIZE; + } else if (map[this2.first][this2.second].getTileNumber() == 18) { + std::cout << "!11!" << std::endl; + rect.first.top = (this1.first + 0.5) * TILE_SIZE; + rect.first.left = (this1.second + 1) * TILE_SIZE; + rect.second = LEFT; + tmpRoadRect.road.push_back(rect); + this2.second++; + this2.first--; + move = 2; + rect.first.width = TILE_SIZE; + rect.first.height = 0.5 * TILE_SIZE; + } else { + std::cout << "!12!" << std::endl; + rect.first.width += TILE_SIZE; + this1.second--; + this2.second--; + } + break; + default: + break; + } + } + + if (move == 1 || move == 3) { + if (move == 1) { + rect.second = DOWN; + } else if (move == 3) { + rect.second = RIGHT; + } + tmpRoadRect.finish.top = (this1.first) * TILE_SIZE; + tmpRoadRect.finish.left = (this1.second + 0.5) * TILE_SIZE; + tmpRoadRect.finish.height = TILE_SIZE; + tmpRoadRect.finish.width = TILE_SIZE; + tmpRoadRect.road.push_back(rect); + } else if (move == 2) { + tmpRoadRect.finish.top = (this1.first) * TILE_SIZE; + tmpRoadRect.finish.left = (this1.second + 0.5) * TILE_SIZE; + tmpRoadRect.finish.height = TILE_SIZE; + tmpRoadRect.finish.width = TILE_SIZE; + rect.second = UP; + rect.first.top = (this1.first + 1) * TILE_SIZE; + rect.first.left = (this1.second + 0.5) * TILE_SIZE; + tmpRoadRect.road.push_back(rect); + } else if (move == 4) { + rect.second = LEFT; + tmpRoadRect.finish.top = (this1.first + 0.5) * TILE_SIZE; + tmpRoadRect.finish.left = (this1.second) * TILE_SIZE; + tmpRoadRect.finish.height = TILE_SIZE; + tmpRoadRect.finish.width = TILE_SIZE; + rect.first.top = (this1.first + 0.5) * TILE_SIZE; + rect.first.left = (this1.second + 0.5) * TILE_SIZE; + tmpRoadRect.road.push_back(rect); + } + std::cout << tmpRoadRect.start.x << " !! " << tmpRoadRect.start.y; + roadRect.push_back(tmpRoadRect); + } +} + +void Map::draw() { + for (auto row : map) { + for(auto tile : row) { + window.draw(tile); + } + } + +// for (auto roadRects : roadRect) { +// for (auto roads : roadRects.road) { +// sf::RectangleShape r(sf::Vector2f(roads.first.width, roads.first.height)); +// r.setPosition(roads.first.left, roads.first.top); +// r.setOutlineColor(sf::Color::Black); +// r.setOutlineThickness(0.5); +// if (roads.second == UP) { +// r.setFillColor(sf::Color::Red); +// } else if (roads.second == DOWN) { +// r.setFillColor(sf::Color::Green); +// } else if (roads.second == LEFT) { +// r.setFillColor(sf::Color::Blue); +// } else if (roads.second == RIGHT) { +// r.setFillColor(sf::Color::White); +// } +// +// //sf::Rect r(i.left, i.top, i.width, i.height); +// window.draw(r); +// } +// sf::RectangleShape f(sf::Vector2f(roadRects.finish.width, roadRects.finish.height)); +// f.setPosition(roadRects.finish.left, roadRects.finish.top); +// f.setFillColor(sf::Color::Black); +// window.draw(f); +// } + +} + + void Map::getRoadRect(std::vector& road) const { + road = roadRect; +} diff --git a/src/Map.h b/src/Map.h new file mode 100644 index 0000000..362d20a --- /dev/null +++ b/src/Map.h @@ -0,0 +1,56 @@ +// +// Created by Falcon on 20.04.2018. +// + +#ifndef TOWERDEFENSE_MAP_H +#define TOWERDEFENSE_MAP_H + +#include + +#include +#include + +#include "Constants.h" +#include "Tile.h" + +class Map { +public: + Map(sf::RenderWindow &window); + void draw(); + void analyze(std::vector& towers1, std::vector& towers2); + + + enum Direction { + UP, + DOWN, + LEFT, + RIGHT + }; + + struct LogicMap { + std::vector> road; + sf::FloatRect finish; + sf::Vector2f start; + }; + +private: + + std::vector roadRect; +public: + void getRoadRect(std::vector&) const; + +private: + sf::RenderWindow &window; + sf::Texture texture; + std::vector> map; + int count; + int width; + int height; + std::vector> start; + std::vector t1; + std::vector t2; + +}; + + +#endif //TOWERDEFENSE_MAP_H diff --git a/src/MenuState.cpp b/src/MenuState.cpp index e08842a..baade04 100644 --- a/src/MenuState.cpp +++ b/src/MenuState.cpp @@ -1 +1,72 @@ #include "MenuState.h" +#include "Graphics/Button.h" +#include "Game.h" +#include "Constants.h" + +MenuState::MenuState(StateManager &stack, States::Context context): State(stack, context) { + mapSprite.setTileNumber(16); + texture.loadFromFile("Resources/map1.png"); + texture.setSmooth(true); + sf::IntRect rect{ TILE_SIZE * (16 % 15), TILE_SIZE * (16 / 15), TILE_SIZE, TILE_SIZE }; + mapSprite.setTexture(texture, rect); + + name.setFont(context.fontHolder->get(Fonts::font1)); + name.setPosition({static_cast(470), + static_cast(150)}); + name.setScale(2.f, 2.f); + name.setString("DATTACK"); + logo.setTexture(context.textureHolder->get(Textures::logo)); + logo.setPosition(270.f, -20.f); + logo.setScale(1.f / 2, 1.f / 2); + initButtons(); +} + +bool MenuState::handleEvent(const sf::Event &event) { + container.handleWidgetsEvent(event); + return false; +} + +void MenuState::initButtons() { + sf::Sprite buttonSprite; + sf::Texture buttonTexture = getContext().textureHolder->get(Textures::button); + sf::IntRect rect{ 0, 0, 618, 185}; + //buttonSprite.setTextureRect(rect); + //buttonSprite.setTexture(buttonTexture); + //buttonSprite.setPosition(100.f, 100.f); + //getContext().window->draw(buttonSprite); + sf::RenderWindow& window = *getContext().window; + auto play = std::make_shared(); + play->setTexture(getContext().textureHolder->get(Textures::button)); + play->setTextureRect(rect); + play->setPosition({static_cast(window.getSize().x / 3 - 100), + static_cast(window.getSize().y / 2)}); + //play->setScale(1.0f, 1.0f); + play->setFont(getContext().fontHolder->get(Fonts::font1)); + play->setText("Play"); + play->setInd(0); + play->setCallback([this](int ind) { + popState(); + pushState(States::ID::ConnectGame); + }); + + container.addWidget(play); +} + + +bool MenuState::update(sf::Time dt) { + +} + +void MenuState::draw() { + getContext().window->clear(sf::Color(0, 165, 80, 0)); + for (int i = 0; i < 20; i++) + for (int j = 0; j < 20; j++) + { + mapSprite.setPosition(static_cast(j * TILE_SIZE), static_cast(i * TILE_SIZE)); + getContext().window->draw(mapSprite); + } + + //getContext().window->draw(name); + getContext().window->draw(container); + getContext().window->draw(logo); +} \ No newline at end of file diff --git a/src/MenuState.h b/src/MenuState.h index dd2b457..bb0aa09 100644 --- a/src/MenuState.h +++ b/src/MenuState.h @@ -1,9 +1,26 @@ #ifndef TOWERDEFENSE_MENUSTATE_H #define TOWERDEFENSE_MENUSTATE_H +#include "Graphics/Gui.h" +#include "State.h" +#include "Tile.h" -class MenuState { +class MenuState : public State { +public: + explicit MenuState(StateManager& stack, States::Context context); + bool handleEvent(const sf::Event& event) override ; + bool update(sf::Time dt) override; + void draw() override; + + void initButtons(); +private: + sf::Texture texture; + Tile mapSprite; + + gui::Gui container; + sf::Text name; + sf::Sprite logo; }; diff --git a/src/Multiplayer/ConnectionFacade/AbstractConnectionFacade.cpp b/src/Multiplayer/ConnectionFacade/AbstractConnectionFacade.cpp new file mode 100644 index 0000000..5e1e19e --- /dev/null +++ b/src/Multiplayer/ConnectionFacade/AbstractConnectionFacade.cpp @@ -0,0 +1,7 @@ +// +// Created by silvman on 16.05.18. +// + +#include "AbstractConnectionFacade.h" + +mp::AbstractConnectionFacade::~AbstractConnectionFacade() { } \ No newline at end of file diff --git a/src/Multiplayer/ConnectionFacade/AbstractConnectionFacade.h b/src/Multiplayer/ConnectionFacade/AbstractConnectionFacade.h new file mode 100644 index 0000000..494e82e --- /dev/null +++ b/src/Multiplayer/ConnectionFacade/AbstractConnectionFacade.h @@ -0,0 +1,25 @@ +// +// Created by silvman on 16.05.18. +// + +#ifndef SERVER_ABSTRACTCONNECTIONFACADE_H +#define SERVER_ABSTRACTCONNECTIONFACADE_H + + +#include "../Entities/Event.h" + +namespace mp { + class AbstractConnectionFacade { + public: + virtual void connect() = 0; + virtual bool hasNewData() = 0; + virtual bool isConnected() = 0; + virtual void getData(std::vector &to) = 0; + virtual void sendData(std::vector& from) = 0; + + virtual ~AbstractConnectionFacade(); + }; +} + + +#endif //SERVER_ABSTRACTCONNECTIONFACADE_H diff --git a/src/Multiplayer/ConnectionFacade/ClientConnectionFacade.cpp b/src/Multiplayer/ConnectionFacade/ClientConnectionFacade.cpp new file mode 100644 index 0000000..ddef2ab --- /dev/null +++ b/src/Multiplayer/ConnectionFacade/ClientConnectionFacade.cpp @@ -0,0 +1,62 @@ +// +// Created by silvman on 16.05.18. +// + +#include +#include "ClientConnectionFacade.h" +#include "../../GameConstants.h" + +bool mp::ClientConnectionFacade::hasNewData() { + if(selector_.wait(sf::milliseconds(GameConstants::instance().cSELECTOR_WAIT_TIME()))) + return selector_.isReady(socket_); + + return false; +} + +void mp::ClientConnectionFacade::getData(std::vector &to) { + sf::Packet packet; + if (socket_.receive(packet) == sf::Socket::Done) { + // парсинг пакета на отдельные эвенты + std::string data = (char *)packet.getData(); + parseEventString(data, to); + + if (GameConstants::instance().cDEBUG_MODE()) for (auto &&event : to) + std::cout << "[get event] " << event.type << " " << event.value << std::endl; + + } else { + throw std::logic_error(msg::error_accepting_events); + } +} + +void mp::ClientConnectionFacade::sendData(std::vector &from) { + sf::Packet packet; + std::string message; + encodeEventsToString(message, from); + + if (GameConstants::instance().cDEBUG_MODE()) for (auto &&event : from) { + std::cout << "[out event] " << event.type << " " << event.value << std::endl; + } + + std::cout << message << std::endl; + packet.append(message.c_str(), message.size() + 1); + + if (socket_.send(packet) == sf::Socket::Done) { + from.clear(); + } else { + throw std::logic_error(msg::error_sending_events); + } +} + +void mp::ClientConnectionFacade::connect() { + std::cout << msg::waiting_connection << std::endl; + if (socket_.connect(GameConstants::instance().cIP_ADDR_SERVER(), + (unsigned short)GameConstants::instance().cCONNECTION_PORT()) == sf::Socket::Status::Done) { + connected_ = true; + selector_.add(socket_); + std::cout << msg::connected << std::endl; + } +} + +bool mp::ClientConnectionFacade::isConnected() { + return connected_; +} \ No newline at end of file diff --git a/src/Multiplayer/ConnectionFacade/ClientConnectionFacade.h b/src/Multiplayer/ConnectionFacade/ClientConnectionFacade.h new file mode 100644 index 0000000..f584ac7 --- /dev/null +++ b/src/Multiplayer/ConnectionFacade/ClientConnectionFacade.h @@ -0,0 +1,40 @@ +// +// Created by silvman on 16.05.18. +// + +#ifndef SERVER_CLIENTCONNECTIONFACADE_H +#define SERVER_CLIENTCONNECTIONFACADE_H + +#include "AbstractConnectionFacade.h" + +namespace mp { + class ClientConnectionFacade : public AbstractConnectionFacade { + private: + struct msg { + static constexpr const char *waiting_connection = "[client:process] connecting to server"; + static constexpr const char *error_sending_events = "[client:fail] server didn't accept events"; + static constexpr const char *error_accepting_events = "[client:fail] can't accept events"; + static constexpr const char *connected = "[client:success] connected to server"; + }; + + sf::TcpSocket socket_; + sf::SocketSelector selector_; + bool connected_ = false; + + public: + void connect() override; + bool hasNewData() override; + bool isConnected() override; + + /* + * Эти два метода кидаются исключениями std::logic_error в случаях, + * когда с соединением что-то не так + */ + void getData(std::vector &to) override; + void sendData(std::vector &from) override; + + }; +} + + +#endif //SERVER_CLIENTCONNECTIONFACADE_H diff --git a/src/Multiplayer/ConnectionFacade/ServerConnectionFacade.cpp b/src/Multiplayer/ConnectionFacade/ServerConnectionFacade.cpp new file mode 100644 index 0000000..423b3e3 --- /dev/null +++ b/src/Multiplayer/ConnectionFacade/ServerConnectionFacade.cpp @@ -0,0 +1,74 @@ +// +// Created by silvman on 16.05.18. +// + +#include "ServerConnectionFacade.h" +#include "../../GameConstants.h" + +bool mp::ServerConnectionFacade::hasNewData() { + if (selector_.wait(sf::milliseconds(GameConstants::instance().cSELECTOR_WAIT_TIME()))) + return first_.hasNewData(selector_) || second_.hasNewData(selector_); + + return false; +} + +void mp::ServerConnectionFacade::getData(std::vector &to) { + if (first_.hasNewData(selector_)) { + try { + first_.getEvents(); + to.insert(to.end(), first_.from_client.begin(), first_.from_client.end()); // сращиваем 2 вектора + first_.from_client.clear(); // очищаем после получения данных + } catch (const std::exception &e) { + selector_.remove(first_.getSocket()); + } + } + + if (second_.hasNewData(selector_)) { + try { + second_.getEvents(); + to.insert(to.end(), second_.from_client.begin(), second_.from_client.end()); // сращиваем 2 вектора + second_.from_client.clear(); // очищаем после получения данных + } catch (const std::exception &e) { + selector_.remove(second_.getSocket()); + } + } +} + +void mp::ServerConnectionFacade::sendData(std::vector &from) { + for (auto &&event : from) { + switch (event.id) { + case 1: { + second_.to_send.push_back(event); + break; + } + + case 2: { + first_.to_send.push_back(event); + break; + } + + case 0: { // broadcasting + second_.to_send.push_back(event); + first_.to_send.push_back(event); + + break; + } + + default: + break; + } + } + + first_.sendEvents(); + second_.sendEvents(); + + from.clear(); // TODO нужна проверка на отправленность +} + +void mp::ServerConnectionFacade::connect() { + // does nothing as the connection comes from the master process +} + +bool mp::ServerConnectionFacade::isConnected() { + return first_.isAvailable() && second_.isAvailable(); // грубая проверка подключения с обоими игроками +} diff --git a/src/Multiplayer/ConnectionFacade/ServerConnectionFacade.h b/src/Multiplayer/ConnectionFacade/ServerConnectionFacade.h new file mode 100644 index 0000000..26ea856 --- /dev/null +++ b/src/Multiplayer/ConnectionFacade/ServerConnectionFacade.h @@ -0,0 +1,34 @@ +// +// Created by silvman on 16.05.18. +// + +#ifndef SERVER_SERVERCONNECTIONFACADE_H +#define SERVER_SERVERCONNECTIONFACADE_H + +#include "../Entities/Player.h" +#include "AbstractConnectionFacade.h" + +namespace mp { + class ServerConnectionFacade : public AbstractConnectionFacade { + private: + mp::player& first_; + mp::player& second_; + sf::SocketSelector selector_; + + public: + explicit ServerConnectionFacade(mp::player &first, mp::player &second) : first_(first), second_(second) { + selector_.add(first_.getSocket()); + selector_.add(second_.getSocket()); + }; + + bool isConnected() override; + void connect() override; + bool hasNewData() override; + void getData(std::vector &to) override; + void sendData(std::vector &from) override; + }; +} + + + +#endif //SERVER_SERVERCONNECTIONFACADE_H diff --git a/src/Multiplayer/Entities/Entity.cpp b/src/Multiplayer/Entities/Entity.cpp new file mode 100644 index 0000000..c547a9b --- /dev/null +++ b/src/Multiplayer/Entities/Entity.cpp @@ -0,0 +1,15 @@ +// +// Created by silvman on 16.05.18. +// + +#include "Entity.h" + +int mp::entity::getId() const { + return id; +} + +void mp::entity::setId(int id) { + entity::id = id; +} + +mp::entity::entity(int id): id(id) { } diff --git a/src/Multiplayer/Entities/Entity.h b/src/Multiplayer/Entities/Entity.h new file mode 100644 index 0000000..6dd7739 --- /dev/null +++ b/src/Multiplayer/Entities/Entity.h @@ -0,0 +1,24 @@ +// +// Created by silvman on 16.05.18. +// + +#ifndef SERVER_ENTITY_H +#define SERVER_ENTITY_H + +namespace mp { + class entity { + protected: + int id; + + public: + explicit entity(int id = 0); + virtual ~entity() = default; + + int getId() const; + void setId(int id); + }; + +} + + +#endif //SERVER_ENTITY_H diff --git a/src/Multiplayer/Entities/Event.cpp b/src/Multiplayer/Entities/Event.cpp new file mode 100644 index 0000000..a51b97a --- /dev/null +++ b/src/Multiplayer/Entities/Event.cpp @@ -0,0 +1,75 @@ +// +// Created by silvman on 16.05.18. +// + +#include "Event.h" + +mp::Event::Event(int id, char type, const std::string &value, sf::Time time) : + id(id), + type(type), + value(value), + time(time) { } + +mp::Event::Event(const std::string &sId, const std::string &sType, const std::string &value, const std::string &sTime) : + id(0), + type('\0'), + value(value), + time() +{ + id = atoi(sId.c_str()); + type = sType[0]; + + unsigned long long temp_time = 0; + for (auto &&digit : sTime) { + temp_time *= 10; + temp_time += digit - '0'; + } + + time = sf::microseconds(temp_time); +} + +void mp::parseEventString(const std::string &sEvents, std::vector &vEvents) { + auto iterator = sEvents.begin(); + + std::string str_num_events; + for (; *iterator != ' '; ++iterator) + str_num_events += *iterator; + iterator++; + + int num_events = atoi(str_num_events.c_str()); + + for (int i = 0; i < num_events; ++i) { + std::string sId; + std::string sType; + std::string sValue; + std::string sTime; + + for (; *iterator != ' '; ++iterator) + sId += *iterator; + ++iterator; + + for (; *iterator != ' '; ++iterator) + sType += *iterator; + ++iterator; + + for (; *iterator != ' '; ++iterator) + sValue += *iterator; + ++iterator; + + for (; *iterator != ' ' && iterator != sEvents.end(); ++iterator) + sTime += *iterator; + ++iterator; + + vEvents.emplace_back(sId, sType, sValue, sTime); + } + +} + +void mp::encodeEventsToString(std::string &sEvents, std::vector &vEvents) { + sEvents.append(std::to_string(vEvents.size()) + " "); + + // сборка сообщения, включающего все эвенты + for (auto &&e : vEvents) + sEvents.append(std::to_string(e.id) + " " + e.type + " " + e.value + " " + std::to_string(e.time.asMicroseconds()) + " "); + +} \ No newline at end of file diff --git a/src/Multiplayer/Entities/Event.h b/src/Multiplayer/Entities/Event.h new file mode 100644 index 0000000..b16fab0 --- /dev/null +++ b/src/Multiplayer/Entities/Event.h @@ -0,0 +1,26 @@ +// +// Created by silvman on 16.05.18. +// + +#ifndef SERVER_EVENT_H +#define SERVER_EVENT_H + +#include + +namespace mp { + struct Event { + int id; + char type; + std::string value; + sf::Time time; + + Event(int id, char type, const std::string &value, sf::Time time); + Event(const std::string &sId, const std::string &sType, const std::string &value, const std::string &sTime); + }; + + void parseEventString(const std::string& sEvents, std::vector& vEvents); + void encodeEventsToString(std::string& sEvents, std::vector& vEvents); +} + + +#endif //SERVER_EVENT_H diff --git a/src/Multiplayer/Entities/Game.cpp b/src/Multiplayer/Entities/Game.cpp new file mode 100644 index 0000000..670a894 --- /dev/null +++ b/src/Multiplayer/Entities/Game.cpp @@ -0,0 +1,51 @@ +// +// Created by silvman on 16.05.18. +// + +#include "Game.h" + +bool mp::game::isReady() const { + return (first_connected_ && second_connected_); +} + +void mp::game::join(int player_id) { + if (is_started_) + throw std::logic_error(msg::game_running); + + if (!first_connected_) { + player_id_first_ = player_id; + first_connected_ = true; + } else if (!second_connected_) { + player_id_second_ = player_id; + second_connected_ = true; + } +} + +const std::string &mp::game::getName() const { + return name_; +} + +mp::game::game(const std::string &name) : + name_(name), + is_started_(false), + first_connected_(false), + second_connected_(false), + player_id_second_(0), + player_id_first_(0) +{ } + +bool mp::game::isStarted() const { + return is_started_; +} + +void mp::game::start() { + is_started_ = true; +} + +int mp::game::getFirstId() const { + return player_id_first_; +} + +int mp::game::getSecondId() const { + return player_id_second_; +} \ No newline at end of file diff --git a/src/Multiplayer/Entities/Game.h b/src/Multiplayer/Entities/Game.h new file mode 100644 index 0000000..990b0c3 --- /dev/null +++ b/src/Multiplayer/Entities/Game.h @@ -0,0 +1,44 @@ +// +// Created by silvman on 16.05.18. +// + +#ifndef SERVER_GAME_H +#define SERVER_GAME_H + +#include "Entity.h" +#include + +namespace mp { + class game : public entity { + private: + struct msg { + static constexpr const char *game_running = "[game:fail] game already running" ; + }; + + std::string name_; + int player_id_first_; + int player_id_second_; + + bool first_connected_; + bool second_connected_; + + bool is_started_; + + public: + explicit game(const std::string& name); + + bool isReady() const; + void join(int player_id); + const std::string& getName() const; + + int getFirstId() const; + + int getSecondId() const; + + + bool isStarted() const; + void start(); + }; +} + +#endif //SERVER_GAME_H diff --git a/src/Multiplayer/Entities/Player.cpp b/src/Multiplayer/Entities/Player.cpp new file mode 100644 index 0000000..5eb3641 --- /dev/null +++ b/src/Multiplayer/Entities/Player.cpp @@ -0,0 +1,103 @@ +// +// Created by silvman on 16.05.18. +// + +#include +#include "Player.h" + +mp::player::player(int id) + : entity(id), state_(notConnected) { } + + +void mp::player::disconnect() { + state_ = notConnected; +} + +mp::player::~player() { + socket_.disconnect(); +} + +bool mp::player::isAvailable() const { + return state_ != notAvailable; +} + +void mp::player::getEvents() try { + sf::Packet packet; + if (socket_.receive(packet) == sf::Socket::Done) { + std::cout << msg::get_events << id << std::endl; + std::string data = (char *)packet.getData(); + + parseEventString(data, from_client); + } else { + throw std::logic_error(msg::not_get_events); + } +} catch (const std::exception& e) { + state_ = notAvailable; + throw; +} + +void mp::player::startGame() { + to_send.emplace_back(0, 'j', std::to_string(id), sf::microseconds(0)); + sendEvents(); +} + + +void mp::player::connect(sf::TcpListener &listener, sf::SocketSelector &selector) try { + if (listener.accept(socket_) == sf::Socket::Done) { + selector.add(socket_); + state_ = connected; // помечает, что подключено + + std::cout << msg::connect_player << id << std::endl; + + } else { + throw std::logic_error(msg::not_connect_player); + } +} catch (const std::exception& e) { + state_ = notAvailable; + throw; +} + +bool mp::player::hasNewData(sf::SocketSelector &selector) { + return selector.isReady(socket_); +} + +void mp::player::sendEvents() try { + if (to_send.empty()) + return; + + sf::Packet packet; + + std::string sEvents; + encodeEventsToString(sEvents, to_send); + + packet.append(sEvents.c_str(), sEvents.size() + 1); + if (socket_.send(packet) == sf::Socket::Done) { // блокирующий вызов, может стать причиной медленной пересылки эвентов + for (auto &&send : to_send) { + std::cout << send.id << " " << send.value << std::endl; + } + to_send.clear(); + std::cout << msg::send_events << id << std::endl; + } else { + throw std::logic_error(msg::not_send_events + id); + } + +} catch (const std::exception& e) { + std::cout << e.what() << std::endl; + state_ = notAvailable; +} + +bool mp::player::isConnected() const { + return state_ == connected; +} + +sf::TcpSocket &mp::player::getSocket() { + return socket_; +} + +bool mp::player::isInGame() const { + return in_game_; +} + +void mp::player::setInGame() { + in_game_ = true; +} \ No newline at end of file diff --git a/src/Multiplayer/Entities/Player.h b/src/Multiplayer/Entities/Player.h new file mode 100644 index 0000000..1833ab5 --- /dev/null +++ b/src/Multiplayer/Entities/Player.h @@ -0,0 +1,73 @@ +// +// Created by silvman on 16.05.18. +// + +#ifndef SERVER_PLAYER_H +#define SERVER_PLAYER_H + +#include +#include "Entity.h" +#include "Event.h" + +namespace mp { + class player : public entity { + public: + enum connection_state { + notConnected = 0, + connected, + notAvailable + }; + + explicit player(int id = 0); + ~player() override; + + sf::TcpSocket& getSocket(); + + + void getEvents(); + void sendEvents(); +// void resendEvents(player& to_who); + + // вызывается у первого игрока для уведомления о начале игры + bool hasNewData(sf::SocketSelector &selector); + + void disconnect(); + + void connect(sf::TcpListener &listener, sf::SocketSelector &selector); + + void startGame(); + + bool isAvailable() const; + bool isConnected() const; + + bool isInGame() const; + void setInGame(); + + + std::vector from_client; + std::vector to_send; + + + private: + struct msg { + static constexpr const char *get_events = "[player:success] get events from "; + static constexpr const char *not_get_events = "[player:error] can't recieve events"; + static constexpr const char *send_id = "[player:success] send id to "; + static constexpr const char *not_send_id = "[player:error] send id to"; + static constexpr const char *connect_player = "[player:success] connected player " ; + static constexpr const char *not_connect_player = "[player:error] didn't connect player" ; + static constexpr const char *send_events = "[player:success] send events to " ; + static constexpr const char *not_send_events = "[player:error] can't send events to " ; + }; + + sf::TcpSocket socket_; + connection_state state_; + bool in_game_; + }; + +} + + + + +#endif //SERVER_PLAYER_H diff --git a/src/Multiplayer/Manager/Manager.cpp b/src/Multiplayer/Manager/Manager.cpp new file mode 100644 index 0000000..67206fd --- /dev/null +++ b/src/Multiplayer/Manager/Manager.cpp @@ -0,0 +1,6 @@ +// +// Created by silvman on 16.05.18. +// + +#include "Manager.h" + diff --git a/src/Multiplayer/Manager/Manager.h b/src/Multiplayer/Manager/Manager.h new file mode 100644 index 0000000..e7af9ae --- /dev/null +++ b/src/Multiplayer/Manager/Manager.h @@ -0,0 +1,24 @@ +// +// Created by silvman on 16.05.18. +// + +#ifndef SERVER_MANAGER_H +#define SERVER_MANAGER_H + +#include + +namespace mp { + template + class manager { + protected: + std::list entities; + + public: + virtual std::list &getEntities(); + + virtual T &get_by_id(int id) = 0; + virtual void remove(int id) = 0; + }; +} + +#endif //SERVER_MANAGER_H diff --git a/src/Multiplayer/Manager/PlayerManager.cpp b/src/Multiplayer/Manager/PlayerManager.cpp new file mode 100644 index 0000000..c84bc8e --- /dev/null +++ b/src/Multiplayer/Manager/PlayerManager.cpp @@ -0,0 +1,39 @@ +// +// Created by silvman on 16.05.18. +// + +#include "PlayerManager.h" + +mp::player_manager::player_manager(): manager(), next_id(1) { } + +mp::player &mp::player_manager::get_by_id(int id) { + for (auto &&player : entities) + if (player.getId() == id) + return player; + + throw std::logic_error("[player_manager::get_by_id] id not found"); +} + +void mp::player_manager::remove(int id) { + for (auto it = entities.begin(); it != entities.end(); ++it) + if (it->getId() == id) { + entities.erase(it); + return;; + } + + throw std::logic_error("[player_manager::remove] id not found"); +} + +mp::player_manager::~player_manager() { + for (auto &&item : entities) { + // TODO нужно ли + item.disconnect(); // устанавливает флаг отключенности + } +} + +mp::player &mp::player_manager::create() { + entities.emplace_back(next_id); + next_id++; + + return entities.back(); +} \ No newline at end of file diff --git a/src/Multiplayer/Manager/PlayerManager.h b/src/Multiplayer/Manager/PlayerManager.h new file mode 100644 index 0000000..47651e2 --- /dev/null +++ b/src/Multiplayer/Manager/PlayerManager.h @@ -0,0 +1,34 @@ +// +// Created by silvman on 16.05.18. +// + +#ifndef SERVER_PLAYERMANAGER_H +#define SERVER_PLAYERMANAGER_H + +#include "Manager.h" +#include "../Entities/Player.h" + +namespace mp { + class player_manager: public manager { + private: + int next_id; + + public: + player_manager(); + ~player_manager(); + + player& get_by_id(int id) override; + // void add(player &&entity) override; + player& create(); + void remove(int id) override; + }; + + template + std::list& mp::manager::getEntities() { + return entities; + } + +} + + +#endif //SERVER_PLAYERMANAGER_H diff --git a/src/Multiplayer/Master.cpp b/src/Multiplayer/Master.cpp new file mode 100644 index 0000000..a69b023 --- /dev/null +++ b/src/Multiplayer/Master.cpp @@ -0,0 +1,124 @@ +// +// Created by silvman on 16.05.18. +// + +#include +#include "Master.h" +#include "Worker.h" +#include "../GameConstants.h" + +mp::master::master(unsigned short port): running_(true) { + if (listener_.listen(port) != sf::Socket::Status::Done) { + running_ = false; + }; + selector_.add(listener_); +} + +mp::master::~master() { + listener_.close(); // TODO Нужно? +} + +void mp::master::work() { + std::cout << msg::run << std::endl; + while (running_) try { + if (selector_.wait(sf::milliseconds(GameConstants::instance().cSELECTOR_WAIT_TIME()))) { + if (selector_.isReady(listener_)) { // подключение нового игрока + player& new_player = pool_players_.create(); // добавление игрока в список + + try { + new_player.connect(listener_, selector_); + } catch (const std::exception& e) { + // если ошибка при подключении + std::cout << e.what(); + pool_players_.remove(new_player.getId()); + } + + } else { + for (auto &&player : pool_players_.getEntities()) { + if (!player.isInGame() && selector_.isReady(player.getSocket())) { + try { + player.getEvents(); + } catch (const std::exception& e) { + // сюда попадаем при проблемах с подключением игрока. Пока что просто удаляем его, в дальнейшем можно было бы обработать + std::cout << e.what() << std::endl; + selector_.remove(player.getSocket()); + } + + // обрабатываем создание новых игр и подключение к ним + proceedEvents(player); + player.from_client.clear(); + } + } + } + } else { + for (auto &&game : pool_games_) { + if (game.isReady() && !game.isStarted()) { + startWorker(game); + } + } + } + } catch (const std::exception& e) { + std::cout << e.what() << std::endl; + } + +// wait(); +} + +void mp::master::proceedEvents(player &player) { + for (auto &&event : player.from_client) { + if (event.type == 'j') { + int pending_game_id = atoi(event.value.c_str()); + + try { + pool_games_.at(pending_game_id).join(player.getId()); + } catch (const std::exception& e) { + std::cout << e.what() << std::endl; + break; + } + + player.setInGame(); + std::cout << msg::join << player.getId() << " " << pending_game_id << std::endl; + + // TODO подключение по именам + } else if (event.type == 'n') { + pool_games_.emplace_back(event.value); // name - имя игры + + player.to_send.emplace_back(0, 'n', std::to_string(pool_games_.size() - 1), + sf::microseconds(0)); + + std::cout << msg::add_game << event.value << std::endl; + + player.sendEvents(); + } + } + +} + +void mp::master::startWorker(mp::game &game) { + pid_t pid = fork(); + + switch (pid) { + case 0: { + game.start(); + selector_.remove(pool_players_.get_by_id(game.getFirstId()).getSocket()); + selector_.remove(pool_players_.get_by_id(game.getSecondId()).getSocket()); + std::cout << msg::success << pid << std::endl; + break; + } // возможно, действия, связанные с обеспечением безопасности игры + + case -1: { + std::cout << msg::error << std::endl; + break; + } + + default: { + running_ = false; // worker не должен продолжать цикл master + + worker worker(pool_players_.get_by_id(game.getFirstId()), pool_players_.get_by_id(game.getSecondId()), pid); + worker.work(); + + return; + } + + } +} \ No newline at end of file diff --git a/src/Multiplayer/Master.h b/src/Multiplayer/Master.h new file mode 100644 index 0000000..a2734a7 --- /dev/null +++ b/src/Multiplayer/Master.h @@ -0,0 +1,42 @@ +// +// Created by silvman on 16.05.18. +// + +#ifndef SERVER_MASTER_H +#define SERVER_MASTER_H + +#include +#include "Entities/Game.h" +#include "Manager/PlayerManager.h" + +namespace mp { + class master { // TODO singleton? + private: + struct msg { + static constexpr const char *run = "[master:run]"; + static constexpr const char *join = "[master:success] player join'd game "; + static constexpr const char *add_game = "[master:success] add game "; + static constexpr const char *success = "[master:success] "; + static constexpr const char *error = "[master:error] fork failed"; + static constexpr const char *end = "[master:end]"; + }; + + sf::TcpListener listener_; + sf::SocketSelector selector_; + std::vector pool_games_; + player_manager pool_players_; + bool running_; + + void proceedEvents(player &player); + void startWorker(game& game); + + public: + explicit master(unsigned short port = 55001); + ~master(); + + void work(); + }; +} + + +#endif //SERVER_MASTER_H diff --git a/src/Multiplayer/MultiplayerFacade/AbstractMultiplayerFacade.cpp b/src/Multiplayer/MultiplayerFacade/AbstractMultiplayerFacade.cpp new file mode 100644 index 0000000..c3e58c5 --- /dev/null +++ b/src/Multiplayer/MultiplayerFacade/AbstractMultiplayerFacade.cpp @@ -0,0 +1,7 @@ +// +// Created by silvman on 16.05.18. +// + +#include "AbstractMultiplayerFacade.h" + +mp::AbstractMultiplayerFacade::~AbstractMultiplayerFacade() { } \ No newline at end of file diff --git a/src/Multiplayer/MultiplayerFacade/AbstractMultiplayerFacade.h b/src/Multiplayer/MultiplayerFacade/AbstractMultiplayerFacade.h new file mode 100644 index 0000000..35b843f --- /dev/null +++ b/src/Multiplayer/MultiplayerFacade/AbstractMultiplayerFacade.h @@ -0,0 +1,31 @@ +// +// Created by silvman on 16.05.18. +// + +#ifndef SERVER_MULTIPLAYERFACADE_H +#define SERVER_MULTIPLAYERFACADE_H + +#include "../ConnectionFacade/AbstractConnectionFacade.h" + +namespace mp { + class AbstractMultiplayerFacade { + protected: + std::unique_ptr connection; + + public: + virtual ~AbstractMultiplayerFacade(); + + virtual bool isConnected() = 0; + virtual void connect() = 0; + + virtual bool askEvents() = 0; + virtual bool sendEvents() = 0; + + std::vector incoming{}; + std::vector outcoming{}; + }; +} + + + +#endif //SERVER_MULTIPLAYERFACADE_H diff --git a/src/Multiplayer/MultiplayerFacade/ClientMultiplayerFacade.cpp b/src/Multiplayer/MultiplayerFacade/ClientMultiplayerFacade.cpp new file mode 100644 index 0000000..f7e51ee --- /dev/null +++ b/src/Multiplayer/MultiplayerFacade/ClientMultiplayerFacade.cpp @@ -0,0 +1,42 @@ +// +// Created by silvman on 16.05.18. +// + +#include +#include "ClientMultiplayerFacade.h" +#include "../ConnectionFacade/ClientConnectionFacade.h" + +bool mp::ClientMultiplayerFacade::askEvents() { + if (connection->hasNewData()) try { + connection->getData(incoming); + return true; + } catch (const std::exception& e) { + std::cout << e.what() << std::endl; + } + + return false; +} + +bool mp::ClientMultiplayerFacade::sendEvents() { + if (!outcoming.empty()) try { + connection->sendData(outcoming); + return true; + } catch (const std::exception& e) { + std::cout << e.what() << std::endl; + } + + return false; +} + +void mp::ClientMultiplayerFacade::connect() { + connection->connect(); + +} + +bool mp::ClientMultiplayerFacade::isConnected() { + return connection->isConnected(); +} + +mp::ClientMultiplayerFacade::ClientMultiplayerFacade() { + connection = std::unique_ptr(new ClientConnectionFacade); +} diff --git a/src/Multiplayer/MultiplayerFacade/ClientMultiplayerFacade.h b/src/Multiplayer/MultiplayerFacade/ClientMultiplayerFacade.h new file mode 100644 index 0000000..f92f482 --- /dev/null +++ b/src/Multiplayer/MultiplayerFacade/ClientMultiplayerFacade.h @@ -0,0 +1,25 @@ +// +// Created by silvman on 16.05.18. +// + +#ifndef SERVER_CLIENTMULTIPLAYERFACADE_H +#define SERVER_CLIENTMULTIPLAYERFACADE_H + +#include "AbstractMultiplayerFacade.h" + +namespace mp { + class ClientMultiplayerFacade : public AbstractMultiplayerFacade { + public: + ClientMultiplayerFacade(); + + bool isConnected() override; + void connect() override ; + + bool askEvents() override; + bool sendEvents() override; + }; +} + + + +#endif //SERVER_CLIENTMULTIPLAYERFACADE_H diff --git a/src/Multiplayer/MultiplayerFacade/ServerMultiplayerFacade.cpp b/src/Multiplayer/MultiplayerFacade/ServerMultiplayerFacade.cpp new file mode 100644 index 0000000..4243ddf --- /dev/null +++ b/src/Multiplayer/MultiplayerFacade/ServerMultiplayerFacade.cpp @@ -0,0 +1,42 @@ +// +// Created by silvman on 16.05.18. +// + +#include +#include "ServerMultiplayerFacade.h" +#include "../ConnectionFacade/ServerConnectionFacade.h" + +mp::ServerMultiplayerFacade::ServerMultiplayerFacade(mp::player &first, mp::player &second) { + connection = std::unique_ptr(new mp::ServerConnectionFacade(first, second)); +} + +bool mp::ServerMultiplayerFacade::askEvents() { + if (connection->hasNewData()) try { + connection->getData(incoming); + return true; + } catch (const std::exception& e) { + std::cout << e.what() << std::endl; + } + + return false; +} + +bool mp::ServerMultiplayerFacade::sendEvents() { + if (!outcoming.empty()) try { + connection->sendData(outcoming); + return true; + } catch (const std::exception& e) { + std::cout << e.what() << std::endl; + } + + return false; +} + +void mp::ServerMultiplayerFacade::connect() { + connection->connect(); +} + +bool mp::ServerMultiplayerFacade::isConnected() { + return connection->isConnected(); +} + diff --git a/src/Multiplayer/MultiplayerFacade/ServerMultiplayerFacade.h b/src/Multiplayer/MultiplayerFacade/ServerMultiplayerFacade.h new file mode 100644 index 0000000..0253e36 --- /dev/null +++ b/src/Multiplayer/MultiplayerFacade/ServerMultiplayerFacade.h @@ -0,0 +1,27 @@ +// +// Created by silvman on 16.05.18. +// + +#ifndef SERVER_SERVERMULTIPLAYERFACADE_H +#define SERVER_SERVERMULTIPLAYERFACADE_H + +#include "AbstractMultiplayerFacade.h" +#include "../Entities/Player.h" + +namespace mp { + class ServerMultiplayerFacade : public AbstractMultiplayerFacade { + public: + ServerMultiplayerFacade(mp::player& first, mp::player& second); + + bool isConnected() override; + void connect() override ; + + bool askEvents() override; + bool sendEvents() override; + + }; +} + + + +#endif //SERVER_SERVERMULTIPLAYERFACADE_H diff --git a/src/Multiplayer/Worker.cpp b/src/Multiplayer/Worker.cpp new file mode 100644 index 0000000..e150343 --- /dev/null +++ b/src/Multiplayer/Worker.cpp @@ -0,0 +1,31 @@ +// +// Created by silvman on 16.05.18. +// + +#include +#include "Worker.h" + +mp::worker::worker(player &first, player &second, pid_t pid) + : first_(first), second_(second), pid_(pid), game_(first, second) { + std::cout << msg::success << pid << std::endl; + + first_.setId(1); + second_.setId(2); +} + +void mp::worker::work() { + std::cout << msg::run << pid_ << std::endl; + + // Отсылаем сообщения о начале игры (включает в себя айдишники) + try { + first_.startGame(); + second_.startGame(); + } catch (const std::exception& e) { + std::cout << e.what() << std::endl; + return; + } + + game_.server_run(false); + + std::cout << msg::end << pid_ << std::endl; +} \ No newline at end of file diff --git a/src/Multiplayer/Worker.h b/src/Multiplayer/Worker.h new file mode 100644 index 0000000..43a2f0a --- /dev/null +++ b/src/Multiplayer/Worker.h @@ -0,0 +1,32 @@ +// +// Created by silvman on 16.05.18. +// + +#ifndef SERVER_WORKER_H +#define SERVER_WORKER_H + +#include "../Game.h" +#include "Entities/Player.h" + +namespace mp { + class worker { + struct msg { + static constexpr const char *success = "[worker:success] "; + static constexpr const char *run = "[worker:run] "; + static constexpr const char *end = "[worker:end] "; + }; + + pid_t pid_; + + player & first_; + player & second_; + Game game_; + + public: + worker(player &first, player &second, pid_t pid); + + void work(); + }; +} + +#endif //SERVER_WORKER_H diff --git a/src/MultiplayerGameState.cpp b/src/MultiplayerGameState.cpp new file mode 100644 index 0000000..bf54c76 --- /dev/null +++ b/src/MultiplayerGameState.cpp @@ -0,0 +1,5 @@ +// +// Created by Falcon on 02.05.2018. +// + +#include "MultiplayerGameState.h" diff --git a/src/MultiplayerGameState.h b/src/MultiplayerGameState.h new file mode 100644 index 0000000..d9b5374 --- /dev/null +++ b/src/MultiplayerGameState.h @@ -0,0 +1,36 @@ +#include + +#include "ResourceManager/ResourcesHolder.h" +#include "ResourceManager/ResourcesIdentifier.h" + +#include "State.h" +#include "Graphics/Gui.h" +#include "Map.h" +#include "Units/Warrior/Warrior.h" +#include "Units/UnitsGraphics/GraphicsUnit.h" + +class Tower; +class Bullet; + +class GameState : public State { +public: + explicit GameState(StateManager& stack, States::Context context); + ~GameState() = default; + + bool handleEvent(const sf::Event &event) override; + bool update(sf::Time dt) override; + void draw() override; + +private: + Player::GameData player1; + Player::GameData player2; + gui::Gui containter; + Map map; + std::vector roadRect; + std::vector warriors; + GraphicsUnit graphicsUnit; + Tower* tower; + std::vector bullets; + sf::Sprite towerSprite; + sf::Sprite bulletSprite; +}; \ No newline at end of file diff --git a/src/ResourceManager/ResourcesHolder.h b/src/ResourceManager/ResourcesHolder.h index ddd7149..2afbd0b 100644 --- a/src/ResourceManager/ResourcesHolder.h +++ b/src/ResourceManager/ResourcesHolder.h @@ -44,4 +44,4 @@ void ResourceHolder::insert(Identifier id, std::unique_ptr resourceMap.insert(std::make_pair(id, std::move(resource))); } -#endif //TOWERDEFENSE_RESOURCESHOLDER_H +#endif //TOWERDEFENSE_RESOURCESHOLDER_H \ No newline at end of file diff --git a/src/ResourceManager/ResourcesIdentifier.h b/src/ResourceManager/ResourcesIdentifier.h index 5d3181c..8d6334f 100644 --- a/src/ResourceManager/ResourcesIdentifier.h +++ b/src/ResourceManager/ResourcesIdentifier.h @@ -8,6 +8,58 @@ namespace sf { namespace Textures { enum id { + cursor = 0, + panel, + button, + map, + target, + towerZeroRed, + towerZeroBlue, + towerOneBase, + towerOneTop, + towerTwoBase, + towerTwoTop, + towerThreeBase, + towerThreeTop, + warriorOne, + warriorTwo, + warriorIconOne, + warriorIconTwo, + addWarriorOne, + addWarriorTwo, + addBarraks, + addWeapons, + addFarm, + blood, + warriorExplosion, + bulletOne, + bulletTwo, + bulletThree, + explosionOne, + explosionTwo, + explosionThree, + gold, + star, + lives, + pauseOn, + pauseOff, + forwardOn, + forwardOff, + fastForwardOn, + fastForwardOff, + fight, + play, + audioOff, + audioOn, + musicOff, + musicOn, + exit, + castle1, + castle2, + farm, + weapons, + barraks, + logo, }; } diff --git a/src/State.cpp b/src/State.cpp index ba1fa11..c373ae3 100644 --- a/src/State.cpp +++ b/src/State.cpp @@ -18,6 +18,6 @@ void State::clearStates() { stack.clearStates(); } -States::Context State::getContext() const { +States::Context& State::getContext() { return context; } \ No newline at end of file diff --git a/src/State.h b/src/State.h index f217213..62ed5cc 100644 --- a/src/State.h +++ b/src/State.h @@ -25,7 +25,7 @@ class State : private sf::NonCopyable { void popState(); void clearStates(); - States::Context getContext() const; + States::Context& getContext() ; private: StateManager &stack; diff --git a/src/StateManager.cpp b/src/StateManager.cpp index b80384c..71d0764 100644 --- a/src/StateManager.cpp +++ b/src/StateManager.cpp @@ -1,6 +1,7 @@ #include "StateManager.h" #include +#include StateManager::StateManager(States::Context context) : context(context) diff --git a/src/Tile.cpp b/src/Tile.cpp new file mode 100644 index 0000000..e682189 --- /dev/null +++ b/src/Tile.cpp @@ -0,0 +1,32 @@ +// +// Created by Falcon on 21.04.2018. +// + +#include "Tile.h" + +Tile::Tile() + : state(Tile::Type::None) +{} + + +void Tile::setTexture(const sf::Texture &texture, sf::IntRect rect) +{ + sprite.setTexture(texture); + sprite.setTextureRect(rect); +} + +void Tile::setTileNumber(int number) +{ + tileNumber = number; +} + +const int Tile::getTileNumber() const +{ + return tileNumber; +} + +void Tile::draw(sf::RenderTarget &target, sf::RenderStates states) const +{ + states.transform *= getTransform(); + target.draw(sprite, states); +} \ No newline at end of file diff --git a/src/Tile.h b/src/Tile.h new file mode 100644 index 0000000..1ee0791 --- /dev/null +++ b/src/Tile.h @@ -0,0 +1,38 @@ +// +// Created by Falcon on 21.04.2018. +// + +#ifndef TOWERDEFENSE_TILE_H +#define TOWERDEFENSE_TILE_H + +#include + +class Tile : public sf::Drawable, public sf::Transformable +{ +public: + enum class Type + { + None = 0, + Invalid, + Valid + }; + + Tile(); + + //void setState(Type state); + void setTexture(const sf::Texture &texture, sf::IntRect rect); + void setTileNumber(int number); + + //const Type getState() const; + const int getTileNumber() const; + +private: + void draw(sf::RenderTarget &target, sf::RenderStates states) const override; + + int tileNumber; + Type state; + sf::Sprite sprite; + sf::Vector2i position; +}; + +#endif //TOWERDEFENSE_TILE_H diff --git a/src/Units/Bullet/Bullet.cpp b/src/Units/Bullet/Bullet.cpp new file mode 100644 index 0000000..34327f4 --- /dev/null +++ b/src/Units/Bullet/Bullet.cpp @@ -0,0 +1,57 @@ +#include +#include "Bullet.h" +#include + +Bullet::Bullet(Type type, const sf::Vector2f& position, const std::shared_ptr& target, int damage, float velocity, + float angle) + : GameUnit(type, position), + target_(target), + damage_(damage), + velocity_(velocity), + angle_(angle), + exploded_(false), + disappeared_(false) { +} + +void Bullet::update(const sf::Time& dTime) { + if (target_ == nullptr) { + disappeared_ = true; + return; + } + if (target_->isFinished() || !target_->isAlive()) { + disappeared_ = true; + target_.reset(); + return; + } + if (!checkCollisionWithTarget()) { + angle_ = std::atan2((target_->getPosition().x - position_.x), (target_->getPosition().y - position_.y)); + position_.x += velocity_ * dTime.asSeconds() * std::sin(angle_); + position_.y += velocity_ * dTime.asSeconds() * std::cos(angle_); + } else { + exploded_ = true; + damage(); + target_.reset(); + } +} + +bool Bullet::checkCollisionWithTarget() { + float area = 10; + return (position_.x < target_->getPosition().x + area && position_.x > target_->getPosition().x - area) + && (position_.y < target_->getPosition().y + area && position_.y > target_->getPosition().y - area); +} + +void Bullet::damage() { + target_->suffer(damage_); +} + +float Bullet::getAngle() const { + return angle_; +} + +bool Bullet::isExploded() const { + return exploded_; +} + +bool Bullet::isDisappeared() const { + return disappeared_; +} \ No newline at end of file diff --git a/src/Units/Bullet/Bullet.h b/src/Units/Bullet/Bullet.h new file mode 100644 index 0000000..886d1c6 --- /dev/null +++ b/src/Units/Bullet/Bullet.h @@ -0,0 +1,34 @@ +#ifndef TOWERDEFENSE_BULLET_H +#define TOWERDEFENSE_BULLET_H + + +#include "../GameUnit.h" +#include "../Warrior/Warrior.h" +#include "../../GameConstants.h" + +class Bullet: public GameUnit { +public: + + void update(const sf::Time& dTime) override; + + float getAngle() const; + + bool isExploded() const; + bool isDisappeared() const; + +protected: + Bullet(Type type, const sf::Vector2f& position, const std::shared_ptr& target, int damage, float velocity, float angle); + virtual void damage(); + + bool checkCollisionWithTarget(); + + std::shared_ptr target_; + int damage_; + float velocity_; + float angle_; + bool exploded_; + bool disappeared_; +}; + + +#endif //TOWERDEFENSE_BULLET_H diff --git a/src/Units/Bullet/BulletLvlOne.cpp b/src/Units/Bullet/BulletLvlOne.cpp new file mode 100644 index 0000000..9f7af08 --- /dev/null +++ b/src/Units/Bullet/BulletLvlOne.cpp @@ -0,0 +1,5 @@ +#include "BulletLvlOne.h" + +BulletLvlOne::BulletLvlOne(const sf::Vector2f &position, float angle,const std::shared_ptr& target) + : Bullet(Type::lvlOne, position, target, GameConstants::instance().cBULLET_1_DAMAGE(), + GameConstants::instance().cBULLET_1_VELOCITY(), angle) {} diff --git a/src/Units/Bullet/BulletLvlOne.h b/src/Units/Bullet/BulletLvlOne.h new file mode 100644 index 0000000..9a18ef6 --- /dev/null +++ b/src/Units/Bullet/BulletLvlOne.h @@ -0,0 +1,13 @@ +#ifndef TOWERDEFENSE_BULLETLVLONE_H +#define TOWERDEFENSE_BULLETLVLONE_H + + +#include "Bullet.h" + +class BulletLvlOne: public Bullet { +public: + BulletLvlOne(const sf::Vector2f& position, float angle, const std::shared_ptr& target); +}; + + +#endif //TOWERDEFENSE_BULLETLVLONE_H diff --git a/src/Units/Bullet/BulletLvlThree.cpp b/src/Units/Bullet/BulletLvlThree.cpp new file mode 100644 index 0000000..770e15c --- /dev/null +++ b/src/Units/Bullet/BulletLvlThree.cpp @@ -0,0 +1,21 @@ +#include "BulletLvlThree.h" + +BulletLvlThree::BulletLvlThree(const sf::Vector2f &position, float angle, const std::shared_ptr& target, + std::list> &warriors) + : Bullet(Type::lvlThree, position, target, GameConstants::instance().cBULLET_3_DAMAGE(), + GameConstants::instance().cBULLET_3_VELOCITY(), angle), + warriors_(warriors), + rangeAOE_(GameConstants::instance().cBULLET_3_AOE()) {} + +void BulletLvlThree::damage() { + for (const auto& warrior: warriors_) { + if (warrior != nullptr && inRange(warrior->getPosition()) && warrior->isAlive()) { + warrior->suffer(damage_); + } + } +} + +bool BulletLvlThree::inRange(const sf::Vector2f& pointPosition) { + return (pointPosition.x - position_.x) * (pointPosition.x - position_.x) + + (pointPosition.y - position_.y) * (pointPosition.y - position_.y) <= rangeAOE_ * rangeAOE_; +} \ No newline at end of file diff --git a/src/Units/Bullet/BulletLvlThree.h b/src/Units/Bullet/BulletLvlThree.h new file mode 100644 index 0000000..a758a69 --- /dev/null +++ b/src/Units/Bullet/BulletLvlThree.h @@ -0,0 +1,23 @@ +#ifndef SERVER_BULLETLVLTHREE_H +#define SERVER_BULLETLVLTHREE_H + + +#include "Bullet.h" +#include + +class BulletLvlThree: public Bullet { +public: + BulletLvlThree(const sf::Vector2f& position, float angle, const std::shared_ptr& target, std::list>& warriors); + + void damage() override; + +private: + bool inRange(const sf::Vector2f& pointPosition); + + std::list>& warriors_; + float rangeAOE_; +}; + + + +#endif //SERVER_BULLETLVLTHREE_H diff --git a/src/Units/Bullet/BulletLvlTwo.cpp b/src/Units/Bullet/BulletLvlTwo.cpp new file mode 100644 index 0000000..073df8e --- /dev/null +++ b/src/Units/Bullet/BulletLvlTwo.cpp @@ -0,0 +1,6 @@ +#include "BulletLvlTwo.h" + +BulletLvlTwo::BulletLvlTwo(const sf::Vector2f &position, float angle, const std::shared_ptr& target) + : Bullet(Type::lvlTwo, position, target, GameConstants::instance().cBULLET_2_DAMAGE(), + GameConstants::instance().cBULLET_2_VELOCITY(), angle) {} + diff --git a/src/Units/Bullet/BulletLvlTwo.h b/src/Units/Bullet/BulletLvlTwo.h new file mode 100644 index 0000000..45ad86b --- /dev/null +++ b/src/Units/Bullet/BulletLvlTwo.h @@ -0,0 +1,13 @@ +#ifndef TOWERDEFENSE_BULLETLVLTWO_H +#define TOWERDEFENSE_BULLETLVLTWO_H + + +#include "Bullet.h" + +class BulletLvlTwo: public Bullet { +public: + BulletLvlTwo(const sf::Vector2f& position, float angle, const std::shared_ptr& target); +}; + + +#endif //TOWERDEFENSE_BULLETLVLTWO_H \ No newline at end of file diff --git a/src/Units/GameUnit.cpp b/src/Units/GameUnit.cpp new file mode 100644 index 0000000..e1d08ee --- /dev/null +++ b/src/Units/GameUnit.cpp @@ -0,0 +1,13 @@ +#include "GameUnit.h" + +GameUnit::GameUnit(Type type, const sf::Vector2f &position) + : type_(type), + position_(position) {} + +Type GameUnit::getType() const { + return type_; +} + +const sf::Vector2f &GameUnit::getPosition() const { + return position_; +} diff --git a/src/Units/GameUnit.h b/src/Units/GameUnit.h new file mode 100644 index 0000000..1d2ac76 --- /dev/null +++ b/src/Units/GameUnit.h @@ -0,0 +1,26 @@ +#ifndef TOWERDEFENSE_GAMEUNIT_H +#define TOWERDEFENSE_GAMEUNIT_H + + +#include +#include +#include "../GameContext.h" + +class GameUnit { +public: + virtual ~GameUnit() = default; + + virtual void update(const sf::Time& dTime) = 0; + + Type getType() const; + const sf::Vector2f& getPosition() const; + +protected: + GameUnit(Type type, const sf::Vector2f& position); + + Type type_; + sf::Vector2f position_; +}; + + +#endif //TOWERDEFENSE_GAMEUNIT_H diff --git a/src/Units/LogicUnitsManager.cpp b/src/Units/LogicUnitsManager.cpp new file mode 100644 index 0000000..a956292 --- /dev/null +++ b/src/Units/LogicUnitsManager.cpp @@ -0,0 +1,42 @@ +#include "LogicUnitsManager.h" +#include "../Castle/Castle.h" +#include "Bullet/Bullet.h" + +LogicUnitsManager::LogicUnitsManager() + : player1_(std::make_shared()), + player2_(std::make_shared()) { + std::cout << "LComponentConstructor" << std::endl; + player1_->setEnemy(player2_); + player2_->setEnemy(player1_); +} + +void LogicUnitsManager::update(const sf::Time& dTime) { + player1_->updateCastle(dTime); + player2_->updateCastle(dTime); + + updateBullets(dTime); +} + +void LogicUnitsManager::updateBullets(const sf::Time& dTime) { + for (auto bullet = bullets_.begin(); bullet != bullets_.end();) { + (*bullet)->update(dTime); + if (*bullet == nullptr || (*bullet)->isExploded() || (*bullet)->isDisappeared()) { + bullet = bullets_.erase(bullet); + } else { + ++bullet; + } + } +} + +std::shared_ptr &LogicUnitsManager::getPlayer1() { + return player1_; +} + +std::shared_ptr &LogicUnitsManager::getPlayer2() { + return player2_; +} + +std::vector> &LogicUnitsManager::getBullets() { + return bullets_; +} + diff --git a/src/Units/LogicUnitsManager.h b/src/Units/LogicUnitsManager.h new file mode 100644 index 0000000..b3fbdc7 --- /dev/null +++ b/src/Units/LogicUnitsManager.h @@ -0,0 +1,30 @@ +#ifndef SERVER_LOGICUNITSMANAGER_H +#define SERVER_LOGICUNITSMANAGER_H + +#include +#include +#include + +class Castle; +class Bullet; + +class LogicUnitsManager { +public: + explicit LogicUnitsManager(); + + void update(const sf::Time& dTime); + + std::shared_ptr& getPlayer1(); + std::shared_ptr& getPlayer2(); + std::vector>& getBullets(); + +private: + void updateBullets(const sf::Time& dTime); + + std::shared_ptr player1_; + std::shared_ptr player2_; + std::vector> bullets_; +}; + + +#endif //SERVER_LOGICUNITSMANAGER_H diff --git a/src/Units/Tower/Tower.cpp b/src/Units/Tower/Tower.cpp new file mode 100644 index 0000000..b197f83 --- /dev/null +++ b/src/Units/Tower/Tower.cpp @@ -0,0 +1,84 @@ +#include +#include +#include "Tower.h" +#include "../Warrior/Warrior.h" +#include "TowerLvlOne.h" +#include "TowerLvlTwo.h" +#include "TowerLvlThree.h" + +#define RAD_IN_DEGREE (180 / M_PI) +#define COOLDOWN 10 + +Tower::Tower(Type type, const sf::Vector2f& position, int price, float attackRange, float attackCooldown, + std::list>& warriors, std::vector>& bullets) + : GameUnit(type, position), + price_(price), + angle_(0), + attackRange_(attackRange), + attackCooldown_(attackCooldown / COOLDOWN), + warriors_(warriors), + bullets_(bullets), + target_(nullptr), + cooldown_(0) {} + +void Tower::update(const sf::Time& dTime) { + if (target_ != nullptr) { + if (inRange(target_->getPosition()) && target_->isAlive() && !target_->isFinished()) { + angle_ = aim(); + shoot(dTime); + } else { + target_.reset(); + } + } else { + for (const auto& warrior : warriors_) { + if (warrior != nullptr && inRange(warrior->getPosition()) && warrior->isAlive() && !warrior->isFinished()) { + target_ = warrior; + break; + } + } + } +} + +int Tower::getPrice() { + return price_; +} + +bool Tower::inRange(const sf::Vector2f& pointPosition) const { + return (pointPosition.x - position_.x) * (pointPosition.x - position_.x) + + (pointPosition.y - position_.y) * (pointPosition.y - position_.y) <= attackRange_ * attackRange_; +} + +float Tower::aim() const { + return static_cast((std::atan2((position_.y - target_->getPosition().y), + (position_.x - target_->getPosition().x)) * RAD_IN_DEGREE) - 90); +} + +void Tower::shoot(const sf::Time &dTime) { + cooldown_ -= dTime.asSeconds(); + if (cooldown_ < 0) { + cooldown_ = attackCooldown_; + bullets_.emplace_back(makeBullet()); + } +} + +float Tower::getAngle() const { + return angle_; +} + +int Tower::upgrade(std::shared_ptr& tower) { + int price = tower->getPrice(); + switch (tower->type_) { + case Type ::lvlZero: + tower.reset(new TowerLvlOne(tower->position_, tower->warriors_, tower->bullets_)); + break; + case Type::lvlOne: + tower.reset(new TowerLvlTwo(tower->position_, tower->warriors_, tower->bullets_)); + break; + case Type::lvlTwo: + tower.reset(new TowerLvlThree(tower->position_, tower->warriors_, tower->bullets_)); + break; + default: + return 0; + } + return price; +} \ No newline at end of file diff --git a/src/Units/Tower/Tower.h b/src/Units/Tower/Tower.h new file mode 100644 index 0000000..74e7025 --- /dev/null +++ b/src/Units/Tower/Tower.h @@ -0,0 +1,44 @@ +#ifndef TOWERDEFENSE_TOWER_H +#define TOWERDEFENSE_TOWER_H + +#include +#include +#include +#include "../GameUnit.h" +#include "../../GameConstants.h" + +class Warrior; +class Bullet; + +class Tower: public GameUnit { +public: + + void update(const sf::Time& dTime) override; + static int upgrade(std::shared_ptr& tower); + float getAngle() const; + int getPrice(); + + GameConstants& gameConst = GameConstants::instance(); + +protected: + Tower(Type type, const sf::Vector2f& position, int price, float attackRange, float attackCooldown, + std::list>& warriors, std::vector>& bullets); + + + bool inRange(const sf::Vector2f& pointPosition) const; + float aim() const; + void shoot(const sf::Time& dTime); + virtual std::shared_ptr makeBullet() = 0; + + int price_; + float angle_; + float attackRange_; + float cooldown_; + float attackCooldown_; + std::shared_ptr target_; + std::list>& warriors_; + std::vector>& bullets_; +}; + + +#endif //TOWERDEFENSE_TOWER_H \ No newline at end of file diff --git a/src/Units/Tower/TowerLvlOne.cpp b/src/Units/Tower/TowerLvlOne.cpp new file mode 100644 index 0000000..505e885 --- /dev/null +++ b/src/Units/Tower/TowerLvlOne.cpp @@ -0,0 +1,13 @@ +#include "TowerLvlOne.h" +#include "../Bullet/BulletLvlOne.h" + +TowerLvlOne::TowerLvlOne(const sf::Vector2f& position, std::list>& warriors, + std::vector>& bullets) + : Tower(Type::lvlOne, position, GameConstants::instance().cTOWER_1_UP_COST(), + GameConstants::instance().cTOWER_1_RANGE(), GameConstants::instance().cTOWER_1_COOLDOWN(), + warriors, bullets) {} + +std::shared_ptr TowerLvlOne::makeBullet() { + double radAngle = angle_ * M_PI / 180 - M_PI / 2; + return std::make_shared(position_ + sf::Vector2f(20 * cos(radAngle), 20 * sin(radAngle)), angle_, target_); +} \ No newline at end of file diff --git a/src/Units/Tower/TowerLvlOne.h b/src/Units/Tower/TowerLvlOne.h new file mode 100644 index 0000000..8a5b22f --- /dev/null +++ b/src/Units/Tower/TowerLvlOne.h @@ -0,0 +1,16 @@ +#ifndef TOWERDEFENSE_TOWERLVLONE_H +#define TOWERDEFENSE_TOWERLVLONE_H + + +#include "Tower.h" +#include "../../Constants.h" +#include +class TowerLvlOne: public Tower { +public: + TowerLvlOne(const sf::Vector2f& position, std::list>& warriors, std::vector>& bullets); + + std::shared_ptr makeBullet() override; +}; + + +#endif //TOWERDEFENSE_TOWERLVLONE_H \ No newline at end of file diff --git a/src/Units/Tower/TowerLvlThree.cpp b/src/Units/Tower/TowerLvlThree.cpp new file mode 100644 index 0000000..6ee3e12 --- /dev/null +++ b/src/Units/Tower/TowerLvlThree.cpp @@ -0,0 +1,13 @@ +#include "TowerLvlThree.h" +#include "../Bullet/BulletLvlThree.h" + + +TowerLvlThree::TowerLvlThree(const sf::Vector2f& position, std::list>& warriors, + std::vector>& bullets) + : Tower(Type::lvlThree, position, -1, GameConstants::instance().cTOWER_3_RANGE(), + GameConstants::instance().cTOWER_3_COOLDOWN(), warriors, bullets) {} + +std::shared_ptr TowerLvlThree::makeBullet() { + double radAngle = angle_ * M_PI / 180 - M_PI / 2; + return std::make_shared(position_ + sf::Vector2f(35 * cos(radAngle), 35 * sin(radAngle)), angle_, target_, warriors_); +} \ No newline at end of file diff --git a/src/Units/Tower/TowerLvlThree.h b/src/Units/Tower/TowerLvlThree.h new file mode 100644 index 0000000..0dc1cf9 --- /dev/null +++ b/src/Units/Tower/TowerLvlThree.h @@ -0,0 +1,15 @@ +#ifndef TOWERDEFENSE_TOWERLVLTHREE_H +#define TOWERDEFENSE_TOWERLVLTHREE_H + + +#include "Tower.h" + +class TowerLvlThree: public Tower { +public: + TowerLvlThree(const sf::Vector2f& position, std::list>& warriors, std::vector>& bullets); + + std::shared_ptr makeBullet() override; +}; + + +#endif //TOWERDEFENSE_TOWERLVLTHREE_H \ No newline at end of file diff --git a/src/Units/Tower/TowerLvlTwo.cpp b/src/Units/Tower/TowerLvlTwo.cpp new file mode 100644 index 0000000..1a6febb --- /dev/null +++ b/src/Units/Tower/TowerLvlTwo.cpp @@ -0,0 +1,13 @@ +#include "TowerLvlTwo.h" +#include "../Bullet/BulletLvlTwo.h" + +TowerLvlTwo::TowerLvlTwo(const sf::Vector2f& position, std::list>& warriors, + std::vector>& bullets) + : Tower(Type::lvlTwo, position, GameConstants::instance().cTOWER_2_UP_COST(), + GameConstants::instance().cTOWER_3_RANGE(), + GameConstants::instance().cTOWER_2_COOLDOWN(), warriors, bullets) {} + +std::shared_ptr TowerLvlTwo::makeBullet() { + double radAngle = angle_ * M_PI / 180 - M_PI / 2; + return std::make_shared(position_+ sf::Vector2f(30 * cos(radAngle), 30 * sin(radAngle)), angle_, target_); +} \ No newline at end of file diff --git a/src/Units/Tower/TowerLvlTwo.h b/src/Units/Tower/TowerLvlTwo.h new file mode 100644 index 0000000..a46da5b --- /dev/null +++ b/src/Units/Tower/TowerLvlTwo.h @@ -0,0 +1,17 @@ +#ifndef TOWERDEFENSE_TOWERLVLTWO_H +#define TOWERDEFENSE_TOWERLVLTWO_H + + +#include "Tower.h" +#include "../../Constants.h" + +class TowerLvlTwo: public Tower { +public: + TowerLvlTwo(const sf::Vector2f& position, std::list>& warriors, std::vector>& bullets); + + std::shared_ptr makeBullet() override; +}; + + + +#endif //TOWERDEFENSE_TOWERLVLTWO_H \ No newline at end of file diff --git a/src/Units/Tower/TowerLvlZero.cpp b/src/Units/Tower/TowerLvlZero.cpp new file mode 100644 index 0000000..3980f84 --- /dev/null +++ b/src/Units/Tower/TowerLvlZero.cpp @@ -0,0 +1,11 @@ +#include "TowerLvlZero.h" +#include "../Bullet/BulletLvlOne.h" + + +TowerLvlZero::TowerLvlZero(const sf::Vector2f& position, std::list>& warriors, + std::vector>& bullets) + : Tower(Type::lvlZero, position, GameConstants::instance().cTOWER_0_UP_COST(), 0, 0, warriors, bullets) {} + +std::shared_ptr TowerLvlZero::makeBullet() { + return nullptr; +} \ No newline at end of file diff --git a/src/Units/Tower/TowerLvlZero.h b/src/Units/Tower/TowerLvlZero.h new file mode 100644 index 0000000..bc1e6ab --- /dev/null +++ b/src/Units/Tower/TowerLvlZero.h @@ -0,0 +1,19 @@ +#ifndef TOWERDEFENSE_TOWERLVLZERO_H +#define TOWERDEFENSE_TOWERLVLZERO_H + + +#include "Tower.h" +#include "../../GameConstants.h" + +class TowerLvlZero: public Tower { +public: + TowerLvlZero(const sf::Vector2f& position, std::list>& warriors, std::vector>& bullets); + + void update(const sf::Time& dTime) override {}; + +private: + std::shared_ptr makeBullet() override; +}; + + +#endif //TOWERDEFENSE_TOWERLVLZERO_H \ No newline at end of file diff --git a/src/Units/Warrior/Warrior.cpp b/src/Units/Warrior/Warrior.cpp new file mode 100644 index 0000000..279a421 --- /dev/null +++ b/src/Units/Warrior/Warrior.cpp @@ -0,0 +1,79 @@ +#include "Warrior.h" + +Warrior::Warrior(Type type, const sf::Vector2f& position, const Map::LogicMap& logicMap, int cost, + float velocity, int hp) + : GameUnit(type, position), + logicMap_(logicMap), + direction_(0), + alive_(true), + finished_(false), + cost_(cost), + velocity_(velocity), + hp_(hp){ +} + +void Warrior::update(const sf::Time &dTime) { + if (!alive_) { + return; + } + + if (logicMap_.finish.contains(position_)) { + finished_ = true; + return; + } + + Map::Direction direction = Map::UP; + + for (auto part : logicMap_.road) { + if (part.first.contains(position_)) { + direction = part.second; + break; + } + } + + switch (direction) { + case Map::UP: + position_.y -= velocity_ * dTime.asSeconds(); + direction_ = 270; + break; + case Map::DOWN: + position_.y += velocity_ * dTime.asSeconds(); + direction_ = 90; + break; + case Map::LEFT: + position_.x -= velocity_ * dTime.asSeconds(); + direction_ = 180; + break; + case Map::RIGHT: + position_.x += velocity_ * dTime.asSeconds(); + direction_ = 0; + break; + } +} + +float Warrior::getDirection() const { + return direction_; +} + +int Warrior::getHp() const { + return hp_; +} + +const int Warrior::getCost() const { + return cost_; +} + +bool Warrior::isAlive() const { + return alive_; +} + +bool Warrior::isFinished() const { + return finished_; +} + +void Warrior::suffer(int damage) { + hp_ -= damage; + if (hp_ <= 0) { + alive_ = false; + } +} diff --git a/src/Units/Warrior/Warrior.h b/src/Units/Warrior/Warrior.h new file mode 100644 index 0000000..fd8f3cf --- /dev/null +++ b/src/Units/Warrior/Warrior.h @@ -0,0 +1,37 @@ +#ifndef TOWERDEFENSE_WARRIOR_H +#define TOWERDEFENSE_WARRIOR_H + + +#include "../../Map.h" +#include "../GameUnit.h" +#include "../../GameConstants.h" + +class Warrior: public GameUnit { +public: + + void update(const sf::Time& dTime) override; + void suffer(int damage); + + float getDirection() const; + int getHp() const; + const int getCost() const; + bool isAlive() const; + bool isFinished() const; + + +protected: + Warrior(Type type, const sf::Vector2f& position, const Map::LogicMap& logicMap, int cost, + float velocity, int hp); + +private: + float direction_; + float velocity_; + int hp_; + const int cost_; + bool alive_; + bool finished_; + const Map::LogicMap& logicMap_; +}; + + +#endif //TOWERDEFENSE_WARRIOR_H diff --git a/src/Units/Warrior/WarriorLvlOne.cpp b/src/Units/Warrior/WarriorLvlOne.cpp new file mode 100644 index 0000000..bc922a2 --- /dev/null +++ b/src/Units/Warrior/WarriorLvlOne.cpp @@ -0,0 +1,6 @@ +#include "WarriorLvlOne.h" + + +WarriorLvlOne::WarriorLvlOne(const sf::Vector2f &position, const Map::LogicMap &logicMap) + : Warrior(Type::lvlOne, position, logicMap, GameConstants::instance().cWARRIOR_1_COST(), + GameConstants::instance().cWARRIOR_1_VELOCITY(), GameConstants::instance().cWARRIOR_1_HP()) {} diff --git a/src/Units/Warrior/WarriorLvlOne.h b/src/Units/Warrior/WarriorLvlOne.h new file mode 100644 index 0000000..f1edb21 --- /dev/null +++ b/src/Units/Warrior/WarriorLvlOne.h @@ -0,0 +1,13 @@ +#ifndef TOWERDEFENSE_WARRIORLVLONE_H +#define TOWERDEFENSE_WARRIORLVLONE_H + + +#include "Warrior.h" + +class WarriorLvlOne: public Warrior { +public: + WarriorLvlOne(const sf::Vector2f& position, const Map::LogicMap& logicMap); +}; + + +#endif //TOWERDEFENSE_WARRIORLVLONE_H diff --git a/src/Units/Warrior/WarriorLvlTwo.cpp b/src/Units/Warrior/WarriorLvlTwo.cpp new file mode 100644 index 0000000..c63a05d --- /dev/null +++ b/src/Units/Warrior/WarriorLvlTwo.cpp @@ -0,0 +1,6 @@ +#include "WarriorLvlTwo.h" + + +WarriorLvlTwo::WarriorLvlTwo(const sf::Vector2f &position, const Map::LogicMap &logicMap) + : Warrior(Type::lvlTwo, position, logicMap, GameConstants::instance().cWARRIOR_2_COST(), + GameConstants::instance().cWARRIOR_2_VELOCITY(), GameConstants::instance().cWARRIOR_2_HP()) {} \ No newline at end of file diff --git a/src/Units/Warrior/WarriorLvlTwo.h b/src/Units/Warrior/WarriorLvlTwo.h new file mode 100644 index 0000000..9ca103a --- /dev/null +++ b/src/Units/Warrior/WarriorLvlTwo.h @@ -0,0 +1,14 @@ +#ifndef TOWERDEFENSE_WARRIORLVLTWO_H +#define TOWERDEFENSE_WARRIORLVLTWO_H + + +#include "Warrior.h" + +class WarriorLvlTwo: public Warrior { +public: + WarriorLvlTwo(const sf::Vector2f& position, const Map::LogicMap& logicMap); +}; + + +#endif //TOWERDEFENSE_WARRIORLVLTWO_H + diff --git a/src/WinState.cpp b/src/WinState.cpp new file mode 100644 index 0000000..f3976af --- /dev/null +++ b/src/WinState.cpp @@ -0,0 +1,62 @@ +#include "WinState.h" +#include "Constants.h" + +#include +#include + +WinState::WinState(StateManager &stack, States::Context context) + : State(stack, context) +{ + texture.loadFromFile("Resources/map1.png"); + texture.setSmooth(true); + sf::IntRect rect{ TILE_SIZE * (16 % 15), TILE_SIZE * (16 / 15), TILE_SIZE, TILE_SIZE }; + mapSprite.setTexture(texture, rect); + + sf::RenderWindow &window = *context.window; + sf::Font &font = *context.font; + + winText.setString("YOU WIN"); + winText.setColor(sf::Color::White); + winText.setCharacterSize(100); + winText.setFont(context.fontHolder->get(Fonts::font1)); + winText.setPosition(375.f, 200.f); + + enterText.setString("ENTER Menu"); + enterText.setColor(sf::Color::Black); + enterText.setCharacterSize(30); + enterText.setFont(context.fontHolder->get(Fonts::font1)); + enterText.setPosition(500.f, 400.f); +} + +bool WinState::handleEvent(const sf::Event &event) +{ + if (event.type == sf::Event::KeyPressed + && event.key.code == sf::Keyboard::Return) + { + popState(); + pushState(States::ID::Menu); + } + + return false; +} + +bool WinState::update(sf::Time dt) +{ + return false; +} + +void WinState::draw() +{ + getContext().window->clear(sf::Color(0, 165, 80, 0)); + for (int i = 0; i < 20; i++) + for (int j = 0; j < 20; j++) + { + mapSprite.setPosition(static_cast(j * TILE_SIZE), static_cast(i * TILE_SIZE)); + getContext().window->draw(mapSprite); + } + + sf::RenderWindow &window = *getContext().window; + //window.setView(window.getDefaultView()); + window.draw(winText); + window.draw(enterText); +} \ No newline at end of file diff --git a/src/WinState.h b/src/WinState.h new file mode 100644 index 0000000..a16a14f --- /dev/null +++ b/src/WinState.h @@ -0,0 +1,21 @@ +#pragma once + +#include "State.h" +#include +#include +#include "Tile.h" +class WinState : public State +{ +public: + explicit WinState(StateManager &stack, States::Context context); + + bool handleEvent(const sf::Event &event) override; + bool update(sf::Time dt) override; + void draw() override; + +private: + sf::Text winText, enterText; + sf::Texture texture; + Tile mapSprite; +}; + diff --git a/src/game_config.cfg b/src/game_config.cfg new file mode 100644 index 0000000..1146695 --- /dev/null +++ b/src/game_config.cfg @@ -0,0 +1,46 @@ +BARRACKS_1_COST 1000 +BARRACKS_2_COST 3000 +BARRACKS_3_COST 5000 +FARM_COST 1000 +FARM_INC_COST_BASE 1 +FARM_LVL_BENEFITS 20 +FARM_TIME_CYCLE 500 +WEAPONS_1_COST 1000 +WEAPONS_2_COST 3000 +WEAPONS_3_COST 5000 +CASTLE_HP 10000 +CASTLE_INIT_GOLD 10000 +CASTLE_WAVE_DURATION 1000 +WARRIORS_BUFFER_SIZE 10 + +BULLET_1_DAMAGE 100 +BULLET_1_VELOCITY 400 +BULLET_2_DAMAGE 150 +BULLET_2_VELOCITY 700 +BULLET_3_DAMAGE 200 +BULLET_3_VELOCITY 500 +BULLET_3_AOE 200 + +TOWER_0_UP_COST 1000 +TOWER_1_UP_COST 2000 +TOWER_1_RANGE 150 +TOWER_1_COOLDOWN 10 +TOWER_2_UP_COST 4000 +TOWER_2_RANGE 250 +TOWER_2_COOLDOWN 5 +TOWER_3_RANGE 400 +TOWER_3_COOLDOWN 20 + +WARRIOR_1_COST 500 +WARRIOR_1_VELOCITY 200 +WARRIOR_1_HP 1000 +WARRIOR_2_COST 1000 +WARRIOR_2_VELOCITY 300 +WARRIOR_2_HP 2000 + +WAVE_TIMER 30 + +SELECTOR_WAIT_TIME 5 +DEBUG_MODE 1 +CONNECTION_PORT 55001 +IP_ADDR_SERVER 0.0.0.0 \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index c905376..fa550d5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,3 +1,4 @@ +#include #include "Game.h" int main() { diff --git a/src/server_main.cpp b/src/server_main.cpp new file mode 100644 index 0000000..522ff74 --- /dev/null +++ b/src/server_main.cpp @@ -0,0 +1,19 @@ +// +// Created by silvman on 08.04.18. +// + +#include +#include "Multiplayer/Master.h" + +int main () { + // TODO чтение порта из конфигов + + try { + mp::master master; + master.work(); + } catch (const std::exception& e) { + std::cout << e.what() << std::endl; + } + + return 0; +} \ No newline at end of file