언리얼 엔진 5/개발 일지

[UE5] 블루아카이브 TPS게임 개발일지 (30) - 리팩토링 (블루프린트 -> C++)

ciel45 2024. 1. 6. 18:42

게임을 기껏 C++ 프로젝트로 만들어놓고 최근 너무 블루프린트로만 기능을 만든 것 같다.

 

그래서 오늘은 몇가지 기능을 C++ 코드로 옮겼다.

 

 

먼저 BP_Enemy의 NoticePlayer, AwarePlayer 이벤트는 각각 플레이어를 목격했을 때, 플레이어의 위치를 인지했을 때 호출되는 이벤트이다.

 

지금은 이동속도 증가 기능뿐이지만, 추후 새로운 기능이 추가될 수 있다.

 

이 두 이벤트를 C++로 옮기되, 이 이벤트에 종속적이던 다른 에셋에는 영향이 없도록 BlueprintCallable 지정자를 사용했다.

//Enemy.h
UFUNCTION(BlueprintCallable)
void NoticePlayer();

UFUNCTION(BlueprintCallable)
void AwarePlayer();

 

void AEnemy::NoticePlayer()
{
	//이동속도 증가
	GetCharacterMovement()->MaxWalkSpeed = 600.f;
}

void AEnemy::AwarePlayer()
{
	//이동속도 증가
	GetCharacterMovement()->MaxWalkSpeed = 600.f;
}

 

 

 

그리고 원래 애니메이션 블루프린트 ABP_Enemy에서 IsCrouching 변수를 선언하고 업데이트시켰는데, 이제 블루프린트가 아닌 C++에서 선언하고 업데이트하도록 하였다.

기존 노드

//ABP_Enemy의 부모클래스 UEnemyAnimInstance

void UEnemyAnimInstance::NativeUpdateAnimation(float DeltaTime)
{
	Super::NativeUpdateAnimation(DeltaTime);

	if (EnemyCharacterMovement)
	{
		GroundSpeed = UKismetMathLibrary::VSizeXY(EnemyCharacterMovement->Velocity);
		IsCrouching = EnemyCharacterMovement->IsCrouching(); 
        //IsCrouching 변수는  헤더에 정의되어있음
	}
}

 

 

그리고 블루프린트로만 만든 투사체 BP_Projectile은 부모클래스로 새로 만든 Projectile C++ 클래스를 가지도록 하였다.

//Projectile.h, 상단 생략

UCLASS()
class KANNATPS_API AProjectile : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	AProjectile();

	// Called every frame
	virtual void Tick(float DeltaTime) override;

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

	UFUNCTION()
	void Damage(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit);

	UPROPERTY(EditDefaultsOnly)
	UStaticMeshComponent* Projectile;

	UPROPERTY(EditDefaultsOnly)
	UProjectileMovementComponent* ProjectileMovement;
private:	

};
//Projectile.cpp, 상단 생략

// Sets default values
AProjectile::AProjectile()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = false;

	Projectile = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Projectile"));
	SetRootComponent(Projectile);

	ProjectileMovement = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("ProjectileMovement"));
	ProjectileMovement->InitialSpeed = 6000.f;
	ProjectileMovement->MaxSpeed = 6000.f;
	ProjectileMovement->ProjectileGravityScale = 0.f;
}

// Called when the game starts or when spawned
void AProjectile::BeginPlay()
{
	Super::BeginPlay();
	
	Projectile->OnComponentHit.AddDynamic(this, &AProjectile::Damage);

	SetLifeSpan(2.f); //스폰되고 2초 후에 사라짐
}

void AProjectile::Damage(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
{
	//맞은 액터가 칸나였을 경우
	if (Cast<AKannaCharacter>(OtherActor))
	{
		UE_LOG(LogTemp, Warning, TEXT("플레이어 피격!"));
	}

	Destroy();
}

BP_Projectile의 Class Setting에서 부모클래스를 Projectile로 변경

 

 

그리고 플레이어 사격 소음 기능(적이 인지하기 위한 것)을 원래 애니메이션 블루프린트 ABP_Kanna 내부에서 애니메이션 Notify로 구현했는데,

직관성을 위해 Pistol.cpp의 Fire함수 마지막에서 C++ 코드를 통해 수행하도록 하였다.

void APistol::Fire(FVector& StartPoint, FVector& Direction)
{
	FHitResult HitResult;
	FVector EndPoint = StartPoint + Direction * Range;

	if (GetWorld())
	{
		if (GetWorld()->LineTraceSingleByChannel(
			HitResult,
			StartPoint,
			EndPoint,
			ECollisionChannel::ECC_Visibility))
		{
			if (HitResult.GetActor())
			{
				if (IHitInterface* HitObject = Cast<IHitInterface>(HitResult.GetActor()))
				{
					HitObject->GetHit();
				}

				UGameplayStatics::ApplyPointDamage(
					HitResult.GetActor(),
					Damage,
					Direction,
					HitResult,
					GetInstigator()->GetController(),
					this,
					UDamageType::StaticClass()
				);
			}
		}
	}

	//총구 화염 효과
	MuzzleFlashEffect();

	//소음 효과
	UAISense_Hearing::ReportNoiseEvent(
		GetWorld(),
		GetActorLocation(),
		1.f,
		UGameplayStatics::GetPlayerPawn(GetWorld(), 0),
		6000.f
	);
}

 

이 외에도 자잘한 정리를 하였다.

 

 

 

사실 블루프린트 비중이 제일 높은 부분은 비헤이비어 트리, EQS 등 AI 관련 기능을 사용하는 부분인데, 

이 부분들은 조금 더 확실히 공부를 한 다음에 만져보려고 한다.