유데미 Sam Pattuzzi 의 언리얼 강좌를 수강하면서 3인칭 슈팅 게임을 만들어보면서 공부하기로 했다.
장르는 3인칭 슈팅게임.
매 판마다 웨이브가 존재하고 웨이브마다 몰려오는 적들을 타파하면 돈과 경험치를 얻고 강해져서
점점 높은 웨이브로 올라가는 게임으로 기획해보았다.
이동 구현
void APlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
// PC
// Keyboard Movement
PlayerInputComponent->BindAxis(TEXT("MoveVertical"), this, &APlayerCharacter::MoveVertical);
PlayerInputComponent->BindAxis(TEXT("MoveHorizontal"), this, &APlayerCharacter::MoveHorizontal);
// Keyboard Jump
PlayerInputComponent->BindAction(TEXT("Jump"), EInputEvent::IE_Pressed, this, &ACharacter::Jump);
// Keyboard Shoot
PlayerInputComponent->BindAction(TEXT("Shoot"), EInputEvent::IE_Pressed, this, &APlayerCharacter::Shoot);
PlayerInputComponent->BindAction(TEXT("Shoot"), EInputEvent::IE_Released, this, &APlayerCharacter::Release);
// Keyboard Aim
PlayerInputComponent->BindAction(TEXT("Aim"), EInputEvent::IE_Pressed, this, &APlayerCharacter::Aim);
PlayerInputComponent->BindAction(TEXT("Aim"), EInputEvent::IE_Released, this, &APlayerCharacter::Aim);
// Mouse Camera Control
PlayerInputComponent->BindAxis(TEXT("LookVertical"), this, &APawn::AddControllerPitchInput);
PlayerInputComponent->BindAxis(TEXT("LookHorizontal"), this, &APawn::AddControllerYawInput);
// Controller
// Gamepad Camera Control
PlayerInputComponent->BindAxis(TEXT("LookVerticalRate"), this, &APlayerCharacter::LookVerticalRate);
PlayerInputComponent->BindAxis(TEXT("LookHorizontalRate"), this, &APlayerCharacter::LookHorizontalRate);
}
언리얼에서는 왠지 한글 주석 달기가 싫어서 영어로 주석을 달게 되었다. 문법은 맞는지 모른다.
강의에서 배운대로 에디터의 Project Setting - Input 에서 Axis, Action 별로 각각 키를 지정해주고
C++ 스크립트에서 키에 따른 함수를 Bind 시켜주었다.
종류는 키보드 조작 / 게임 패드 조작 / 마우스 조작 이렇게 세 가지를 넣었다.
강의에서는 EInputEvent::IE_Pressed 만 다루는데 키를 땔 때 입력을 얻고 싶어 IE_Released 를 사용했다.
다음은 바인딩 시켜준 함수들이다.
// Move Forward & Backward
void APlayerCharacter::MoveVertical(float AxisValue)
{
AddMovementInput(GetActorForwardVector() * AxisValue);
}
// Move Right & Left
void APlayerCharacter::MoveHorizontal(float AxisValue)
{
AddMovementInput(GetActorRightVector() * AxisValue);
}
// Gamepad Camera Control
void APlayerCharacter::LookVerticalRate(float AxisValue)
{
AddControllerPitchInput(AxisValue * controllerRotationRate * GetWorld()->GetDeltaSeconds());
}
void APlayerCharacter::LookHorizontalRate(float AxisValue)
{
AddControllerYawInput(AxisValue * controllerRotationRate * GetWorld()->GetDeltaSeconds());
}
MoveVertical 은 앞 뒤 움직임, MoveHorizontal 은 좌 우 움직임이다.
아래 Look함수들은 게임패드로 카메라 시점 조작하는 함수인데, 따로 패드가 없어서 테스트는 못해봤지만, 강의에서는
정상작동하는 모습을 보여줬기에 동일할 것이다.
사격 구현
// Attack with pistol
void APlayerCharacter::Shoot()
{
if(IsAiming) // Aiming == true then
{
if(CanShoot)
{
IsShoot = true;
Gun->PullTrigger();
UE_LOG(LogTemp, Warning, TEXT("One Shot"));
CanShoot = false;
}
}
else IsShoot = false;
}
void APlayerCharacter::Release()
{
IsShoot = false;
}
마우스 좌클릭에 바인딩 된 Shoot 함수가 호출되면,
첫 If문에서 "조준 중인지?" 를 판단한다. 게임 기획 상 마우스 우클릭으로 조준을 해야만 사격 가능하게 했기 때문에
넣어준 변수이다.
조준 중이 맞다면, 두 번째 If문에서 "사격이 가능한 상태인지?" 를 체크한다.
사격이 가능하다면 IsShoot 이라는 사격 여부 판단 변수에 true를 주고, 이 부분이 추후에 사격 애니메이션 재생에 쓰였으나 사격부분 애니메이션을 Blueprint가 아닌 C++ 코드로 하게 되어서 IsShoot 변수는 제거했다.(22.06.28)
Gun 이라는 총 스크립트의 PullTrigger() 함수를 실행시킨다. PullTrigger 내부에 총알 발사와 관련 코드가 있다.
그리고 연사를 방지하기 위해 CanShoot을 false로 변경한다.
Release 함수는 마우스 좌클릭을 땔 때 호출되면서, 사격했는지? 에 대한 변수를 false로 만들어준다.
IsShoot은 굳이 없어도 되는 변수같지만, 애니메이션 블루프린트 쪽에서 이 변수로 활용을 한 부분이 있어서
혹시나 이 글을 보고 따라하는 사람이 있다면 참고만 하면 될 것 같다.
발사 시간 타이머
void APlayerCharacter::CheckFireRate()
{
FireTimer = FireTimer - 0.2f;
if(FireTimer <= 0)
{
ResetFireRate();
CanShoot = true;
}
}
void APlayerCharacter::ResetFireRate()
{
FireTimer = 1.2f;
}
가장 애를 먹었던 부분이다..
게임 설계 상 권총이 무기라 한발 씩 쏘고 싶은데 그러려면 마우스입력에 Lock을 걸어주어야 했다.
유니티였다면 임의의 float Timer를 설정하고 Time.DeltaTime 을 더해주면서 타이머를 만들었겠지만,
언리얼에서는 정보를 몰라서 유니티 처럼 시도했다가 낭패를 보았다.
void APlayerCharacter::BeginPlay()
{
Super::BeginPlay();
FireTimer = 0;
GetWorldTimerManager().SetTimer(Handle, this, &APlayerCharacter::CheckFireRate, 0.2f, true);
}
GetWorldTimerManager() 이하 코드로 타이머를 설정해줄 수 있었다.
안에 매개변수로는
FTimerHandle Handle;
FTimerHandle 형태의 Handle이라는 이름으로 변수 하나 설정해주고
두 번째 인자로는 this
세 번째 인자로는 "내가 타이머 동안에 호출할 함수" 를 넣어준다. 중요한 건 앞에 '&' 연산자를 붙여주기
네 번째 인자로는 0.2를 주었는데 "얼마에 한번씩 세번째 인자로 준 함수를 호출할 건지?" 를 정해주는 곳이다.
다섯 번째는 true를 주면된다.
여섯 번째는 언제 소멸될 건지? 인거 같던데 안써도 무방하다.
암튼 BeginPlay() 에서 저렇게 타이머를 세팅해주고 CheckFireRate 함수를 만들어주고 원하는 동작을 넣어주면
정한 시간마다 타이머가 호출되면서 CheckFireRate 함수를 실행한다.
'언리얼5 & C++' 카테고리의 다른 글
[Unreal 5, C++] 캐릭터 사망 & 애니메이션 : C++ 변수, 함수를 블루프린트에서 사용하기 (0) | 2022.06.28 |
---|---|
[Unreal 5, Blueprint & C++] 캐릭터 점프 구현과 오류 해결 Animation Transition (0) | 2022.06.28 |
[Unreal 5, C++] 언리얼5 C++ 로그 찍는법 (0) | 2022.06.18 |
[Unreal 5, C++] 언리얼 C++에서 변수를 에디터에 보이게 하는법 / C++ 변수 블루프린트에서 호출하기 : UPROPERTY, UFUNCTION (2) | 2022.06.18 |
[Unreal, C++] 3인칭 슈팅게임 연습 일지 - 2 : 사격, 이펙트 구현 (0) | 2022.06.18 |