[UE5] ๐Ÿš€ Project Galaga (5)

Singery00ยท2024๋…„ 5์›” 21์ผ
0

Project Galaga

๋ชฉ๋ก ๋ณด๊ธฐ
5/15
post-thumbnail

๊ฐœ์š”

๐Ÿš€ Project Galaga ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

Unreal C++๊ณผ ๊ฒŒ์ž„์ˆ˜ํ•™์„ ์ ‘๋ชฉํ•ด์„œ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค.

2024.05.04 ~ 2024.05.21์˜ ๊ฐœ๋ฐœ ๊ธฐ๊ฐ„์œผ๋กœ, ์ด 17์ผ ๋™์•ˆ ๊ฐœ๋ฐœ์„ ์™„๋ฃŒํ•˜์˜€์Šต๋‹ˆ๋‹ค.

๊ฑฐ์ฐฝํ•˜๊ฒŒ ์‹œ์ž‘ํ•œ ํ”„๋กœ์ ํŠธ๋ณด๋‹จ ์ง€๊ธˆ๊นŒ์ง€ ๋ฐฐ์šด ๊ฒƒ๋“ค์„ ์ข…ํ•ฉ์ ์œผ๋กœ ์‚ฌ์šฉํ•ด์„œ ๊ฒฐ๊ณผ๋ฌผ์„ ๋งŒ๋“ค์–ด ๋‚ด๋ณด๊ฒ ๋‹ค๋Š” ๋งˆ์Œ์œผ๋กœ ์™„์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.

ํ•ด๋‹น ์‹œ๋ฆฌ์ฆˆ์—๋Š” ๊ฐœ๋ฐœ ์ผ์ง€๋ฅผ ์ •๋ฆฌํ•˜๋ฉฐ, ๊ฐœ๋ฐœ ๋‚ด์šฉ์— ๋Œ€ํ•œ ์„ค๋ช…๊ณผ ์ด์Šˆ๋ฅผ ์ •๋ฆฌํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.

๐Ÿš€ Project Galaga Github Repository


๋ณธ๋ก 

์ ์˜ ์›€์ง์ž„์— ๋Œ€ํ•ด์„œ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„ํ•˜์˜€๋Š”์ง€์— ๋Œ€ํ•ด ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.


๋ฌด๋น™ ํฌ์ธํŠธ

์ ์ด ํŠน์ • ํฌ์ธํŠธ๋กœ ์ด๋™ํ•˜๊ธฐ ์œ„ํ•ด ์ขŒํ‘œ๊ฐ’์„ ๋ฐ›์•„ ์˜ฌ ์ˆ˜ ์žˆ๋Š” ๋ฌด์–ธ๊ฐ€๊ฐ€ ํ•„์š”ํ•˜๋‹ค ์ƒ๊ฐํ•˜์˜€์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ Collision๋งŒ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” Moving Point๋ฅผ ์ƒ์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.

Moving Point

๋‚ด๋ถ€์˜ Moving Point์™€ ์™ธ๋ถ€์˜ Moving Point๋ฅผ ๋ ˆ๋ฒจ์— ๋ฐฐ์น˜ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

Moving Point๋Š” ์ ๊ณผ ์ถฉ๋Œ ์‹œ Overlap Event๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.

์ด๋•Œ ํ•ด๋‹น ์ ์˜ ๋ชฉํ‘œ Moving Point๊ฐ€ ์ž์‹ ์ด ๋งž๋Š”์ง€ ๊ฒ€์‚ฌํ•˜๊ณ , ์ผ์น˜ํ•œ๋‹ค๋ฉด ํŒจํ„ด์„ ๋ณ€ํ™”์‹œ์ผœ ์ค๋‹ˆ๋‹ค.

์ ๋“ค์€ ์ด๋™ํ•˜๋ฉฐ ๋ชฉํ‘œ Moving Point์— ๋„์ฐฉํ•˜๊ฒŒ ๋˜๋ฉด ์›€์ง์ž„ ํŒจํ„ด์ด ์ผ๋‹จ๋ฝ๋ฉ๋‹ˆ๋‹ค.

