인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

작성자 없음

작성자 정보가 삭제된 글입니다.

이득우의 언리얼 프로그래밍 Part2 - 언리얼 게임 프레임웍의 이해

강의 외 질문입니다.

작성

·

56

0

제가 현재 NPC가 플레이어가 공격 범위 내에 없으면 쫓아오게 하였습니다. 이때 NPC에서 공격범위의 값을 바꾸고 싶어서 UPROPERTY로 변수를 선언을 하였습니다.

커스텀 데코레이터에서 공격범위 값을 가져오기 위해 Interface를 만들어서 캐스팅을 해주었습니다.
하지만 플레이를 해보면 Interface가 없다고 나옵니다. 뭐가 잘못된 것일까요..?

 

class LIFEOFLUCK_API IOLNPCInterface
{
	GENERATED_BODY()

	// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
	virtual float AttackRange() = 0;
};
#include "CoreMinimal.h"
#include "Character/OLCharacterBase.h"
#include "Interface/OLNPCInterface.h"
#include "OLNPCBasic.generated.h"

UCLASS()
class LIFEOFLUCK_API AOLNPCBasic : public AOLCharacterBase, public IOLNPCInterface
{
...
	
protected:
	virtual float AttackRange() override;

	UPROPERTY(EditAnywhere, Category = "AttackRange")
	float AttackRangeValue = 160;	// 공격 범위 값
};
float AOLNPCBasic::AttackRange()
{
	return AttackRangeValue;
}
#include "AI/BTDecorator_AttackRange.h"
#include "AIController.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "Interface/OLNPCInterface.h"

DEFINE_LOG_CATEGORY(Not);

UBTDecorator_AttackRange::UBTDecorator_AttackRange()
{
}

bool UBTDecorator_AttackRange::CalculateRawConditionValue(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) const
{
	Super::CalculateRawConditionValue(OwnerComp, NodeMemory);

	APawn* NPC = OwnerComp.GetAIOwner()->GetPawn();
	if (NPC == nullptr)
	{
		UE_LOG(Not, Error, TEXT("No NPC"));
		return false;
	}

	FName PlayerName = TEXT("Target");
	APawn* Player = Cast<APawn>(OwnerComp.GetBlackboardComponent()->GetValueAsObject(PlayerName));	// 타겟인 플레이어 가져오기(캐스팅하기)
	if (Player == nullptr)
	{
		UE_LOG(Not, Error, TEXT("No Target"));
		return false;
	}

	IOLNPCInterface* NPCInterface = Cast<IOLNPCInterface>(NPC);	// NPC가 인터페이스를 생성한 경우 캐스팅이 됨
	if (NPCInterface)
	{
		UE_LOG(Not, Error, TEXT("No NPCInterface"));
		return false;
	}

	float Distance = FVector::Dist(NPC->GetActorLocation(), Player->GetActorLocation());	// NPC와 플레이어 사이의 거리 구하기
	float AttackRange = NPCInterface->AttackRange();
	bool AttackRangeResult = Distance <= AttackRange;

	UE_LOG(LogTemp, Display, TEXT("Distance: %f"), Distance);
	UE_LOG(LogTemp, Display, TEXT("AttackRange: %s"), AttackRangeResult ? TEXT("True") : TEXT("False"));

	return AttackRangeResult;
}

답변 3

1

이득우님의 프로필 이미지
이득우
지식공유자

가능하면 인터페이스는 언리얼 엔진이 제안하는 방식으로 만드는 것을 권장합니다.
블루프린트까지의 확장을 감안하면 그 방식이 좋습니다.

ajkdfj님의 프로필 이미지

답해주셔서 감사합니다!

언리얼 엔진 문서에서 읽어보니 인터페이스에서 함수를 선언할 때 순수가상함수로 선언을 하지 않았는데 언리얼 엔진 문서와 동일하게 작성을 해야 하는 건가요?

아님 강의에서 배운 것도 언리얼 엔진에서 제안하는 방식인 건가요?

ajkdfj님의 프로필 이미지

그리고 제가 아래와 같이 NPC에서 정의를 하여 리턴값으로 넣어주었는데 이렇게 해도 되는 건가요..?

UPROPERTY(EditAnywhere, Category = "AttackRange")
float AttackRangeValue = 160; // 공격 범위 값

 

