저번에 했던 Shoot 함수 안에는 PullTrigger()함수가 있었다.
이번에는 이 함수에 대해 적어볼 것이다.
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;
}
Gun 은 헤더 파일에서 무기 클래스를 Gun이라는 이름으로 선언한 것이다.
APistol_Gun* Gun;
Pistol_Gun.cpp 에 PullTrigger에 대한 내용이 있다. (앞에 A는 Actor를 의미하며 모든 액터류에는 다 A가 자동으로 붙는다)
발사 구현 코드 전체
void APistol_Gun::PullTrigger()
{
UE_LOG(LogTemp, Warning, TEXT("In Pulltrigger"));
UGameplayStatics::SpawnEmitterAttached(MuzzleFlash, Mesh, TEXT("Muzzle"));
APawn* OwnerPawn = Cast<APawn>(GetOwner());
if(OwnerPawn == nullptr) return;
AController* OwnerController = OwnerPawn->GetController();
if(OwnerController == nullptr) return;
FVector Location;
FRotator Rotation;
OwnerController->GetPlayerViewPoint(Location, Rotation);
FVector End = Location + Rotation.Vector() * MaxRange;
FHitResult Hit;
bool Success = GetWorld()->LineTraceSingleByChannel(Hit, Location, End, ECollisionChannel::ECC_GameTraceChannel1);
if(Success)
{
FVector AimDirection = -Rotation.Vector();
UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), Impact, Hit.Location, AimDirection.Rotation());
//DrawDebugPoint(GetWorld(), Hit.Location, 20, FColor::Red, true);
AActor* HitActor = Hit.GetActor();
if(HitActor != nullptr)
{
FPointDamageEvent DamageEvent(PrimaryDamage, Hit, AimDirection, nullptr);
HitActor->TakeDamage(PrimaryDamage, DamageEvent, OwnerController, this);
}
}
}
일단 전체를 보고,
위에서 부터 천천히 보겠다!
총 발사 이펙트 / 총의 주인 찾기
//UE_LOG(LogTemp, Warning, TEXT("In Pulltrigger"));
UGameplayStatics::SpawnEmitterAttached(MuzzleFlash, Mesh, TEXT("Muzzle"));
APawn* OwnerPawn = Cast<APawn>(GetOwner());
if(OwnerPawn == nullptr) return;
AController* OwnerController = OwnerPawn->GetController();
if(OwnerController == nullptr) return;
UGameplayStatics::SpawnEmitterAttached(붙일 이펙트, 붙일 대상, 붙일 소켓의 이름)
함수를 사용해서 총구에서 생길 이펙트를 총의 Mesh에 Muzzle이라는 이름을 가진 뼈대 소켓에 붙일 수 있다.
유니티에서 이펙트 GameObject를 Instaniate()를 통해 생성하는것과 비슷해 보인다.
그 후, Pawn변수에 이 총을 들고있는 Owner 를 찾아서 넣어줄 것이다. 이 스크립트는 총 스크립트이고, 총을 들고 있는 부모 액터 즉, 플레이어를 찾아내는 과정이다.
+ 예외 처리를 위해 if문을 통해 변수에 nullptr 아무것도 들어가지 않았으면 안전하게 함수를 종료하는 처리를 해준다.
그 다음, 컨트롤러 변수를 만들고 아까 얻어낸 플레이어 에게서 Getcontroller 를 가져온다.
시점 찾기
FVector Location;
FRotator Rotation;
OwnerController->GetPlayerViewPoint(Location, Rotation);
FVector End = Location + Rotation.Vector() * MaxRange;
이제 벡터와 회전을 담을 변수를 각각 정해주고,
아까 구한 컨트롤러에게서 플레이어의 시점 즉, 카메라가 바라보는 위치와 회전을 가져온다.
Vector End 에 그 위치에 + 바라보는 방향 * 사거리 를 대입한다. 여기서 사거리는 총의 사거리를 말한다.
다시 정리하면, 카메라가 보는 시점으로부터 총의 사거리만큼 쭉 선을 긋는 과정이라 생각하면 된다.
라인 트레이싱 / 피격 판정
FHitResult Hit;
bool Success = GetWorld()->LineTraceSingleByChannel(Hit, Location, End, ECollisionChannel::ECC_GameTraceChannel1);
if(Success)
{
FVector AimDirection = -Rotation.Vector();
UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), Impact, Hit.Location, AimDirection.Rotation());
//DrawDebugPoint(GetWorld(), Hit.Location, 20, FColor::Red, true);
AActor* HitActor = Hit.GetActor();
if(HitActor != nullptr)
{
FPointDamageEvent DamageEvent(PrimaryDamage, Hit, AimDirection, nullptr);
HitActor->TakeDamage(PrimaryDamage, DamageEvent, OwnerController, this);
}
}
맞은 곳의 정보를 담을 Hit변수를 FHitResult 형태로 선언한다.
bool 변수인 Success 는 "맞았는지?" 를 의미한다.
GetWorld()->LineTraceSingleByChannel(맞은 곳 저장할 변수, 아까 정한 카메라 위치(시작점), 아까 계산한 도착지점, 충돌채널)
함수를 통해 직선 광선을 쏴서 총알이 피격되는 곳을 얻어낼 수 있다.
이제 총이 맞은 위치에 탄흔 이펙트를 생성할 것이다.
UGameplayStatics::SpawnEmitterAtLocation(월드, 붙일 이펙트, 맞은 위치, 이펙트의 회전값) 함수를 통해 할 수 있다.
AimDirection 에 마이너스 값을 주는 이유는,
총이 나간 방향의 반대방향으로 이펙트가 튀어야 하기 때문이다.
쉽게말하면 총알 맞은 방향의 정반대로 파편이 튀어야 하기 때문인데, 마이너스로 안하면 아마 이펙트가 총알 방향이랑 똑같이 생성 될 거라 어색하거나, 이펙트가 벽 안쪽에 파묻힐 것이다.
그 뒤에 코드는 맞은 액터의 Actor를 가져와서 그 Actor에게 데미지를 주는 DamageEvent를 실행하는 과정이다.
이렇게 하면 카메라 시점대로 화면 중앙으로 LineTracing을 하고 맞은 위치에 이펙트까지 생성할 수 있다.
'언리얼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 5, C++] 3인칭 슈팅 게임 연습 일지 - 1 : 타이머 사용법, 이동, 사격 (0) | 2022.06.18 |