bool AEnemyMovingPoint::CheckTargetMovingPoint(AEnemyBase* enemy)
{
	auto targetP = enemy->GetTargetMovingPointByIndex(enemy->GetEnemyTargetMovingPointIndex());

	if (targetP)
	{
		AEnemyMovingPoint* targetMovingPoint = Cast<AEnemyMovingPoint>(targetP);
		if (targetMovingPoint != nullptr)
		{
			if (targetMovingPoint == this)
			{
				return true;
			}
		}
	}
	return false;
}

Enemy Manager

Moving Point๋“ค์„ ๊ด€๋ฆฌํ•ด์ฃผ๊ธฐ ์œ„ํ•ด์„œ Enemy Manager Class๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

Enemy Manager๋Š” ๊ฐ Moving Point๋ฅผ ๊ทธ๋ฃน๋ณ„๋กœ ์ฐพ์•„ ์†Œ์œ ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

public:
	// Inner Moving Points
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = SpawnSettings)
	TArray<class AActor*> InnerMovingPoints;

	// Left Moving Points
	UPROPERTY(EditAnywhere, Category = SpawnSettings)
	TArray<class AActor*> LeftMovingPoints;

	// Right Moving Points
	UPROPERTY(EditAnywhere, Category = SpawnSettings)
	TArray<class AActor*> RightMovingPoints;

	// Bottom Moving Points
	UPROPERTY(EditAnywhere, Category = SpawnSettings)
	TArray<class AActor*> BottomMovingPoints;

	// Top Moving Points
	UPROPERTY(EditAnywhere, Category = SpawnSettings)
	TArray<class AActor*> TopMovingPoints;

๊ฒŒ์ž„ ์‹œ์ž‘ ์‹œ ๋ ˆ๋ฒจ์—์„œ ์ด๋ฆ„์„ ๊ธฐ๋ฐ˜์œผ๋กœ Moving Point๋ฅผ ๊ฒ€์ƒ‰ํ•˜์—ฌ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

GetAllActorsOfClass()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ตœ์ดˆ ๋ถ€ํ•˜๊ฐ€ ์‹ฌํ•˜์ง€๋งŒ ๋ชจ๋“  Moving Point๋“ค์„ ์ˆ˜์ž‘์—…์œผ๋กœ ๋„ฃ์ง€ ์•Š๊ณ  ์ž๋™ํ™” ์ž‘์—…์„ ๊ตฌํ˜„ํ•œ๋‹ค๋Š” ๊ฒƒ์— ์˜์˜๋ฅผ ๋‘์—ˆ์Šต๋‹ˆ๋‹ค.

void AEnemyManager::FindEnemyLeftMovingPoints()
{
	TArray<AActor*>allActors;

	UGameplayStatics::GetAllActorsOfClass(GetWorld(), AActor::StaticClass(), allActors);

	for (auto movingP : allActors)
	{
		if (movingP->GetName().Contains(TEXT("BP_EnemyLeftMovingPoint")))
		{
			LeftMovingPoints.Add(movingP);
		}
	}
}

์ ๋“ค์€ Enemy Manager๋ฅผ ํ†ตํ•ด ์›ํ•˜๋Š” ๊ทธ๋ฃน์˜ Moving Point์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๋ฐ›์•„ ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


์›€์ง์ž„ ํŒจํ„ด

์ด๋ ‡๊ฒŒ Enemy Manager๋ฅผ ํ†ตํ•ด ์ ๋“ค์—๊ฒŒ ๋””ํ…Œ์ผํ•œ ์›€์ง์ž„ ํŒจํ„ด์„ ๊ตฌ์‚ฌํ•˜๋„๋ก ์ œ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๊ณ ์ •ํ˜• (Fixed)

์ ์€ ๋ชฉํ‘œ Moving Point๋กœ ์ด๋™ํ•œ ํ›„ ์›€์ง์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

// ๊ณ ์ •		- ์†Œํ™˜ ํ›„ MovingPoint๋กœ ์ด๋™์—์„œ ์›€์ง์ด์ง€ ์•Š์Œ
void UEnemyFSM::FixedMove()
{
	if (GetIsMoving())
	{
		FVector P0 = me->GetActorLocation();

		FVector dir = me->GetDirectionToTargetMovingPoint(0);
		FVector vt = me->GetEnemySpeed() * GetWorld()->DeltaTimeSeconds * dir;

		FVector P = P0 + vt;

		me->SetActorLocation(P);
	}

}


์ˆœํšŒํ˜• (Patrol)

