diff --git a/CMakeLists.txt b/CMakeLists.txt index 877432f2..9a51fb75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -230,8 +230,11 @@ set(INCLUDE_FILES ${INCLUDE_DIR}/Scene/SandBoxScene.hpp - ${INCLUDE_DIR}/AI/Enemy.hpp - ${INCLUDE_DIR}/AI/EnemyScripts.hpp + + ${INCLUDE_DIR}/Enemy/Enemy.hpp + ${INCLUDE_DIR}/Enemy/EnemyScripts.hpp + ${INCLUDE_DIR}/Enemy/AIGroupCommander.hpp + ${INCLUDE_DIR}/Core/Context.hpp ${INCLUDE_DIR}/Core/DebugMessageCallback.hpp diff --git a/include/AI/AIGroupCommander.hpp b/include/AI/AIGroupCommander.hpp index 149667a9..9796102e 100644 --- a/include/AI/AIGroupCommander.hpp +++ b/include/AI/AIGroupCommander.hpp @@ -4,7 +4,184 @@ #ifndef PRACTICALTOOLSFORSIMPLEDESIGN_AIGROUPCOMMANDER_HPP #define PRACTICALTOOLSFORSIMPLEDESIGN_AIGROUPCOMMANDER_HPP +#include "Mechanics/UnitManager.hpp" +#include "Avatar/Avatar.hpp" +#define GROUP_SIZE 4 +#define AUTO_FIND_RANGE 4 +#define AUTO_ATTACK_METHOD 2 +class AIGroupCommander { +private: + std::shared_ptr m_PlayerUnitManager; + std::shared_ptr m_AIUnitManager; + std::shared_ptr m_AIAvatarManager; + std::shared_ptr m_Map; + + std::vector>> m_offensiveGroup; + std::vector> m_defensiveGroup; +public: + AIGroupCommander(std::shared_ptr PlayerUnitManager,std::shared_ptr AIUnitManager,std::shared_ptr Map):m_PlayerUnitManager(PlayerUnitManager),m_AIUnitManager(AIUnitManager),m_Map(Map){}; + ~AIGroupCommander(){}; + void Start(){ + m_AIAvatarManager = m_AIUnitManager->getAvatarManager(); + m_defensiveGroup = m_AIAvatarManager->getAvatarArray(); + } + void Update(){ + updateDefensiveGroup(); + updateOffensiveGroup(); + } + + + void setAllTroopToAttackMode(){ + if(m_defensiveGroup.empty()){ + return; + } + for(auto i : m_defensiveGroup){ + addTroopToOffensiveGroup(i); + } + m_defensiveGroup.clear(); + } + void setTroopToAttackMode(int num){ + if(m_defensiveGroup.empty()){ + return; + } + int max = static_cast(m_defensiveGroup.size()); + for(int i=max-1;i>=0 && num>=max-i;i--){ + addTroopToOffensiveGroup(m_defensiveGroup[i]); + m_defensiveGroup.pop_back(); + } + } + + int getDefensiveTroopSize(){ + return static_cast(m_defensiveGroup.size()); + } + + int getOffensiveTroopSize(){ + int totalSize = 0; + for (const auto& row : m_offensiveGroup) { + totalSize += static_cast(row.size()); + } + return totalSize; + } +protected: + void updateOffensiveGroup(){ + for(auto i : m_offensiveGroup){ + for(int j=0;j(i.size());j++){ + if(i[j]->getHealth()->ifDead()){ + i.erase(i.begin()+j); + } + } + } + updateOffensiveTroopAttackTarget(); + } + void updateDefensiveGroup(){ + for(int i = static_cast(m_defensiveGroup.size());i>0;--i ){ + if(m_defensiveGroup[i-1]->getHealth()->ifDead()){ + m_defensiveGroup.erase(m_defensiveGroup.begin()+i-1); + }else{ + autoAttack(m_defensiveGroup[i-1],AUTO_ATTACK_METHOD); + }; + } + std::vector> temp = m_AIAvatarManager->getAvatarArray(); + for(int i=static_cast(temp.size())-1;i>=0;i--){ + if(temp[i]->getAIType()==AI_Type::NONE){ + temp[i]->setAIType(AI_Type::DEFENCE); + m_defensiveGroup.push_back(temp[i]); + } + } + } + void addTroopToOffensiveGroup(std::shared_ptr unit){ + auto it = std::find_if(m_offensiveGroup.begin(), m_offensiveGroup.end(), [](const std::vector>& group) { + return group.size() < GROUP_SIZE; + }); + unit->setAIType(AI_Type::ATTACK); + if (it != m_offensiveGroup.end()) { + it->push_back(unit); + } else { + m_offensiveGroup.push_back(std::vector>()); + m_offensiveGroup.back().push_back(unit); + } + } + void autoAttack(std::shared_ptr unit,int method){ + switch (method) { + case 1: + for(auto i : m_PlayerUnitManager->getAvatarManager()->getAvatarArray()){ + if(i->getDistance(unit->getCurrentLocationInCell())<=AUTO_FIND_RANGE){ + //attack + m_AIAvatarManager->assignAttackOrderToAvatar(unit,i->getCurrentLocationInCell(),HouseType::ENEMY); + return; + } + } + break; + case 2: + glm::vec2 targetCell = m_Map->findEnemyInRange(AUTO_FIND_RANGE,unit->getCurrentLocationInCell(),HouseType::ENEMY); + if(targetCell.x == -1 && targetCell.y == -1){ + return; + } + //attack + m_AIAvatarManager->assignAttackOrderToAvatar(unit,targetCell,HouseType::ENEMY); + break; + } + } + void updateOffensiveTroopAttackTarget(){ + for(int i = static_cast(m_offensiveGroup.size());i>0;--i){ + auto& currentGroup = m_offensiveGroup[i-1]; + printf("(updateOffensiveTroopAttackTarget)groupSize : %d\n",static_cast(currentGroup.size())); + if(!currentGroup.empty()){ + if (!m_AIAvatarManager->ifAvatarHasNemesis(currentGroup.front())){ + // find new target + glm::vec2 targetCell = findTargetForOffensiveUnit(currentGroup.front()); + if(targetCell.x==-1.f){ + printf("(updateOffensiveTroopAttackTarget) No Target\n"); + break; + } + // attack + for (int j=static_cast(currentGroup.size());j>0;--j) { + if(currentGroup[j-1]->getHealth()->ifDead()){ + currentGroup.erase(currentGroup.begin()+j-1); + }else{ + m_AIAvatarManager->assignAttackOrderToAvatar( + currentGroup[j-1], targetCell,HouseType::ENEMY); + } + } + }else{ + glm::vec2 targetCell = m_AIAvatarManager->getAvatarNemesisCell(currentGroup.front()); + printf("(updateOffensiveTroopAttackTarget)AvatarHasNemesis : {%d,%d}\n",static_cast(targetCell.x),static_cast(targetCell.y)); + } + }else{ + m_offensiveGroup.erase(m_offensiveGroup.begin()+i-1); + } + } + } + + glm::vec2 findTargetForOffensiveUnit(std::shared_ptr unit){ + glm::vec2 targetCell = {-1.f,-1.f}; + //issue: empty group should delete before this + if(false&&static_cast(m_offensiveGroup.size())>=static_cast(m_PlayerUnitManager->getAvatarManager()->getAvatarArray().size())){ + if(!m_PlayerUnitManager->getStructureManager()->getStructureArray()->getBuiltStructureArray().empty()){ + targetCell=m_PlayerUnitManager->getStructureManager()->getStructureArray()->getBuiltStructureArray().front()->getCurrentLocationInCell(); + } + for(auto i : m_PlayerUnitManager->getStructureManager()->getStructureArray()->getBuiltStructureArray()){ + if(unit->getDistance(i->getCurrentLocationInCell())getDistance(targetCell)){ + //attack + targetCell = i->getCurrentLocationInCell(); + } + } + }else{ + if(!m_PlayerUnitManager->getAvatarManager()->getAvatarArray().empty()){ + targetCell=m_PlayerUnitManager->getAvatarManager()->getAvatarArray().front()->getCurrentLocationInCell(); + } + for(auto i : m_PlayerUnitManager->getAvatarManager()->getAvatarArray()){ + if(i->getDistance(unit->getCurrentLocationInCell())getDistance(targetCell)){ + //attack + targetCell = i->getCurrentLocationInCell(); + } + } + } + printf("(findTargetForOffensiveUnit) TargetCell : {%d,%d}\n",targetCell.x,targetCell.y); + return targetCell; + } +}; + -class AIGroupCommander {}; #endif // PRACTICALTOOLSFORSIMPLEDESIGN_AIGROUPCOMMANDER_HPP diff --git a/include/AI/EnemyScripts.hpp b/include/AI/EnemyScripts.hpp index 2c4cbec3..6179f4e2 100644 --- a/include/AI/EnemyScripts.hpp +++ b/include/AI/EnemyScripts.hpp @@ -4,8 +4,8 @@ #ifndef PRACTICALTOOLSFORSIMPLEDESIGN_ENEMYSCRIPTS_HPP #define PRACTICALTOOLSFORSIMPLEDESIGN_ENEMYSCRIPTS_HPP -#include "Enemy.hpp" #include "Mechanics/UnitManager.hpp" +#include "AIGroupCommander.hpp" #define SPACE 4 @@ -17,6 +17,7 @@ class EnemyScripts{ std::shared_ptr m_GameObjectManager; std::shared_ptr m_EnemyObjectManager; std::shared_ptr m_Map; + std::shared_ptr m_AIGroupCommander; glm::vec2 m_baseCell = {20, 20}; int constructCountX = 0; diff --git a/include/Avatar/Avatar.hpp b/include/Avatar/Avatar.hpp index 4da16fa8..4247935d 100644 --- a/include/Avatar/Avatar.hpp +++ b/include/Avatar/Avatar.hpp @@ -15,7 +15,7 @@ #include "Selectable.hpp" #include "Unit/Huntable.hpp" #include "Util/Image.hpp" - +enum class AI_Type{NONE,DEFENCE,ATTACK}; class Avatar : public Util::GameObject, public Selectable, public Huntable { public: @@ -62,6 +62,12 @@ class Avatar : public Util::GameObject, public Selectable, public Huntable { void DrawAvatar(); + void setAIType(AI_Type type){ + m_aiType=type; + } + AI_Type getAIType(){ + return m_aiType; + } public: GameObjectID getID() { return m_ID; } @@ -104,5 +110,6 @@ class Avatar : public Util::GameObject, public Selectable, public Huntable { private: GameObjectID m_ID; + AI_Type m_aiType = AI_Type::NONE; }; #endif // PRACTICALTOOLSFORSIMPLEDESIGN_AVATAR_HPP diff --git a/include/Avatar/AvatarOrder.hpp b/include/Avatar/AvatarOrder.hpp index 551150a7..5ecb6fa7 100644 --- a/include/Avatar/AvatarOrder.hpp +++ b/include/Avatar/AvatarOrder.hpp @@ -4,7 +4,7 @@ #ifndef PRACTICALTOOLSFORSIMPLEDESIGN_AVATARORDER_HPP #define PRACTICALTOOLSFORSIMPLEDESIGN_AVATARORDER_HPP -enum class AvatarOrderType { SPAWNED, OPEN_FIRE, MOVE, NO_ORDER, TAKEN_DAMAGE }; +enum class AvatarOrderType { SPAWNED, OPEN_FIRE,CHASE, MOVE, NO_ORDER, TAKEN_DAMAGE }; class AvatarOrder { public: AvatarOrder() {} diff --git a/include/Avatar/Infantry.hpp b/include/Avatar/Infantry.hpp index c1b7bf7f..8885c364 100644 --- a/include/Avatar/Infantry.hpp +++ b/include/Avatar/Infantry.hpp @@ -19,7 +19,6 @@ class Infantry : public Avatar { // setHp(50); getMoving()->setMovementSpeed(4); } - private: }; #endif // PRACTICALTOOLSFORSIMPLEDESIGN_INFANTRY_HPP diff --git a/include/Avatar/PathUtility.hpp b/include/Avatar/PathUtility.hpp index 982ba691..40027a3e 100644 --- a/include/Avatar/PathUtility.hpp +++ b/include/Avatar/PathUtility.hpp @@ -33,6 +33,8 @@ class PathUtility { MoveDirection currentdir); static MoveDirection findNewDirWhenCrash(Side side, glm::vec2 currentcell, MoveDirection currentdir); + static std::string debug_dirToString(MoveDirection dir); + }; #endif // PRACTICALTOOLSFORSIMPLEDESIGN_PATHUTILITY_HPP diff --git a/include/Map/Map.hpp b/include/Map/Map.hpp index 036f9400..b6cff4b2 100644 --- a/include/Map/Map.hpp +++ b/include/Map/Map.hpp @@ -55,6 +55,35 @@ class MapClass : public Core::Drawable { getTileByCellPosition(position)->removeStructure(); } + glm::vec2 findEnemyInRange(int attackRange,glm::vec2 myCell,HouseType myHouse){ + glm::vec2 NullPos={-1,-1}; + int x,y=1; + int r=1; + for(r=1;rifEnemyAtTile(myHouse)){ + return {myCell.x+x,myCell.y+y}; + } + } + for(y=r-1;y>=-1*r;y--){ + if(getTileByCellPosition({myCell.x+x,myCell.y+y})->ifEnemyAtTile(myHouse)){ + return {myCell.x+x,myCell.y+y}; + } + } + for(x=r-1;x>-1*r;x--){ + if(getTileByCellPosition({myCell.x+x,myCell.y+y})->ifEnemyAtTile(myHouse)){ + return {myCell.x+x,myCell.y+y}; + } + } + for(y=-1*r+1;yifEnemyAtTile(myHouse)){ + return {myCell.x+x,myCell.y+y}; + } + } + } + return NullPos; + } protected: void InitGrid(); diff --git a/include/Map/Tile.hpp b/include/Map/Tile.hpp index 10893873..6ba9fea4 100644 --- a/include/Map/Tile.hpp +++ b/include/Map/Tile.hpp @@ -118,6 +118,31 @@ class TileClass { return false; } + bool ifEnemyAtTile(HouseType myHouse) { + if(myHouse==HouseType::MY){ + if (m_Structure->getID().getHouse() == HouseType::ENEMY) { + return true; + } + for (auto a : m_Avatars) { + if (a->getID().getHouse() == HouseType::ENEMY) { + return true; + } + } + return false; + }else if(myHouse==HouseType::ENEMY){ + if (m_Structure->getID().getHouse() == HouseType::MY) { + return true; + } + for (auto a : m_Avatars) { + if (a->getID().getHouse() == HouseType::MY) { + return true; + } + } + return false; + } + } + + private: bool m_TerrainBuildable; bool m_TerrainWalkable; diff --git a/include/Mechanics/AvatarManager.hpp b/include/Mechanics/AvatarManager.hpp index dd3cd4a9..5333515a 100644 --- a/include/Mechanics/AvatarManager.hpp +++ b/include/Mechanics/AvatarManager.hpp @@ -35,7 +35,17 @@ class AvatarManager { void assignAttackOrderToAvatar(std::shared_ptr unit, glm::vec2 destcell); - + void assignAttackOrderToAvatar(std::shared_ptr avatar, + glm::vec2 destcell,HouseType myHouse); + int getAvatarSize(){ + return static_cast(m_AvatarArray.size()); + } + bool ifAvatarHasNemesis(std::shared_ptr unit){ + return m_NemesisManager->ifAvatarHasNemesis(unit); + } + glm::vec2 getAvatarNemesisCell(std::shared_ptr unit){ + return m_NemesisManager->getNemesisCell(unit); + } protected: void assignOrderToMyAvatar(std::shared_ptr unit); void updateTileWhileAvatarMoving(std::shared_ptr unit); diff --git a/include/Mechanics/AvatarNavigator.hpp b/include/Mechanics/AvatarNavigator.hpp index 6d05a041..c2e33be6 100644 --- a/include/Mechanics/AvatarNavigator.hpp +++ b/include/Mechanics/AvatarNavigator.hpp @@ -39,5 +39,6 @@ class AvatarNavigator { private: std::shared_ptr m_Map = std::make_shared(); + MoveDirection recursionCrashHandler(MoveDirection currentDir,int count); }; #endif // PRACTICALTOOLSFORSIMPLEDESIGN_AVATARNAVIGATOR_HPP diff --git a/include/Mechanics/NemesisManager.hpp b/include/Mechanics/NemesisManager.hpp index 187fcc7c..a8e565ce 100644 --- a/include/Mechanics/NemesisManager.hpp +++ b/include/Mechanics/NemesisManager.hpp @@ -29,6 +29,12 @@ class NemesisManager { return false; } } + glm::vec2 getNemesisCell(std::shared_ptr avatar){ + if(!ifAvatarHasNemesis(avatar)){ + return {-1.f,-1.f}; + } + return m_Nemesis[avatar]->getCurrentLocationInCell(); + } bool ifNemesisWithinWeaponRange(std::shared_ptr hunter) { if (ifAvatarHasNemesis(hunter) == false) { return false; diff --git a/include/Mechanics/Player.hpp b/include/Mechanics/Player.hpp index f662ac10..32d7894f 100644 --- a/include/Mechanics/Player.hpp +++ b/include/Mechanics/Player.hpp @@ -16,16 +16,14 @@ class Player { void addFixedPower(int value) { m_FixedPower += value; } int getTotalCurrency() { return m_TotalCurrency; } - int getMaxTroopSize() { return m_MaxTroopSize; } + protected: int getTotalPower(std::vector> m_BuiltStructure) { int totalPower = 0; for (int i = 0; i < m_BuiltStructure.size(); i++) { - if(m_BuiltStructure[i]->getHouseType()==HouseType::MY){ - totalPower += m_BuiltStructure[i]->getElectricPower(); - } + totalPower += m_BuiltStructure[i]->getElectricPower(); } return totalPower; } diff --git a/include/Mechanics/UnitManager.hpp b/include/Mechanics/UnitManager.hpp index 2ad6367a..f55187a3 100644 --- a/include/Mechanics/UnitManager.hpp +++ b/include/Mechanics/UnitManager.hpp @@ -32,7 +32,6 @@ class UnitManager : public Player { m_AvatarManager->Start(m_Map); m_CursorSelection->Start(m_Map); - m_StartTime = std::chrono::high_resolution_clock::now(); } void Update(); @@ -49,6 +48,7 @@ class UnitManager : public Player { return m_StructureManager; } + int updateCurrency(); void spawnToWayPoint(UnitType unit, HouseType house); @@ -57,12 +57,20 @@ class UnitManager : public Player { void addUnitConstructCount(UnitType type, int value) { unitCount[type] += value; } - int getUnitConstructCount(UnitType type) { return unitCount[type]; } - int getAvatarCount() { return unitCount[UnitType::INFANTRY]; } - void addAvatarCount(UnitType type, int value) { unitCount[type] += value; } + + int getUnitConstructCount(UnitType type){ + return unitCount[type]; + } + int getAvatarCount(){ + return m_AvatarManager->getAvatarSize();; + } + + + + private: - std::unordered_map unitCount; + std::unordered_map unitCount; std::shared_ptr m_CursorSelection = std::make_shared(); std::shared_ptr m_StructureManager = @@ -70,9 +78,8 @@ class UnitManager : public Player { std::shared_ptr m_AvatarManager = std::make_shared(); std::shared_ptr m_Map = std::make_shared(); - std::chrono::high_resolution_clock::time_point m_StartTime; - double m_lastElapsed = 0.F; - int m_troopSize = 0; + float m_mainDeltaTime = 0; + Util::Time m_Time; }; #endif // PRACTICALTOOLSFORSIMPLEDESIGN_UNITMANAGER_HPP diff --git a/include/Scene/SandBoxScene.hpp b/include/Scene/SandBoxScene.hpp index 1c51e723..08c293e6 100644 --- a/include/Scene/SandBoxScene.hpp +++ b/include/Scene/SandBoxScene.hpp @@ -27,8 +27,6 @@ class SandBoxScene : public Scene { SpriteSheet m_SpriteSheet; std::shared_ptr m_Cursor = std::make_shared(); Grid testGrid; - std::shared_ptr m_Enemy = - std::make_shared(SceneMode::TUTORIAL); std::shared_ptr m_EnemyScripts = std::make_shared(); Stages m_stage = Stages::START; diff --git a/include/Scene/TutorialScene.hpp b/include/Scene/TutorialScene.hpp index d0903eba..c38ce404 100644 --- a/include/Scene/TutorialScene.hpp +++ b/include/Scene/TutorialScene.hpp @@ -42,8 +42,6 @@ class TutorialScene : public Scene { SpriteSheet m_SpriteSheet; std::shared_ptr m_Cursor = std::make_shared(); Grid testGrid; - std::shared_ptr m_Enemy = - std::make_shared(SceneMode::TUTORIAL); std::shared_ptr m_EnemyScripts = std::make_shared(); std::shared_ptr m_PlayerObjectivesText = diff --git a/include/Structure/AdvencePowerPlants.hpp b/include/Structure/AdvencePowerPlants.hpp index aa867bd7..7720bce6 100644 --- a/include/Structure/AdvencePowerPlants.hpp +++ b/include/Structure/AdvencePowerPlants.hpp @@ -22,8 +22,8 @@ class ADVPowerPlants : public Structure { "../assets/sprites/ADVPowerPlants_SpriteSheet.png", 72, 72, 13, 0); m_SpriteSheetAnimation->initSpriteSheetAnimation(m_StructureSpriteSheet, false, INTERVAL, false); - m_RelativeOccupiedArea = {{0, 0}, {0, 1}, {0, 2}, - {1, 0}, {1, 1}, {1, 2}}; + m_RelativeOccupiedArea = {{0, 0}, {0, 1}, + {1, 0}, {1, 1},{2,0},{2,1}}; } void SetObjectLocation(glm::vec2 location) override { location = MapUtil::PositionStickToGrid(location); diff --git a/src/AI/EnemyScripts.cpp b/src/AI/EnemyScripts.cpp index 655e05ae..0ee23a10 100644 --- a/src/AI/EnemyScripts.cpp +++ b/src/AI/EnemyScripts.cpp @@ -2,13 +2,16 @@ // Created by nudle on 2024/5/23. // #include "AI/EnemyScripts.hpp" -void EnemyScripts::Start(std::shared_ptr GameObjectManager, - std::shared_ptr EnemyObjectManager, - std::shared_ptr map, bool active) { - m_GameObjectManager = GameObjectManager; + +#define MAX_TROOPS_SIZE 25 +void EnemyScripts::Start(std::shared_ptr GameObjectManager,std::shared_ptr EnemyObjectManager,std::shared_ptr map,bool active){ + m_GameObjectManager=GameObjectManager; + m_EnemyObjectManager = EnemyObjectManager; m_Map = map; m_active = active; + m_AIGroupCommander = std::make_shared(GameObjectManager,EnemyObjectManager,map); + m_AIGroupCommander->Start(); } void EnemyScripts::Update() { @@ -43,6 +46,7 @@ void EnemyScripts::Update() { m_AvatarCDTime * (-1.f)); } modeUpdate(); + m_AIGroupCommander->Update(); } } @@ -50,27 +54,33 @@ void EnemyScripts::modeUpdate() { if (!ifBuiltBasic()) { buildBasic(); } else { - if (m_EnemyObjectManager->getAvatarCount() == 0 || - (m_GameObjectManager->getAvatarCount() / - m_EnemyObjectManager->getAvatarCount() >= + float playerAvatarCount = m_GameObjectManager->getAvatarCount(); + float enemyAvatarCount = m_EnemyObjectManager->getAvatarCount(); + if (enemyAvatarCount == 0 || + (playerAvatarCount / + enemyAvatarCount >= 2 && - m_GameObjectManager->getAvatarCount() != 0)) { + playerAvatarCount != 0)) { // Defense mode , spawn Troop only spawnUnit(); - } else { - if (m_GameObjectManager->getAvatarCount() / - m_EnemyObjectManager->getAvatarCount() <= - 0.5) { - // Attack , set all troop to attack mode , set defensive Troop = - // 0 - updateAllTroopStates(); - } else { - // Safe now , build adv or spawn troop - if (!ifBuiltADV()) { + }else{ + if(playerAvatarCount/enemyAvatarCount<=0.5){ + //Attack , set all troop to attack mode , set defensive Troop = 0 + //updateAllTroopStates(); + m_AIGroupCommander->setAllTroopToAttackMode(); + spawnUnit(); + }else{ + //Safe now , build adv or spawn troop + if(m_AIGroupCommander->getDefensiveTroopSize()>25){ + m_AIGroupCommander->setTroopToAttackMode(m_AIGroupCommander->getDefensiveTroopSize()-25); + } + if(!ifBuiltADV() && enemyAvatarCountgetAvatarCount() > 50) { + m_EnemyObjectManager->getAvatarCount() > 16) { return; } if (m_EnemyObjectManager->getAvatarCount() <= 25 && @@ -173,7 +185,7 @@ void EnemyScripts::UpdateSpawnScript(SpawnMode spawnMode) { if (m_selectedBuildingType == UnitType::NONE) { return; } - m_GameObjectManager->spawn( + m_EnemyObjectManager->spawn( m_selectedBuildingType, HouseType::ENEMY, {m_baseCell.x + constructCountX, m_baseCell.y + constructCountY}); m_EnemyObjectManager->addUnitConstructCount(m_selectedBuildingType, 1); @@ -193,7 +205,7 @@ void EnemyScripts::UpdateSpawnScript(SpawnMode spawnMode) { return; } if (m_selectedAvatarType == UnitType::INFANTRY) { - m_GameObjectManager->spawnToWayPoint(m_selectedAvatarType, + m_EnemyObjectManager->spawnToWayPoint(m_selectedAvatarType, HouseType::ENEMY); setCost(0, SpawnMode::AVATAR); setCDTime(0.f, SpawnMode::AVATAR); diff --git a/src/Avatar/Avatar.cpp b/src/Avatar/Avatar.cpp index 2106e901..481e7379 100644 --- a/src/Avatar/Avatar.cpp +++ b/src/Avatar/Avatar.cpp @@ -32,6 +32,12 @@ void Avatar::Update() { getAvatarOrder()->setAvatarOrder(AvatarOrderType::NO_ORDER); } } else if (getAvatarOrder()->getAvatarOrder() == + AvatarOrderType::CHASE) { + m_Moving->moveUpdate(); + if (getMoving()->getCurrentDir() == MoveDirection::IDLE) { + getAvatarOrder()->setAvatarOrder(AvatarOrderType::NO_ORDER); + } + }else if (getAvatarOrder()->getAvatarOrder() == AvatarOrderType::NO_ORDER) { noorderUpdate(); } else if (getAvatarOrder()->getAvatarOrder() == diff --git a/src/Avatar/PathUtility.cpp b/src/Avatar/PathUtility.cpp index 9d9709b4..021a71d8 100644 --- a/src/Avatar/PathUtility.cpp +++ b/src/Avatar/PathUtility.cpp @@ -85,9 +85,6 @@ MoveDirection PathUtility::getDirByRelativeCells(glm::vec2 currentcell, int destinationCellY = destinationcell.y; int currCellX = currentcell.x; int currCellY = currentcell.y; - printf("(findNextCellDir)Cell now :{%.d,%.d}\n(find)Cell destination : " - "{%.d,%.d}\n", - currCellX, currCellY, destinationCellX, destinationCellY); int xDiff = destinationCellX - currCellX; int yDiff = destinationCellY - currCellY; int xAbs = abs(xDiff); @@ -125,8 +122,35 @@ MoveDirection PathUtility::getDirByRelativeCells(glm::vec2 currentcell, } } } + printf("-----\n(PathUtil)Cell now :{%.d,%.d}\n(PathUtil)Cell destination : " + "{%.d,%.d}\n(PathUtil)Dir : %s\n-----\n", + currCellX, currCellY, destinationCellX, destinationCellY,debug_dirToString(direction).c_str()); return direction; } +std::string PathUtility::debug_dirToString(MoveDirection dir){ + switch (dir) { + case MoveDirection::UP: + return "Up"; + case MoveDirection::UP_RIGHT: + return "Up Right"; + case MoveDirection::UP_LEFT: + return "Up Left"; + case MoveDirection::RIGHT: + return "Right"; + case MoveDirection::LEFT: + return "Left"; + case MoveDirection::DOWN_RIGHT: + return "Down Right"; + case MoveDirection::DOWN_LEFT: + return "Down Left"; + case MoveDirection::DOWN: + return "Down"; + case MoveDirection::IDLE: + return "Idle"; + default: + return "Unknown"; + } +} glm::vec2 PathUtility::getNextCellByCurrent(MoveDirection currentdir, glm::vec2 currentcell) { diff --git a/src/Mechanics/AvatarManager.cpp b/src/Mechanics/AvatarManager.cpp index b22e2890..fe2f5320 100644 --- a/src/Mechanics/AvatarManager.cpp +++ b/src/Mechanics/AvatarManager.cpp @@ -25,6 +25,19 @@ void AvatarManager::Update() { updateTileWhileAvatarMoving(m_AvatarArray[i]); } + if (m_AvatarArray[i]->getAvatarOrder()->getAvatarOrder() == + AvatarOrderType::CHASE) { + updateTileWhileAvatarMoving(m_AvatarArray[i]); + } + + if(m_AvatarArray[i]->getAvatarOrder()->getAvatarOrder()==AvatarOrderType::CHASE && m_AvatarArray[i]->getMoving()->ifMovePathEmpty()){ + glm::vec2 targetCell = m_NemesisManager->getNemesisCell(m_AvatarArray[i]); + auto queue = + m_Navigator->findPath(m_AvatarArray[i]->getMoving()->getCurrentCell(), targetCell); + m_AvatarArray[i]->getMoving()->setMovePath(queue); + m_AvatarArray[i]->getAvatarOrder()->setAvatarOrder(AvatarOrderType::CHASE); + } + // give order to avatar if (m_AvatarArray[i]->getSelected()) { assignOrderToMyAvatar(m_AvatarArray[i]); @@ -55,6 +68,24 @@ void AvatarManager::assignAttackOrderToAvatar(std::shared_ptr avatar, } } } +void AvatarManager::assignAttackOrderToAvatar(std::shared_ptr avatar, + glm::vec2 destcell,HouseType myHouse) { + m_NemesisManager->removeNemesis(avatar); + if (m_Map->getTileByCellPosition(destcell)->ifEnemyAtTile(myHouse)) { + if (m_Map->getTileByCellPosition(destcell)->ifStructureExists()) { + m_NemesisManager->addNemesis( + avatar, m_Map->getTileByCellPosition(destcell)->getStructure()); + } else { + m_NemesisManager->addNemesis( + avatar, + m_Map->getTileByCellPosition(destcell)->getAvatars()[0]); + } + auto queue = + m_Navigator->findPath(avatar->getMoving()->getCurrentCell(), destcell); + avatar->getMoving()->setMovePath(queue); + avatar->getAvatarOrder()->setAvatarOrder(AvatarOrderType::CHASE); + } +} void AvatarManager::assignOrderToMyAvatar(std::shared_ptr avatar) { if (avatar->getID().getHouseType() == HouseType::MY) { diff --git a/src/Mechanics/AvatarNavigator.cpp b/src/Mechanics/AvatarNavigator.cpp index 81dd25e3..1df8e392 100644 --- a/src/Mechanics/AvatarNavigator.cpp +++ b/src/Mechanics/AvatarNavigator.cpp @@ -13,7 +13,10 @@ std::deque AvatarNavigator::findPath(glm::vec2 currentcell, Side whichSideToTouchObstacle = randomlyChooseSide(); - while (currentcell != destinationcell) { + int count = 0; + while (currentcell != destinationcell && count<100) { + printf("(findPath)\n"); + count++; std::vector staightDirque; bool canFindStraightPath = findStraightPath(currentcell, destinationcell, &staightDirque); @@ -27,6 +30,7 @@ std::deque AvatarNavigator::findPath(glm::vec2 currentcell, } break; } else { + auto facingDir = PathUtility::getDirByRelativeCells( currentcell, destinationcell); // turn @@ -57,7 +61,7 @@ AvatarNavigator::moveAlongsideObstacle(Side side, glm::vec2 currentcell, std::vector path; while (!canResumeWalkingStraight(currentcell, destinationcell)) { - + printf("(moveAlongsideObstacle)\n"); // if next is not touched by obstacle, turn if (!isTouchedByObstacle(side, currentcell, currentdir)) { currentdir = PathUtility::findNewDirWhenNotTouchedByObstacle( @@ -79,6 +83,7 @@ MoveDirection AvatarNavigator::findNewDirWhenCrash(Side side, glm::vec2 currentcell, MoveDirection currentdir) { MoveDirection newdir = currentdir; + int crashCount = 0; while (m_Map ->getTileByCellPosition( PathUtility::getNextCellByCurrent(newdir, currentcell)) @@ -153,10 +158,20 @@ MoveDirection AvatarNavigator::findNewDirWhenCrash(Side side, break; } } +// newdir=recursionCrashHandler(newdir,crashCount); + crashCount++; } return newdir; } - +MoveDirection AvatarNavigator::recursionCrashHandler(MoveDirection currentDir,int count){ + int enumSize = 8; + int newDirValue = (static_cast(currentDir) + count) % enumSize; + if (newDirValue < 0) { + newDirValue += enumSize; + } + printf("(recursionCrashHandler)crashCount : %d\n",count); + return static_cast(newDirValue); +} bool AvatarNavigator::isTouchedByObstacle(Side side, glm::vec2 currentcell, MoveDirection currentdir) { currentcell = PathUtility::getNextCellByCurrent(currentdir, currentcell); @@ -262,6 +277,7 @@ bool AvatarNavigator::findStraightPath(glm::vec2 currentcell, std::vector *path) { while (currentcell != destinationcell) { + printf("(findStraightPath)\n"); MoveDirection followingDir = PathUtility::getDirByRelativeCells(currentcell, destinationcell); diff --git a/src/Mechanics/UnitManager.cpp b/src/Mechanics/UnitManager.cpp index a2c3a32a..f67b7698 100644 --- a/src/Mechanics/UnitManager.cpp +++ b/src/Mechanics/UnitManager.cpp @@ -25,7 +25,6 @@ void UnitManager::spawnToWayPoint(UnitType unit, HouseType house) { avatar, m_StructureManager->getStructureArray() ->getPlayerBarrackWayPointCell()); m_AvatarManager->AppendAvatar(avatar); - m_troopSize += 1; } default: { @@ -42,54 +41,48 @@ void UnitManager::spawn(UnitType unit, HouseType house, glm::vec2 cellPos) { auto structure = std::make_shared(house); auto globalPos = MapUtil::CellCoordToGlobal(cellPos); structure->Start(globalPos); - structure->setWaypointLocationByCellCoord( - {cellPos.x + 2, cellPos.y - 2}); - m_StructureManager->getStructureArray()->buildNewStructure(structure, - true); + m_StructureManager->getStructureArray()->buildNewStructure( + structure, true); + structure->setWaypointLocationByCellCoord({cellPos.x+2,cellPos.y+2}); break; } case UnitType::ORE_REF: { auto structure = std::make_shared(house); auto globalPos = MapUtil::CellCoordToGlobal(cellPos); structure->Start(globalPos); - m_StructureManager->getStructureArray()->buildNewStructure(structure, - true); + m_StructureManager->getStructureArray()->buildNewStructure( + structure, true); break; } case UnitType::POWER_PLANT: { auto structure = std::make_shared(house); auto globalPos = MapUtil::CellCoordToGlobal(cellPos); structure->Start(globalPos); - m_StructureManager->getStructureArray()->buildNewStructure(structure, - true); + m_StructureManager->getStructureArray()->buildNewStructure( + structure, true); break; } case UnitType::WAR_FACT: { auto structure = std::make_shared(house); auto globalPos = MapUtil::CellCoordToGlobal(cellPos); structure->Start(globalPos); - structure->setWaypointLocationByCellCoord( - {cellPos.x + 2, cellPos.y - 2}); - m_StructureManager->getStructureArray()->buildNewStructure(structure, - true); + structure->setWaypointLocationByCellCoord({cellPos.x+2,cellPos.y-2}); + m_StructureManager->getStructureArray()->buildNewStructure( + structure, true); break; } case UnitType::ADV_POWER_PLANT: { auto structure = std::make_shared(house); auto globalPos = MapUtil::CellCoordToGlobal(cellPos); structure->Start(globalPos); - m_StructureManager->getStructureArray()->buildNewStructure(structure, - true); + m_StructureManager->getStructureArray()->buildNewStructure( + structure, true); break; } case UnitType::INFANTRY: { auto avatar = std::make_shared(house); avatar->Start(cellPos); - // avatar ->setNewDestination(cellPos); - m_AvatarManager->assignMoveOrderToAvatar( - avatar, {cellPos.x + 1, cellPos.y + 1}); m_AvatarManager->AppendAvatar(avatar); - m_troopSize += 1; break; } case UnitType::NONE: { @@ -101,6 +94,9 @@ void UnitManager::spawn(UnitType unit, HouseType house, glm::vec2 cellPos) { break; } } + if(unit!=UnitType::NONE){ + addUnitConstructCount(unit,1); + } } void UnitManager::Update() { @@ -108,14 +104,12 @@ void UnitManager::Update() { m_AvatarManager->Update(); m_CursorSelection->Update(); + m_mainDeltaTime += m_Time.GetDeltaTime(); // currency update - std::chrono::high_resolution_clock::time_point m_currentTime = - std::chrono::high_resolution_clock::now(); - std::chrono::duration elapsed = m_currentTime - m_StartTime; - if (elapsed.count() - m_lastElapsed >= 1) { // update every second - m_lastElapsed = elapsed.count(); + if (m_mainDeltaTime >= 1) { + m_mainDeltaTime = 0; + updateCurrency(); } - m_StructureManager->SelectingBuildSite(); } diff --git a/src/Scene/SandBoxScene.cpp b/src/Scene/SandBoxScene.cpp index 0bede413..514d083a 100644 --- a/src/Scene/SandBoxScene.cpp +++ b/src/Scene/SandBoxScene.cpp @@ -101,10 +101,9 @@ void SandBoxScene::stageStart() { break; } case Stages::STAGE4: { - for (int i = 0; i < 50; i++) { - m_EnemyObjectManager->spawn(UnitType::INFANTRY, HouseType::ENEMY, - {30 + i / 5, 5 + i % 5}); - } + m_GameObjectManager->spawn( UnitType::BARRACKS, HouseType::MY,{7,5}); + m_GameObjectManager->spawn(UnitType::INFANTRY, HouseType::MY, {7, 9}); + m_GameObjectManager->spawn(UnitType::INFANTRY, HouseType::MY, {7, 8}); m_stage = Stages::END; break; } @@ -133,11 +132,11 @@ void SandBoxScene::stageUpdate() { if (Util::Input::IsKeyPressed(Util::Keycode::NUM_4)) { m_stage = Stages::STAGE4; m_EnemyScripts->Start(m_GameObjectManager, m_EnemyObjectManager, - m_Map, false); + m_Map, true); stageStart(); } } - if (Util::Input::IsKeyPressed(Util::Keycode::DEBUG_KEY)) { - m_Enemy->addTotalCurrency(500); + if (Util::Input::IsKeyPressed(Util::Keycode::DEBUG_KEY )) { + m_EnemyObjectManager->addTotalCurrency(500); } } diff --git a/src/Scene/TutorialScene.cpp b/src/Scene/TutorialScene.cpp index 7f03bb19..3e33fbbb 100644 --- a/src/Scene/TutorialScene.cpp +++ b/src/Scene/TutorialScene.cpp @@ -10,9 +10,9 @@ void TutorialScene::Start() { 64, 64); m_GameObjectManager->Start(m_Map); m_EnemyObjectManager->Start(m_Map); + m_GameObjectManager->setTotalCurrency(5000); + m_EnemyObjectManager->setTotalCurrency(5000); m_UI->Start(m_Map, m_GameObjectManager); - m_Player->setTotalCurrency(5000); - m_Enemy->setTotalCurrency(5000); m_SceneCamera->Start(MapUtil::CellCoordToGlobal(glm::vec2(-10, -10)), MapUtil::CellCoordToGlobal(glm::vec2(100, 100))); diff --git a/src/Structure/WarFactory.cpp b/src/Structure/WarFactory.cpp index 2e7f32fd..bb60cb73 100644 --- a/src/Structure/WarFactory.cpp +++ b/src/Structure/WarFactory.cpp @@ -26,7 +26,7 @@ void WarFactory::Start(glm::vec2 location) { // Set Texture---------------------------------------- m_StructureSpriteSheet->Start( "../assets/sprites/WarFactory_SpriteSheet.png", 72, 48, 15, 0); - SetRelativeOccupiedArea({{0, 0}, {0, 1}, {0, 2}, {1, 0}, {1, 1}, {1, 2}}); + SetRelativeOccupiedArea({{0, 0}, {0, 1}, {1, 0}, {1, 1}, {2, 1}, {2, 0}}); m_wayPoint->SetDrawable( std::make_unique("../assets/sprites/flagB.png")); m_HighLight.SetDrawable( diff --git a/src/UI/UIScriptProcess.cpp b/src/UI/UIScriptProcess.cpp index 26088564..a932620b 100644 --- a/src/UI/UIScriptProcess.cpp +++ b/src/UI/UIScriptProcess.cpp @@ -227,7 +227,7 @@ std::shared_ptr UIScriptProcess::spawnAvatar() { // printf("(UISC)spawnAvatar\n"); switch (m_currentInfType) { case UnitType::INFANTRY: { - return std::make_unique(); + return std::make_unique(HouseType::MY); } } }