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

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

Project Galaga

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

๊ฐœ์š”

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

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

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

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

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

๐Ÿš€ Project Galaga Github Repository


๋ณธ๋ก 

ํ”Œ๋ ˆ์ด์–ด์˜ ์„ฑ๋Šฅ์„ ํ•œ ์ธต ์˜ฌ๋ ค์ค„ ์ˆ˜ ์žˆ๋Š” ์•„์ดํ…œ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์•„์ดํ…œ์— ๊ตฌํ˜„๋œ ๋‚ด์šฉ๋“ค์— ๋Œ€ํ•˜์—ฌ ์ •๋ฆฌํ•˜๋Š” ์‹œ๊ฐ„์„ ๊ฐ€์ง€๊ฒ ์Šต๋‹ˆ๋‹ค.


์•„์ดํ…œ ์›€์ง์ž„

์•„์ดํ…œ๋„ ๋™์ผํ•˜๊ฒŒ ๋“ฑ์†๋„ ์šด๋™ ๊ณต์‹์„ ์‚ฌ์šฉํ•˜์—ฌ ์›€์ง์ด๊ฒŒ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์•„์ดํ…œ์ด ์ญ‰ ์ด๋™ํ•˜๋‹ค๊ฐ€ ๊ฐ€๋กœ ๋ง‰ํ˜€์„œ ๋ฉˆ์ถ”๊ฑฐ๋‚˜, ๋จน์„ ์ˆ˜ ์—†๊ฒŒ ๋งต ๋ฐ–์œผ๋กœ ๋‚˜๊ฐ€๋ฉด ๊ณค๋ž€ํ•˜๊ฒ ์ฃ ?

๊ทธ๋ž˜์„œ ๋ฒฝ์— ๋ถ€๋”ชํžˆ๊ฒŒ ๋œ๋‹ค๋ฉด ํŠ•๊ฒจ ๋‚˜์™€ ๋งต ์•ˆ์—์„œ ๋– ๋Œ๋‹ค ์‚ฌ๋ผ์ง€๋„๋ก ๊ตฌํ˜„ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

Overlap Event

๊ธฐ์กด ๋งต์— ๊ตฌํ˜„ํ•ด์คฌ๋˜ ๋ฒฝ๋“ค์—๊ฒŒ ํƒœ๊ทธ๋ฅผ ๋„ฃ์—ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๊ฐ ๋ฒฝ๋งˆ๋‹ค 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๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  1. ๊ณต๊ฒฉ๋ ฅ ์ฆ๊ฐ€
  2. ๊ณต๊ฒฉ์†๋„ ์ฆ๊ฐ€
  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);
}

์ด ์™ธ์—๋„ ์ฒด๋ ฅ ์ฆ๊ฐ€, ํญํƒ„ ๊ฐœ์ˆ˜ ์ฆ๊ฐ€์™€ ๊ฐ™์€ ์œ ํ‹ธ๋ฆฌํ‹ฐ ์•„์ดํ…œ๋„ ๊ตฌํ˜„ํ–ˆ์œผ๋‚˜ ๋‚ด์šฉ์ด ๋™์ผํ•˜์—ฌ ๋„˜์–ด ๊ฐ€๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.


๋งˆ๋ฌด๋ฆฌ

์—ฌ๊ธฐ๊นŒ์ง€ ์•„์ดํ…œ์— ๊ด€ํ•œ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•˜์˜€์Šต๋‹ˆ๋‹ค.

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

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