From 0529de4bf927eaa381ba82351a987b11c6c9594d Mon Sep 17 00:00:00 2001 From: "sigonasr2, Sig, Sigo" Date: Mon, 10 Jul 2023 18:40:51 +0000 Subject: [PATCH] Add in pathfinding abilities to monster movement strategies. --- .vscode/settings.json | 3 +- Crawler/Crawler.cpp | 6 ++- Crawler/Crawler.h | 1 + Crawler/Monster.cpp | 83 ++++++++++++++++++++++++++++++++++++----- Crawler/Monster.h | 6 ++- Crawler/Pathfinding.cpp | 3 ++ Crawler/Player.cpp | 2 +- Crawler/Player.h | 1 - Crawler/State.h | 1 + 9 files changed, 92 insertions(+), 14 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index e617935c..fba248f5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -87,6 +87,7 @@ "__tree": "cpp", "bitset": "cpp", "regex": "cpp", - "valarray": "cpp" + "valarray": "cpp", + "*.inc": "cpp" } } \ No newline at end of file diff --git a/Crawler/Crawler.cpp b/Crawler/Crawler.cpp index 4204d6e9..5e859954 100644 --- a/Crawler/Crawler.cpp +++ b/Crawler/Crawler.cpp @@ -33,6 +33,10 @@ bool Crawler::OnUserCreate(){ InitializeLevel("assets/Campaigns/1_1.tmx",CAMPAIGN_1_1); + #ifdef OLC_PLATFORM_EMSCRIPTEN + ConsoleCaptureStdOut(true); + #endif + ClassData::InitializeClassData(); //Initialize Camera. @@ -1096,7 +1100,7 @@ void Crawler::LoadLevel(MapName map){ } player.upperLevel=false; //Assume player starts on lower level. player.SetPos(MAP_DATA[map].MapData.playerSpawnLocation); - player.path.Initialize(); + pathfinder.Initialize(); } vi2d Crawler::GetWorldSize(){ diff --git a/Crawler/Crawler.h b/Crawler/Crawler.h index 8b508b4e..771ce7dd 100644 --- a/Crawler/Crawler.h +++ b/Crawler/Crawler.h @@ -27,6 +27,7 @@ class Crawler : public olc::PixelGameEngine GFX_Splash_Effect; public: Renderable GFX_BulletCircle,GFX_BulletCircleOutline,GFX_EnergyBolt; + Pathfinding pathfinder; private: std::vectorforegroundEffects,backgroundEffects; std::mapMAP_DATA; diff --git a/Crawler/Monster.cpp b/Crawler/Monster.cpp index a205a4a9..8fec1736 100644 --- a/Crawler/Monster.cpp +++ b/Crawler/Monster.cpp @@ -23,6 +23,7 @@ Monster::Monster(vf2d pos,MonsterData data): } } randomFrameOffset=(rand()%1000)/1000.f; + game->pathfinder.Initialize(); } vf2d&Monster::GetPos(){ return pos; @@ -141,13 +142,23 @@ bool Monster::Update(float fElapsedTime){ state=MOVE_TOWARDS; hasHitPlayer=false; } - if(state==MOVE_TOWARDS&&geom2d::line(pos,target).length()>100*fElapsedTime*GetMoveSpdMult()){ - SetPosition(pos+geom2d::line(pos,target).vector().norm()*100*fElapsedTime*GetMoveSpdMult()); - PerformJumpAnimation(); - } else { - if(state==MOVE_TOWARDS){ - state=NORMAL;//Revert state once we've finished moving towards target. - UpdateAnimation(MONSTER_DATA[type].GetAnimations()[0]); + switch(state){ + case MOVE_TOWARDS:{ + if(geom2d::line(pos,target).length()>100*fElapsedTime*GetMoveSpdMult()){ + vf2d newPos=pos+geom2d::line(pos,target).vector().norm()*100*fElapsedTime*GetMoveSpdMult(); + if(!SetX(newPos.x)||!SetY(newPos.y)){ + StartPathfinding(4); + } + PerformJumpAnimation(); + } else { + state=NORMAL;//Revert state once we've finished moving towards target. + UpdateAnimation(MONSTER_DATA[type].GetAnimations()[0]); + } + }break; + case PATH_AROUND:{ + PathAroundBehavior(fElapsedTime); + }break; + default:{ } } }break; @@ -183,12 +194,19 @@ bool Monster::Update(float fElapsedTime){ } canMove=true; geom2d::line moveTowardsLine=geom2d::line(pos,target); + bool pathfindingDecision=false; switch(state){ case MOVE_TOWARDS:{ if(moveTowardsLine.length()>1){ vf2d newPos=pos+moveTowardsLine.vector().norm()*100*fElapsedTime*GetMoveSpdMult(); - canMove=SetX(newPos.x)&&SetY(newPos.y); + bool movedX=SetX(newPos.x); + bool movedY=SetY(newPos.y); + pathfindingDecision=movedX|movedY; + canMove=movedX&&movedY; } + if(!pathfindingDecision){ + StartPathfinding(2.5); + }else if(line.length()<=24*7){ state=NORMAL; } @@ -202,8 +220,14 @@ bool Monster::Update(float fElapsedTime){ case MOVE_AWAY:{ if(moveTowardsLine.length()>1){ vf2d newPos=pos+moveTowardsLine.vector().norm()*100*fElapsedTime*GetMoveSpdMult(); - canMove=SetX(newPos.x)&&SetY(newPos.y); + bool movedX=SetX(newPos.x); + bool movedY=SetY(newPos.y); + pathfindingDecision=movedX|movedY; + canMove=movedX&&movedY; } + if(!pathfindingDecision){ + StartPathfinding(2.5); + }else if(line.length()>=24*6){ state=NORMAL; } @@ -214,6 +238,9 @@ bool Monster::Update(float fElapsedTime){ } PerformJumpAnimation(); }break; + case PATH_AROUND:{ + PathAroundBehavior(fElapsedTime); + }break; default:{ if(attackCooldownTimer==0){ attackCooldownTimer=1; @@ -352,6 +379,44 @@ void Monster::AddBuff(BuffType type,float duration,float intensity){ buffList.push_back(Buff{type,duration,intensity}); } +void Monster::StartPathfinding(float pathingTime){ + state=State::PATH_AROUND; + path=game->pathfinder.Solve_AStar(pos,target,12,OnUpperLevel()); + if(path.size()>0){ + pathIndex=0; + //We gives this mob 5 seconds to figure out a path to the target. + targetAcquireTimer=pathingTime; + } +} + +void Monster::PathAroundBehavior(float fElapsedTime){ + if(path.size()>0){ + //Move towards the new path. + geom2d::line moveTowardsLine=geom2d::line(pos,path[pathIndex]*24); + if(moveTowardsLine.length()>2){ + SetPosition(pos+moveTowardsLine.vector().norm()*100*fElapsedTime*GetMoveSpdMult()); + if(moveTowardsLine.vector().x>0){ + facingDirection=RIGHT; + } else { + facingDirection=LEFT; + } + }else{ + if(pathIndex+1>=path.size()){ + //We have reached the end of the path! + std::cout<<"Reached the end of the path."<Monster::GetBuffs(BuffType buff){ std::vectorfilteredBuffs; std::copy_if(buffList.begin(),buffList.end(),std::back_inserter(filteredBuffs),[buff](Buff&b){return b.type==buff;}); diff --git a/Crawler/Monster.h b/Crawler/Monster.h index 910d1c39..cc1c6841 100644 --- a/Crawler/Monster.h +++ b/Crawler/Monster.h @@ -80,6 +80,9 @@ struct Monster{ bool hasHitPlayer=false; bool canMove=true; //Set to false when stuck due to collisions. bool upperLevel=false; + vf2d pathTarget={}; + std::vectorpath; + int pathIndex=0; protected: public: Monster()=delete; @@ -112,7 +115,8 @@ protected: void PerformShootAnimation(); bool OnUpperLevel(); void Moved(); - + void StartPathfinding(float pathingTime); + void PathAroundBehavior(float fElapsedTime); void AddBuff(BuffType type,float duration,float intensity); std::vectorGetBuffs(BuffType buff); }; diff --git a/Crawler/Pathfinding.cpp b/Crawler/Pathfinding.cpp index 7229fcf3..d8414111 100644 --- a/Crawler/Pathfinding.cpp +++ b/Crawler/Pathfinding.cpp @@ -5,6 +5,9 @@ INCLUDE_game void Pathfinding::Initialize(){ + if(nodes!=nullptr){ + delete[] nodes; + } nodes = new sNode[game->WORLD_SIZE.x * game->WORLD_SIZE.y]; for (int x = 0; x < game->WORLD_SIZE.x; x++) for (int y = 0; y < game->WORLD_SIZE.y; y++) diff --git a/Crawler/Player.cpp b/Crawler/Player.cpp index 2d694e34..1b218798 100644 --- a/Crawler/Player.cpp +++ b/Crawler/Player.cpp @@ -460,6 +460,6 @@ std::vectorPlayer::GetBuffs(BuffType buff){ } bool Player::CanPathfindTo(vf2d pos,vf2d targetPos,float range){ - std::vectorpathing=path.Solve_AStar(pos,targetPos,8,upperLevel); + std::vectorpathing=game->pathfinder.Solve_AStar(pos,targetPos,8,upperLevel); return pathing.size()>0&&pathing.size()<8;//We'll say 7 tiles or less is close enough to 650 range. Have a little bit of wiggle room. } \ No newline at end of file diff --git a/Crawler/Player.h b/Crawler/Player.h index d51ae90c..0b9252e3 100644 --- a/Crawler/Player.h +++ b/Crawler/Player.h @@ -67,7 +67,6 @@ struct Player{ bool SetPos(vf2d pos); void SetClass(Class cl); std::vectorbuffList; - Pathfinding path; protected: public: Player(); diff --git a/Crawler/State.h b/Crawler/State.h index 3ddc6ca3..b57b4d99 100644 --- a/Crawler/State.h +++ b/Crawler/State.h @@ -9,4 +9,5 @@ enum State{ MOVE_AWAY, BLOCK, TELEPORT, + PATH_AROUND }; \ No newline at end of file