๐ Project Galaga ์์ํฉ๋๋ค.
Unreal C++๊ณผ ๊ฒ์์ํ์ ์ ๋ชฉํด์ ํ๋ก์ ํธ๋ฅผ ์งํํ์ต๋๋ค.
2024.05.04 ~ 2024.05.21์ ๊ฐ๋ฐ ๊ธฐ๊ฐ์ผ๋ก, ์ด 17์ผ ๋์ ๊ฐ๋ฐ์ ์๋ฃํ์์ต๋๋ค.
๊ฑฐ์ฐฝํ๊ฒ ์์ํ ํ๋ก์ ํธ๋ณด๋จ ์ง๊ธ๊น์ง ๋ฐฐ์ด ๊ฒ๋ค์ ์ข ํฉ์ ์ผ๋ก ์ฌ์ฉํด์ ๊ฒฐ๊ณผ๋ฌผ์ ๋ง๋ค์ด ๋ด๋ณด๊ฒ ๋ค๋ ๋ง์์ผ๋ก ์์ฑํ์์ต๋๋ค.
ํด๋น ์๋ฆฌ์ฆ์๋ ๊ฐ๋ฐ ์ผ์ง๋ฅผ ์ ๋ฆฌํ๋ฉฐ, ๊ฐ๋ฐ ๋ด์ฉ์ ๋ํ ์ค๋ช ๊ณผ ์ด์๋ฅผ ์ ๋ฆฌํ ์์ ์ ๋๋ค.
ํ๋ ์ด์ด์ ์ฑ๋ฅ์ ํ ์ธต ์ฌ๋ ค์ค ์ ์๋ ์์ดํ ์ด ์์ต๋๋ค.
์์ดํ ์ ๊ตฌํ๋ ๋ด์ฉ๋ค์ ๋ํ์ฌ ์ ๋ฆฌํ๋ ์๊ฐ์ ๊ฐ์ง๊ฒ ์ต๋๋ค.
์์ดํ ๋ ๋์ผํ๊ฒ ๋ฑ์๋ ์ด๋ ๊ณต์์ ์ฌ์ฉํ์ฌ ์์ง์ด๊ฒ ํ์์ต๋๋ค.
ํ์ง๋ง ์์ดํ ์ด ์ญ ์ด๋ํ๋ค๊ฐ ๊ฐ๋ก ๋งํ์ ๋ฉ์ถ๊ฑฐ๋, ๋จน์ ์ ์๊ฒ ๋งต ๋ฐ์ผ๋ก ๋๊ฐ๋ฉด ๊ณค๋ํ๊ฒ ์ฃ ?
๊ทธ๋์ ๋ฒฝ์ ๋ถ๋ชํ๊ฒ ๋๋ค๋ฉด ํ๊ฒจ ๋์ ๋งต ์์์ ๋ ๋๋ค ์ฌ๋ผ์ง๋๋ก ๊ตฌํํ์์ต๋๋ค.
๊ธฐ์กด ๋งต์ ๊ตฌํํด์คฌ๋ ๋ฒฝ๋ค์๊ฒ ํ๊ทธ๋ฅผ ๋ฃ์์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ ๊ฐ ๋ฒฝ๋ง๋ค Overlap Event๊ฐ ๋ฐ์ํ ์, ๋๋คํ ๋ฐ๋ ๋ฐฉํฅ์ผ๋ก ์ด๋ํ๋๋ก ํ์์ต๋๋ค.
else if (OtherActor->ActorHasTag("Edge"))
{
if (boundCount > 0)
{
if (OtherComp->ComponentHasTag("TopEdge"))
{
int rand = FMath::RandRange(0, 1) == 0 ? -1 : 1;
Direction = FVector(-Direction.X, rand, 0);
}
else if (OtherComp->ComponentHasTag("BottomEdge"))
{
int rand = FMath::RandRange(0, 1) == 0 ? -1 : 1;
Direction = FVector(-Direction.X, rand, 0);
}
else if (OtherComp->ComponentHasTag("LeftEdge"))
{
int rand = FMath::RandRange(0, 1) == 0 ? -1 : 1;
Direction = FVector(rand, -Direction.Y, 0);
}
else if (OtherComp->ComponentHasTag("RightEdge"))
{
int rand = FMath::RandRange(0, 1) == 0 ? -1 : 1;
Direction = FVector(rand, -Direction.Y, 0);
}
boundCount -= 1;
}
else
{
FTimerHandle TimerHandle;
GetWorld()->GetTimerManager().SetTimer(TimerHandle, this, &AItem::DestroyItem, 1.5f, false);
}
}
๊ทธ๋ผ ๋งต ์์ ํ๊ธฐ๋ฉด์ ํ๋ ์ด์ด๊ฐ ์์ดํ ์ ๋จน์ ์ ์๊ฒ ๋๊ฒ ์ฃ .
์ถ๊ฐ๋ก ์ต๋ 20๋ฒ๊น์ง๋ง ํ๊ธฐ๋๋ก ๋ง๋ค์์ต๋๋ค.
20ํ๊ฐ ์ง๋๋ฉด ๋งต๋ฐ์ผ๋ก ์ฌ๋ผ์ง๊ณ , ์๋ฉธํ๊ฒ ๋ฉ๋๋ค.
์ ๊ทธ๋ ์ด๋ ํจ๊ณผ์๋ 3๊ฐ์ง๊ฐ ์์ต๋๋ค.
์ด๋ ์ ์ ๋ค์ด ์ํ๋ ํจ๊ณผ๋ฅผ ๋จน์ ์ ์๋๋ก 2.5์ด๋ง๋ค ์์ดํ ์ ํจ๊ณผ๊ฐ ๋ณํ๋๋ก ๋ง๋ค์์ต๋๋ค.
Enum Class๋ฅผ ์ฌ์ฉํ์ฌ ์ ๊ทธ๋ ์ด๋ ํจ๊ณผ๋ฅผ ์ฃผ๊ธฐ์ ์ผ๋ก ๋ณํ ์์ผ ์ฃผ์์ต๋๋ค.
UENUM(BlueprintType)
enum class EItemType : uint8
{
Damage,
Speed,
Count,
Boom,
Hp,
};
์์ดํ ์ด ๊ทธ๋ฅ ๋งต์ ๋์๋ค๋๋ ๋๋ฌด ์ฌ์ฌํ๊ณ ๋ฐ๋ฐํ์ต๋๋ค.
๊ทธ๋์ ์ฝ๊ฐ์ ์ ๋๋ฉ์ด์
ํจ๊ณผ๋ฅผ ์ฃผ๊ณ ์ถ์์ต๋๋ค.
Scale๊ฐ์ 1.0 ~ 2.0์ฌ์ด๋ฅผ VInterpTo ๋ณด๊ฐ์ ์ฌ์ฉํ์ฌ ๋ถ๋๋ฝ๊ฒ ์ปค์ก๋ค ์์์ก๋ค๋ฅผ ๋ฐ๋ณตํ์ฌ '์ด์ ๋จน์ด๋ผ~' ํ๋ ํจ๊ณผ๋ฅผ ๊ตฌํํ์ต๋๋ค.
void AItem::ChangeScale()
{
// 0.5์ด๋ฅผ ๊ธฐ์ค์ผ๋ก ์์ดํ
์ ํฌ๊ธฐ๋ฅผ InterpTo๋ฅผ ์ฌ์ฉํ์ฌ ๋ณ๊ฒฝ
FVector CurrentScale = ItemBody->GetComponentScale();
FVector NewScale = FMath::VInterpTo(CurrentScale, TargetScale, GetWorld()->GetDeltaSeconds(), 2.0f);
ItemBody->SetWorldScale3D(NewScale);
}
ํจ๊ณผ ์ ํ๊ณผ ์ ๋๋ฉ์ด์
ํจ๊ณผ๋ ๊ฐ์ด ๋ณด์๊ฒ ์ต๋๋ค.
์ถฉ๋ํ ์กํฐ๊ฐ 'Player' ํ๊ทธ๋ฅผ ๊ฐ์ง๊ณ ์๋ค๋ฉด ํ์ฌ ํจ๊ณผ์ ๋ฐ๋ผ ๊ฐ ์ ๊ทธ๋ ์ด๋์ ํด๋นํ๋ ํจ์๋ฅผ ์คํํ์ต๋๋ค.
if (OtherActor->ActorHasTag("Player"))
{
AMyPlayer* player = Cast<AMyPlayer>(OtherActor);
if (player)
{
ItemEffect(itemType);
switch (itemType)
{
case EItemType::Damage:
player->PlayerAttack->IncreaseBulletDamage();
break;
case EItemType::Speed:
player->PlayerAttack->IncreaseAttackSpeed();
break;
case EItemType::Count:
player->PlayerAttack->IncreaseBulletCount();
break;
case EItemType::Boom:
player->IncreasePlayerBoomCount();
break;
case EItemType::Hp:
player->IncreasePlayerHp();
break;
default:
break;
}
DestroyItem();
}
}
ํ๋ ์ด์ด๊ฐ ์ด์ ๊ฐ์ ์ฆ๊ฐ ์์ดํ
์ ๋จน๊ณ ์ด์ ๊ฐ์๊ฐ ์ฆ๊ฐํ๋ ๊ฒ์ ์์๋ก ํ์ธํ๊ฒ ์ต๋๋ค.
์์ดํ ์ ์ ์ด ์ฃฝ์ผ๋ฉด์ ์ํํฉ๋๋ค.
์์ดํ ๋๋ ์ฌ๋ถ์ ๋ํ bool ๋ณ์๊ฐ์ Stat ์ค์ ๊ณผ ๋์ผํ๊ฒ true๋ก ์ค์ ํด์ค๋ค๋ฉด ํด๋น ์ ์ ์ฃฝ์ผ๋ฉด์ ์์ดํ ์ ์ํํฉ๋๋ค.
if (isSpawnItemWhenDie)
{
isSpawnItemWhenDie = false;
FTransform spawnTransform = FTransform(FVector::ForwardVector.Rotation(), GetActorLocation(), FVector(2, 2, 2));
GetWorld()->SpawnActor<AItem>(SpawnItem, spawnTransform);
}
์ด ์ธ์๋ ์ฒด๋ ฅ ์ฆ๊ฐ, ํญํ ๊ฐ์ ์ฆ๊ฐ์ ๊ฐ์ ์ ํธ๋ฆฌํฐ ์์ดํ ๋ ๊ตฌํํ์ผ๋ ๋ด์ฉ์ด ๋์ผํ์ฌ ๋์ด ๊ฐ๋๋ก ํ๊ฒ ์ต๋๋ค.
์ฌ๊ธฐ๊น์ง ์์ดํ ์ ๊ดํ ๋ด์ฉ์ ์ ๋ฆฌํ์์ต๋๋ค.