์ˆœํšŒํ˜•์€ ๋ชฉํ‘œ Moving Point๋ฅผ 2๊ฐœ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ ๋ชฉํ‘œ์— ๋„์ฐฉํ•˜๋ฉด ๋ชฉํ‘œ Moving Point๋ฅผ ๋‹ค๋ฅธ ํ•˜๋‚˜๋กœ ์ „ํ™˜ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ด๋ฅผ ํ†ตํ•ด ๊ฐ Moving Point๋ฅผ ๋ฐ˜๋ณตํ•˜๋ฉฐ ์ด๋™ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

// ํŒจํŠธ๋กค	- ํŠน์ • MovingPoint ๋ฐ˜๋ณต
void UEnemyFSM::PatrolMove()
{

	FVector P0 = me->GetActorLocation();

	if (!isMoving)
	{
		if (me->GetEnemyTargetMovingPointIndex() == 0)
		{
			me->SetEnemyTargetMovingPointIndex(1);
		}
		else 
		{
			me->SetEnemyTargetMovingPointIndex(0);
		}

		FVector dir = me->GetDirectionToTargetMovingPoint(me->GetEnemyTargetMovingPointIndex());
		dir.Normalize();
		SetNowMovingDir(dir);

		SetIdleState();
		currentTime = 0.0f;
	}

	FVector vt = me->GetEnemySpeed() * GetWorld()->DeltaTimeSeconds * GetNowMovingDir();

	FVector P = P0 + vt;


	//me->SetActorRotation(FVector::BackwardVector.Rotation());
	me->SetActorLocation(P);
}


์žํญํ˜• (Suiside)

์žํญํ˜•์€ ํ”Œ๋ ˆ์ด์–ด์—๊ฒŒ ์ง€์†์ ์œผ๋กœ ๋”ฐ๋ผ ๋ถ™์œผ๋ฉฐ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.

ํ”Œ๋ ˆ์ด์–ด์™€ ์ถฉ๋Œํ•˜๋ฉด ๊ฐ์ฒด๊ฐ€ ํŒŒ๊ดด๋ฉ๋‹ˆ๋‹ค.

// ์žํญ		- ํ”Œ๋ ˆ์ด์–ด์—๊ฒŒ ๋Œ์ง„
void UEnemyFSM::SuisideMove()
{
	FVector P0 = me->GetActorLocation();
	FVector dir = GetDirection();
	FVector vt = me->GetEnemySpeed() * GetWorld()->DeltaTimeSeconds * dir;

	FVector P = P0 + vt;
	me->SetActorRotation(dir.Rotation());
	me->SetActorLocation(P);
}


ํŒจ์Šคํ˜• (PassBy)

ํŒจ์Šคํ˜•์€ ์™ธ๋ถ€ Moving Point๋ผ๋ฆฌ ์ด๋™ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์™ธ๋ถ€ > ๋‚ด๋ถ€ > ์™ธ๋ถ€๋กœ ์ด๋™ํ•˜๋ฉฐ ์ง€๋‚˜๊ฐ€๋Š” ํŒจํ„ด์ž…๋‹ˆ๋‹ค.

์™ธ๋ถ€๋กœ ๋‚˜๊ฐ€๋ฉด ์•กํ„ฐ๋Š” ํŒŒ๊ดด๋˜๋„๋ก ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

// ํ†ต๊ณผ		- ์†Œํ™˜์œ„์น˜์—์„œ ๋ชฉํ‘œ MovingPoint๋กœ ์ด๋™ ํ›„ ์†Œ๋ฉธ
void UEnemyFSM::PassByMove()
{
	FVector P0 = me->GetActorLocation();

	FVector dir = me->GetDirectionToTargetMovingPoint(0);
	FVector vt = me->GetEnemySpeed() * GetWorld()->DeltaTimeSeconds * dir;

	FVector P = P0 + vt;

	me->SetActorLocation(P);
}


๋ฌด์ž‘์œ„ํ˜• (Random)

๋ฌด์ž‘์œ„ํ˜•์€ Enemy Manager๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” Inner Moving Point์—์„œ ๋ฌด์ž‘์œ„๋กœ ๋Œ€์ƒ์„ ๋ฐ›์•„์™€ ์›€์ง์ž„์„ ๋ฐ˜๋ณตํ•ฉ๋‹ˆ๋‹ค.

