Showing

[Unreal] 클래스 캐스팅 바로 접근시 nullptr 사례 본문

Issue Solving

[Unreal] 클래스 캐스팅 바로 접근시 nullptr 사례

RabbitCode 2024. 1. 18. 15:01

오류 상황

멀티플레이어(Lan 리슨 서버) 게임에서, 총알로 다른 플레이어를 쏠 때 nullptr error가 뜨면서 언리얼 강제 종료

고친 뒤 캡처

 

오류 코드

void ABulletActor::OnOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	// 스폰도 서버가 담당하듯이 지우는 것도 서버가 지워주기
	if (HasAuthority()) {
		if (AMyProjectCharacter* player = Cast<AMyProjectCharacter>(OtherActor)) {
			// 때린(맞은) 아이
			player->Damaged(damage); 
            
            // 플레이어 점수를 10점 올린다
			// 나자신의 오너
			ANetPlayerState* ownerPlayer = Cast<AMyProjectCharacter>(GetOwner())->GetPlayerState<ANetPlayerState>();
			ownerPlayer->SetScore(ownerPlayer->GetScore() + 10);
			UE_LOG(LogTemp, Warning, TEXT("ABulletActor::OnOverlap %d"), damage);
		}
		Destroy();
	}
}
  1. if (AMyProjectCharacter* player = Cast<AMyProjectCharacter>(OtherActor)) 부분:
    • 이 코드는 OtherActor를 AMyProjectCharacter 클래스로 캐스팅하려고 시도하였고 OtherActor가 nullptr일 경우 캐스팅은 실패하며 런타임 오류를 발생시킬 여지가 있다. 하지만 직접적인 원인은 아니었다.
  2. Cast<AMyProjectCharacter>(GetOwner())->GetPlayerState<ANetPlayerState>() 부분:
    • GetOwner() 함수의 결과에서 플레이어스테이트까지 가져오는 경우로 직접적인 원인이었다.

코드 수정

캐릭터에서 바로 플레이어스테이트로 넘어가지 않고, 플레이어가 nullptr이 아닌지 한번 더 검토해주고 playerstate를 받아온다.

void ABulletActor::OnOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	if (!OtherActor)
		return;

	if (HasAuthority()) {
		if (AMyProjectCharacter* player = Cast<AMyProjectCharacter>(OtherActor)) {
			// 때린(맞은) 아이
			player->Damaged(damage);
            
            // 플레이어 점수를 10점 올린다
			// 나자신의 오너
			AMyProjectCharacter* OwnerCharacter = Cast<AMyProjectCharacter>(GetOwner());
			if (OwnerCharacter) {
				ANetPlayerState* ownerPlayer = OwnerCharacter->GetPlayerState<ANetPlayerState>();
				if (ownerPlayer) {
					ownerPlayer->SetScore(ownerPlayer->GetScore() + 10);
				}
			}

			UE_LOG(LogTemp, Warning, TEXT("ABulletActor::OnOverlap %d"), damage);
		}
		// 서버에서만 파괴
		Destroy();
	}
}