이득우님의 프로필 이미지
이득우
지식공유자

헤더에서 초기화하는걸 의미하는 걸까요? 리턴값이라고 하니 혼동되네요.
기본값을 지정해도 좋지만 가급적 생성자에서 설정해주는게 좋습니다.

ajkdfj님의 프로필 이미지

네 헤더에서 초기화하는 걸 말한 것입니다.

그리고 언리얼 엔진이 제안하는 방식으로 만드는 것을 권장한다는 게 언리얼 엔진 문서에 나와있는 걸 말씀하시는 건가요?

이득우님의 프로필 이미지
이득우
지식공유자

네 언리얼 엔진에서 인터페이스의 경우 강의에서 제시한대로 엔진 에디터의 [툴 > 새로운 C++ 클래스] 메뉴를 통해 별도의 파일로 생성하는 것을 권장합니다. 내부 관리를 위해 두 개의 클래스가 생성됩니다.

헤더파일 초기화도 차후 관리적인 측면에서 가급적 생성자에서 진행함으로 통일하시는 것이 좋을 것 같아요.

ajkdfj님의 프로필 이미지

아하 그렇군요. 답해주셔서 감사합니다!

0

ajkdfj님의 프로필 이미지

해결을 했습니다! 제가 착각하고 interface == nullptr을 했어야 하는데 nullptr을 빼먹고 안 적어서

인터페이스가 존재할 때 false가 되어서 이상하게 작동을 한 거였습니다.

0

인프런 AI 인턴님의 프로필 이미지

안녕하세요, 인프런 AI 인턴입니다. ajkdfj님.

NPC가 인터페이스를 통해 공격 범위 값을 가져오는 과정에서 문제가 발생한 것으로 보입니다. 주어진 코드와 설명에서 몇 가지 점을 확인해보겠습니다.

  1. 인터페이스 구현 확인:

    • 현재 AOLNPCBasic 클래스가 IOLNPCInterface를 구현하는 것으로 보이지만, 인터페이스의 함수 AttackRange()를 정상적으로 오버라이드하고 있는지 확인이 필요합니다.
    • 인터페이스 메서드 구현을 확인했지만, 꼭 UObject를 상속받은 클래스에서만 인터페이스를 제대로 사용할 수 있습니다. Cast<IOLNPCInterface>(NPC)의 형태로 캐스팅되는지 확인해야 합니다. 일반적으로 인터페이스의 메서드를 직접 호출할 수 없을 수도 있습니다. 인터페이스를 배우는 것이 아닌 UINTERFACE 키워드로 인터페이스를 선언해야 합니다.
  2. 캐스팅 문제:

    • Cast<IOLNPCInterface>(NPC); 부분에서 제대로 캐스팅이 이뤄지지 않는 경우, NPC가 정말 AOLNPCBasic 타입으로 생성된 것인지 확인이 필요합니다.
    • 만약 인터페이스가 제대로 구현되지 않았다면, Cast가 null을 반환하게 됩니다.
  3. 로그 확인:

    • UE_LOG(Not, Error, TEXT("No NPCInterface")); 로그가 거짓으로 나올 경우, 이는 Cast가 실패했음을 의미합니다. 이 경우 Cast의 결과를 null 체크하여 문제를 추적해야 합니다.
  4. 인터페이스 규칙 확인:

    • Unreal Engine에서 인터페이스를 선언할 때는 통상적으로 UInterface로 선언하기 때문에 IOLNPCInterface가 일반 클래스를 상속받는 것인지, 언리얼 엔진의 인터페이스 구조를 제대로 활용하고 있는지 확인해볼 필요가 있습니다.
  5. 인터페이스 초기화 누락:

    • 만약 AOLNPCBasic의 인스턴스가 생성될 때 IOLNPCInterface와 연결되지 않았다면, 메서드 호출이 불가능할 수도 있습니다.

아래는 관련된 다른 질문 답변 링크입니다:
- Unreal 인터페이스 사용 시 발생하는 일반적인 문제
- 인터페이스의 올바른 구현 방법과 적용 사례

위의 점검 사항들을 확인한 후에도 해결되지 않는다면 실질적으로 인터페이스 구현과 사용이 맞는지를 다시 한번 점검해 보실 것을 권장드립니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

작성자 없음

작성자 정보가 삭제된 글입니다.

질문하기