// ๋žœ๋ค		- ๋žœ๋ค MovingPoint๋กœ ๊ณ„์†ํ•ด์„œ ์ด๋™
void UEnemyFSM::RandomMove()
{
	FVector P0 = me->GetActorLocation();

	if (!isMoving)
	{
		SetIsMoving(true);
		FVector targetLocation = enemyManager->GetRandomInnerMovingPoint();
		FVector dir = targetLocation - me->GetActorLocation();
		dir.Normalize();
		SetNowMovingDir(dir);
	}

	FVector vt = me->GetEnemySpeed() * GetWorld()->DeltaTimeSeconds * GetNowMovingDir();

	FVector P = P0 + vt;


	me->SetActorLocation(P);
}


์ถœ์ž…ํ˜• (InOut)

์ถœ์ž…ํ˜•์€ ํ•œ๋ฒˆ ๋ชฉํ‘œ ์œ„์น˜๋กœ ๋“ค์–ด์˜จ ํ›„ ๋’ค๋กœ ๋‚˜๊ฐ€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๊ตฌํ˜„ํ•˜๊ธฐ ๊ฐ€์žฅ ๊นŒ๋‹ค๋กœ์› ๋˜ ์›€์ง์ž„ ํŒจํ„ด์œผ๋กœ, ์˜ค์ง 4 Stage๋งŒ์„ ์œ„ํ•ด ๊ตฌํ˜„ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

๋ชฉํ‘œ ์œ„์น˜๋กœ ์ด๋™ ํ›„ ์„ค์ •ํ•œ ์‹œ๊ฐ„๋™์•ˆ ๋Œ€๊ธฐํ•˜๋‹ค, ํ›„์ง„์œผ๋กœ ์ด๋™ํ•˜๋ฉฐ ํŒŒ๊ดด๋ฉ๋‹ˆ๋‹ค.

Timer๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์‹œ Move์ƒํƒœ๋กœ ์ „ํ™˜, ๊ณต๊ฒฉ, ํŒŒ๊ดด๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ์ง„ํ–‰ํ•˜๋„๋ก ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

์ œํ•œ ์‹œ๊ฐ„๋™์•ˆ ์ ์˜ ๊ณต์„ธ์—์„œ ๋ฒ„ํ‹ฐ๊ธฐ ์œ„ํ•ด ์—ฐ์ถœ์ ์ธ ํšจ๊ณผ๋ฅผ ์œ„ํ•œ ์›€์ง์ž„ ํŒจํ„ด์ž…๋‹ˆ๋‹ค.

void UEnemyFSM::InOutMove()
{

	if (GetIsMoving())
	{
		FVector P0 = me->GetActorLocation();
		if (isIn)
		{
			FVector dir = me->GetDirectionToTargetMovingPoint(0);
			FVector vt = me->GetEnemySpeed() * GetWorld()->DeltaTimeSeconds * dir;

			FVector P = P0 + vt;

			me->SetActorLocation(P);
		}
		else {
			FVector dir = -me->GetActorForwardVector();
			dir.Normalize();

			FVector vt = me->GetEnemySpeed() * GetWorld()->DeltaTimeSeconds * dir;

			FVector P = P0 + vt;
			me->SetActorLocation(P);
		}

	}
	else {
		FTimerHandle MoveTimer;
		me->GetWorldTimerManager().SetTimer(MoveTimer, [this]() {
			SetIsMoving(true);
			}, (me->GetInOutDelayTime()+4.0f), false);

		FTimerHandle AttackTimer;
		me->GetWorldTimerManager().SetTimer(AttackTimer, [this]() {
			me->SetEnemyAttackSpeed(50.0f);
			}, me->GetInOutDelayTime(), false);


		FTimerHandle DieTimer;
		me->GetWorldTimerManager().SetTimer(DieTimer, [this]() {
			me->Destroy();
			}, (me->GetInOutDelayTime() + 8.0f), false);
	}

}


๋งˆ๋ฌด๋ฆฌ

์—ฌ๊ธฐ๊นŒ์ง€ ์ด 6๊ฐ€์ง€์˜ ์›€์ง์ž„ ํŒจํ„ด์ด์˜€์Šต๋‹ˆ๋‹ค.

profile
๊ฒŒ์ž„ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜์–ด๋ณด์ž

0๊ฐœ์˜ ๋Œ“๊ธ€