Path Guide - B477042/GraduationProject GitHub Wiki
Player์ ๊ฒ์ ์งํ์ ๋์์ด ๋๋๋ก ์ถ๊ฐํ์ต๋๋ค.
Node๋ค์ Treeํํ๋ก ๊ตฌ์ฑํ ํ, ๊ทธ ์์์ Astar๋ฅผ ์ ์ฉํ๋ค๋ฉด ๊ธธ์ ์๋ดํ ์ ์์์ง ๊ถ๊ธํด์ Tree์ Astar๋ฅผ ์กฐํฉํ ํํ๋ฅผ ๋๊ณ ์์ต๋๋ค.
UCLASS()
class ESCAPEGAME_API AAStarFinder : public AActor
{
//๋ฐฉ๋ฌธํด์ผ๋ ๋
ธ๋
//UPROPERTY(Transient)
TQueue<TWeakObjectPtr<AAstarNode>>ToVisitNodes;
//Goal Node in map
UPROPERTY(Transient, EditInstanceOnly, meta = (AllowPrivateAccess = "true"))
TWeakObjectPtr<AAstarNode> GoalNode;
//CardKey Node
TWeakObjectPtr<AAstarNode>KeyNode;
UPROPERTY(Transient, meta = (DisplayName = "Nodes"))
TArray< TWeakObjectPtr<AAstarNode>>AllNodes;
}
์ด๊ธฐ์ UE4์ Singleton class๋ก ์ค์ ํด์ ํ์ฉํ์ต๋๋ค. ํ์ง๋ง, Singleton class์ ํน์ฑ์ ๊ณ์ ์๋ํฐ์ ๊ฒ์์ ์กด์ฌํ๊ธฐ ๋๋ฌธ์ ๋ชฉ์ ์ ๋ง์ง ์์์ Actor ํํ๋ก ๋ค์ ๋ง๋ค์์ต๋๋ค.
AAstarNode๋ค์ AllNodes๋ผ๋ ๋ฐฐ์ด์ Weak Pointer ํํ๋ก ๋ด์๋์ต๋๋ค.
๊ฒฝ๋ก๋ฅผ ์ฐพ์ ๋
ธ๋๋ฅผ Goal ํน์ Key ๋ฉค๋ฒ ๋ณ์ ๊ฐ์ผ๋ก ์ง์ ํ์ต๋๋ค.
void AAStarFinder::PathFind(AAstarNode * Start,EPathTarget Mode)
{
if (!Start)
{
EGLOG(Error, TEXT("Start is nullptr"));
return;
}
ToVisitNodes.Empty();
ToVisitNodes.Enqueue(Start);
switch (Mode)
{
case EPathTarget::Key:
KeyFind(Start, KeyNode.Get());
break;
case EPathTarget::Gate:
GoalFind(Start, GoalNode.Get());
break;
default:
break;
}
}
void AAStarFinder::GoalFind(AAstarNode * Start, AAstarNode * Goal)
{
if (!Start)
{
EGLOG(Error, TEXT("Nullptr"));
return;
}
if (!Goal)
{
EGLOG(Error, TEXT("Nullptr"));
return;
}
๊ฒฝ๋ก์ ํ์ ๊ธฐ๋ฅ์ผ๋ก Goal๊ณผ Key๋ฅผ ์ฐพ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๊ณ ์์ต๋๋ค. ๋์ ์๊ณ ๋ฆฌ์ฆ์ ๊ฐ๊ณ ์ฐพ๋ ๋์๋ง ๋ค๋ฅธ ํจ์์ ๋๋ค.
TWeakObjectPtr<AAstarNode> PopedNode;
int i = 0;
//๋ฐฉ๋ฌธํด์ผ๋ ๋
ธ๋๊ฐ ๋น์์ง ๋๊น์ง
while (!ToVisitNodes.IsEmpty())
{
i++;
//Queue์์ ํ๋๋ฅผ ๊บผ๋ธ๋ค
ToVisitNodes.Dequeue(PopedNode);
if (!PopedNode.IsValid())
{
EGLOG(Error, TEXT("PopedNode is invalid"));
return;
}
//EGLOG(Warning, TEXT("Current Node : %s"), *PopedNode->GetName());
//๋
ธ๋์ ๋ฐฉ๋ฌธ์ ๋ง์น๋ค
PopedNode->VisitNode();
//๊บผ๋ธ ๋
ธ๋๊ฐ Goal๊ณผ ์์น๊ฐ ๊ฐ๋ค๋ฉด
if (PopedNode->GetActorLocation() == Goal->GetActorLocation())
{
//GoalNode๋ฅผ ์ค์ ํด์ฃผ๊ณ ToVisiteNode๋ฅผ ๋น์์ค๋ค
// EGLOG(Error, TEXT("Goal Find! : %s"), *PopedNode->GetName());
GoalNode = PopedNode.Get();
ToVisitNodes.Empty();
break;
}
while ๋ฃจํ์ ์กฐ๊ฑด์ผ๋ก ToVisitNodes๊ฐ ๋น์์ง ๋๊น์ง ๋ฐ๋ณต๋๊ฒ ํ์ต๋๋ค.๊ทธ๋ฆฌ๊ณ Queue์ ๋ด๊ธด ์์๋๋ก ๋ ธ๋๋ค์ ๊ฒ์ฌํ์ต๋๋ค.
๋ ธ๋๋ฅผ ๊บผ๋ธ ์งํ ๋ ธ๋์ ๋ฐฉ๋ฌธํ ๋ ธ๋์์ ํ์ํ์ต๋๋ค. Goal ๋ ธ๋๋ฅผ ์ฐพ๋ ์์ ์ด๊ธฐ์ ์ฌ๊ธฐ์๋ Goal ๋ ธ๋์ธ์ง ๊ฒ์ฌ๋ฅผ ์งํํ์ต๋๋ค.
//์ธ๊ทผ๋
ธ๋๋ค์ ์ฃผ๋ณ ๋
ธ๋๋ค์ด ์๋ค๋ฉด
if (PopedNode->NearNodes.GetData() != nullptr)
//์ธ๊ทผ ๋
ธ๋๋ค์ ๊ฐ์ ๊ณ์ฐํ๋ค
{
for (auto it : PopedNode->NearNodes)
{
//์ ํจํ์ง ์๋ค๋ฉด ๋์ด๊ฐ๋ค
if (!it.IsValid())continue;
//๋ฐฉ๋ฌธํ๋ ๋
ธ๋๋ฉด ๋์ด๊ฐ๋ค.
if (it->IsVisitedNode())continue;
it->CalcFCount(Start->GetActorLocation(), Goal->GetActorLocation());
}
//๊บผ๋ธ ๋
ธ๋์ ์ฃผ๋ณ ๋
ธ๋๋ค์ ์ด์ ๋
ธ๋๋ฅผ ๊บผ๋ธ ๋
ธ๋๋ก ์ค์ ํด์ค๋ค.
PopedNode->SetNearNodesPrevAsMe();
//fcount ์์ผ๋ก ์ ๋ ฌ
for (int k = 0; k < PopedNode->NearNodes.Num();++k)
{
for (int j = k+1 ; j < PopedNode->NearNodes.Num()-1; ++j)
{
//๋น๊ต์ ์ ํจ์ฑ ๊ฒ์ฌ
if (!PopedNode->NearNodes[k].IsValid() || !PopedNode->NearNodes[j].IsValid())continue;
if (PopedNode->NearNodes[k]->GetF() > PopedNode->NearNodes[j]->GetF())
PopedNode->NearNodes.Swap(k, j);
}
}
๋ฐฉ๋ฌธํ ์ด ๋
ธ๋๊ฐ Goal์ด ์๋๋ผ๋ฉด ์ธ๊ทผ ๋
ธ๋๋ค์ ์ ํจ์ฑ์ ๊ฒ์ฌํ ํ F Count๋ฅผ ๊ณ์ฐํ์ต๋๋ค.
๊ฒ์ฌ๊ฐ ๋๋ ํ, ๊ฒฝ๋ก๋ฅผ ํ์ํ๊ธฐ ์ํด์ List ํํ๋ก Node๋ค์ ์ฐ๊ฒฐ ์ํค๊ธฐ ๋๋ฌธ์ ์ฃผ๋ณ ๋
ธ๋๋ค์ ์ด์ ๋
ธ๋ ๊ฐ์ผ๋ก ์์ ์ ์ง์ ํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ Near Node๋ค์ ๋ฐฐ์ด ์์๋ฅผ Fcount์์ผ๋ก ๋ค์ ์ ๋ ฌ์ ํฉ๋๋ค. ๊ฒฝ์ฐ์ ์๊ฐ ๋ง์ง ์๊ธฐ ๋๋ฌธ์ Bubble Sort๋ฅผ ์งํํ์ต๋๋ค.
F,G,H ์นด์ดํธ์ ๊ณ์ฐ์ ๊ธฐ์ค์ ๊ฐ์ฒด์ ์ขํ ๋ฒกํฐ ๊ฐ์ผ๋ก ํ์ต๋๋ค.
//์ ๋ ฌ๋ ์์๋๋ก ๋ฃ๋๋ค
for (auto it : PopedNode->NearNodes)
{
//์ ํจํ์ง ์๋ค๋ฉด ๋์ด๊ฐ๋ค
if (!it.IsValid())continue;
//๋ฐฉ๋ฌธํ๋ ๋
ธ๋๋ฉด ๋ค์ ์ ๋ฃ์ด๋ ๋๋ค
if (it->IsVisitedNode())continue;
//PopedNode->VisitNode();
// EGLOG(Warning, TEXT("Enqueue : %s"), *it->GetName());
ToVisitNodes.Enqueue(it.Get());
}
}
}
//================ While ๋ฃจํ ์ข
๋ฃ ==============
//๊ณจ ๋
ธ๋๋ฅผ ์ฐพ์๋ค๋ฉด ๊ฒฝ๋ก๋ค์ ํ์ฑํ ์์ผ์ค๋ค
if (GoalNode.IsValid())
ShowPath(EPathTarget::Gate);
}
์ ๋ ฌ๋ ์์๋๋ก ToVisitNodes์ ๋ฃ์ด์ค๋๋ค.
While ๋ฃจํ๊ฐ ๋๋๊ณ Goal Node๋ฅผ ๋ฐ๊ฒฌํด์ ์ฐพ์๋ค๋ฉด, Node์ ์ง์ ํ ์ด์ ๋
ธ๋๋ค์ ํ์ฑํ ์์ผ ๊ฒฝ๋ก๋ฅผ ํ์ํ๋ ๋ฐฉ๋ฒ์
๋๋ค.
ํธ๋ฆฌ ํํ์ ๊ตฌ์กฐ์ธ๋ฐ Astar๊ฐ ๊ณผ์ฐ ์ ์ฉ์ด ๋ ๊นํ๋ ์๋ฌธ์ด ์์์ง๋ง ๊ฒฐ๊ณผ์ ์ผ๋ก ๊ฒฝ๋ก๋ ์ ํ์๊ฐ ๋์ต๋๋ค.
์ด ๊ฒ์ ๊ตฌํํ ๋ ์ง์คํ ์ ์ ๊ณ์ฐ์ ์์ํ๋ ์์ ์ด Player๊ฐ ๋
ธ๋์ ๋ฟ์์ ๋ ์์ํ๊ธฐ ๋๋ฌธ์ ์ด ์์
๋๋ฌธ์ ์ฑ๋ฅ์ด ๋์ ๋๊ฒ ๋จ์ด์ง๋ ๊ฒฝ์ฐ๋ ์์ด์ผ ๋๋ค๋ ์๊ฐ ๋ฟ์ด์์ต๋๋ค. ๋์ ๋๋ ํ๋ ์ ๋ณํ ์์ด ๊ฒฝ๋ก๊ฐ ์ ํ์ ๋์ ์ข์์ต๋๋ค.
AStar ์๊ณ ๋ฆฌ์ฆ์ ์ ํํ ์ดํดํ๊ณ ๋ง๋ค๊ธฐ ์ํด AStar๋ฅผ ๊ณต๋ถํ๋ ๊ณผ์ ์ด ์ด๋ ค์ ์ต๋๋ค. F,G,H๋ผ๋ ์ํ๋ฒณ์ ๋ณ์๋ก ์ฌ์ฉํ ํ์ ์ด๊ฒ ๋ฌด์จ ์๋ฏธ์ธ์ง ํ๊ฐ๋ ธ์ต๋๋ค. ๊ณต๋ถ๋ฅผ ๋๋ด๊ณ ๋ ๋ค F,G,H์ ๊ฐ๊ฐ ์ด๋ฆ์ ์๋ก ๋ถ์ผ์ง ๊ณ ๋ฏผ์ ํ์ง๋ง, ์ ์ธ๊ณ ์ฌ๋๋ค์ด F,G,H๋ก ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ํฌ๊ธฐํ์ต๋๋ค. ์ด ์์ ์ ํตํด ๊ฒ์ ์์ ๊ธธ ์ฐพ๊ธฐ๋ฅผ ์ ์ฉ ์์ผ๋ณด๋ ๊ฒฝํ์ ํ๊ฒ ๋๊ณ ์๊ณ ๋ฆฌ์ฆ์ด ์์๋๋ผ๋ฉด ์ด๊ฑธ ์ด๋ป๊ฒ ๊ตฌํ ํ์์ง ๋ง๋งํ๋ค๋ ์๊ฐ์ด ๋ค์ด ์ด๋ฐ ์๊ณ ๋ฆฌ์ฆ์ ๋ง๋ค์ด์ฃผ์ ๋ถ๋ค๊ป ๊ฐ์ฌํ ๋ง์์ ๊ฐ์ง๊ฒ ๋์ต๋๋ค.
์ด ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ๊ฒฝ์ฐ, ๋ ธ๋๋ค์ ์๋ํฐ์์ ์ด์ด ๋ถ์ฌ์ฃผ๋ ์์ ์ด ํ์ํ๊ธฐ ๋๋ฌธ์ ์ข์ ์์ ์ ์๋๋๋ค. ์ด๋ป๊ฒํ๋ฉด ์๋์ผ๋ก ์๋ก ๋ถ์ผ ์ ์์์ง ๋ฐฉ๋ฒ์ ์ฐพ๊ณ ์ถ์ด์ก์ต๋๋ค.