๐ Project Galaga ์์ํฉ๋๋ค.
Unreal C++๊ณผ ๊ฒ์์ํ์ ์ ๋ชฉํด์ ํ๋ก์ ํธ๋ฅผ ์งํํ์ต๋๋ค.
2024.05.04 ~ 2024.05.21์ ๊ฐ๋ฐ ๊ธฐ๊ฐ์ผ๋ก, ์ด 17์ผ ๋์ ๊ฐ๋ฐ์ ์๋ฃํ์์ต๋๋ค.
๊ฑฐ์ฐฝํ๊ฒ ์์ํ ํ๋ก์ ํธ๋ณด๋จ ์ง๊ธ๊น์ง ๋ฐฐ์ด ๊ฒ๋ค์ ์ข ํฉ์ ์ผ๋ก ์ฌ์ฉํด์ ๊ฒฐ๊ณผ๋ฌผ์ ๋ง๋ค์ด ๋ด๋ณด๊ฒ ๋ค๋ ๋ง์์ผ๋ก ์์ฑํ์์ต๋๋ค.
ํด๋น ์๋ฆฌ์ฆ์๋ ๊ฐ๋ฐ ์ผ์ง๋ฅผ ์ ๋ฆฌํ๋ฉฐ, ๊ฐ๋ฐ ๋ด์ฉ์ ๋ํ ์ค๋ช ๊ณผ ์ด์๋ฅผ ์ ๋ฆฌํ ์์ ์ ๋๋ค.
ํ๋ ์ด์ด๋ Pawn Class๋ฅผ ์์ํ์ฌ ๊ฐ๋ฐํ์์ต๋๋ค.
์ฐ์ฃผ์ ์์ ์ Static Mesh๋ง์ ์ ํ๊ณ , ์ ๋๋ฉ์ด์ ์ด ๋ฐ๋ก ํ์์๋ค๊ณ ์๊ฐํ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
ํ๋ ์ด์ด์ ์ธํ์ Collision๋ฅผ ๋ฃจํธ๋ก, Static Mesh๋ฅผ ์์์ผ๋ก ์ฃผ์์ต๋๋ค.
public: // Component
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = PlayerBody, meta = (AllowPrivateAccess = true))
class UStaticMeshComponent* PlayerBody;
UPROPERTY(VisibleAnywhere, Category = PlayerBody)
class USphereComponent* PlayerBodyCollision;
// Sets default values
AMyPlayer::AMyPlayer()
{
// Set this pawn to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
PlayerBodyCollision = CreateDefaultSubobject<USphereComponent>(TEXT("PlayerBodyCollision"));
RootComponent = PlayerBodyCollision;
PlayerBody = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("PlayerBody"));
PlayerBody->SetCollisionEnabled(ECollisionEnabled::NoCollision);
PlayerBody->SetRelativeScale3D(FVector(0.02f, 0.02f, 0.02f));
PlayerBody->SetupAttachment(PlayerBodyCollision);
ConstructorHelpers::FObjectFinder<UStaticMesh>PlayerBodyMesh(TEXT("/Script/Engine.StaticMesh'/Game/spaceship-cb2/source/StaticMesh.StaticMesh'"));
if (PlayerBodyMesh.Succeeded())
{
PlayerBody->SetStaticMesh(PlayerBodyMesh.Object);
}
PlayerBodyCollision->SetCollisionProfileName(TEXT("BlockAll"));
}
ํด๋น ํ๋ก์ ํธ์ ์์ง์์ Old Input System์ ์ฌ์ฉํ์ฌ ๊ตฌํํ์์ต๋๋ค.
์์ง์๊ณผ ๊ณต๊ฒฉ์ผ๋ก ๊ตฌ๋ถํ์ฌ ๊ฐ๊ฐ ์กํฐ ์ปดํฌ๋ํธ๋ฅผ ์ ์ํด ์ถ๊ฐํ์ฌ ์ฃผ์์ต๋๋ค.
void AMyPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
PlayerMove->SetupInputBinding(PlayerInputComponent);
PlayerAttack->SetupInputBinding(PlayerInputComponent);
PlayerInputComponent->BindAction(TEXT("Boom"), IE_Pressed, this, &AMyPlayer::Boom);
PlayerInputComponent->BindAction(TEXT("Pause"), IE_Pressed, this, &AMyPlayer::Pause);
}
ํ๋ ์ด์ด์ ์์ง์์ W, A, S, D 4๊ฐ์ง์ ํค๋ฅผ ์ฌ์ฉํ์ฌ ์ํ์ข์ฐ๋ก ์กฐ์ํฉ๋๋ค.
Axis๊ฐ์ ๋ฐ๋ผ Direction์ผ๋ก ์ด๋๋ฐฉํฅ์ ๊ฒฐ์ ํ ๋ค, ๋ฑ์์ด๋ ๊ณต์์ ์ฌ์ฉํ์ฌ ํ๋ ์ด์ด์ ์ด๋์ ๊ตฌํํ์์ต๋๋ค.
P(๊ฒฐ๊ณผ ์์น) = P0(ํ์ฌ ์์น) + v(์๋) * t(์๊ฐ)
void UPlayerMove::Move(float DeltaTime)
{
FVector P0 = me->GetActorLocation();
FVector vt = DeltaTime * MoveSpeed * Direction;
FVector P = P0 + vt;
me->SetActorLocation(P, true);
Direction = FVector::ZeroVector;
}
ํ๋ ์ด์ด์ ๊ณต๊ฒฉ์ Action์ผ๋ก ๊ฐ์ ๋ฐ์ isAttack์ ์ ํํด ์ฃผ์์ต๋๋ค.
void UPlayerAttack::SetupInputBinding(UInputComponent* PlayerInputComponent)
{
PlayerInputComponent->BindAction(TEXT("Fire"), IE_Pressed, this, &UPlayerAttack::Fire);
PlayerInputComponent->BindAction(TEXT("Fire"), IE_Released, this, &UPlayerAttack::Fire);
}
isAttack์ด ์ฐธ์ผ ๋๋ง AttackSpeedTimer์ Deltatime์ ๋ํ์ฌ ๊ณต๊ฒฉ์๋ ์์คํ ์ ๊ตฌํํ์์ต๋๋ค.
์ด๊ธฐ์๋ Player Bullet์ ์์ฑํด์ฃผ์์ผ๋ ์ถํ ์ค๋ธ์ ํธ ํ๋ง์ ์ฌ์ฉํ์ฌ ๋ฆฌํฉํ ๋งํด์ฃผ์์ต๋๋ค.
์ค๋ธ์ ํธ ํ๋ง์ ๋ํ ๋ด์ฉ์ ์ดํ ํฌ์คํ ์์ ์์ธํ ์ ๊ฒ ์ต๋๋ค.
void UPlayerAttack::FireBullet(float DeltaTime)
{
AttackSpeedTimer += DeltaTime;
if (AttackSpeedTimer >= AttackSpeed)
{
me->FireSound();
//FActorSpawnParameters param;
//param.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
//APlayerBullet* bullet = GetWorld()->SpawnActor<APlayerBullet>(BulletFactory, GetActorLocation(), FRotator::ZeroRotator, param);
me->PlayerBulletPool->SpawnPlayerPooledBullet();
AttackSpeedTimer = 0.0f;
}
}
์ฌ๊ธฐ๊น์ง๊ฐ ๊ฐ๋จํ ์กฐ์๊ตฌํ์ ๋๋ค.
ํญํ, ํ์ด๊ธฐ๋ ๋ค๋ฅธ ์์์ ๊ฒฐํฉํ์ฌ ๋ฐ๋ก ํฌ์คํ ํ๊ฒ ์ต๋๋ค.
์ฌ๊ธฐ๊น์ง ํ๋ ์ด์ด ์กฐ์์ ๋ํ ๊ตฌํ๋ด์ฉ์ด์์ต๋๋ค.