인터페이스(Interface) 클래스는 (잠재적으로) 무관한 클래스 세트가 공통의 함수 세트를 구현할 수 있도록 하는 데 쓰입니다. 그대로라면 유사성이 없었을 크고 복잡한 클래스들에 어떤 게임 함수 기능을 공유시키고자 하는 경우 매우 좋습니다. 예를 들어 트리거 볼륨에 들어서면 함정이 발동되거나, 적에게 경보가 울리거나, 플레이어에게 점수를 주는 시스템을 가진 게임이 있다 칩시다. 함정, 적, 점수에서 ReactToTrigger (트리거에 반응) 함수를 구현하면 될 것입니다. 하지만 함정은 AActor 에서 파생될 수도, 적은 특수 APawn 또는 ACharacter 서브클래스일 수도, 점수는 UDataAsset 일 수도 있습니다. 이 모든 클래스에 공유 함수 기능이 필요하지만, UObject 말고는 공통 조상이 없습니다. 이럴 때 인터페이스를 추천합니다.
docs.unrealengine.com/ko/Programming/UnrealArchitecture/Reference/Interfaces/index.html
언리얼 문서에 적혀있는 인터페이스에 대한 설명이다. 상호참조문제나 virtual 함수들을 구현하고 클래스 단위로 구분하기 위해 사용됩니다.
캐릭터 클래스의 정보를 애님인스턴스 클래스로 인터페이스를 통해 전달해보겠습니다.
1. 삼인칭 프로젝트 생성
InaterfaceCharacter.h
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "InterfaceCharacter.generated.h"
UCLASS(config=Game)
class AInterfaceCharacter : public ACharacter
{
GENERATED_BODY()
...
...
...
// 인터페이스로 전달할 변수
private:
float MaxWalkSpeed;
};
InterfaceCharacter.cpp
// Copyright Epic Games, Inc. All Rights Reserved.
#include "InterfaceCharacter.h"
#include "HeadMountedDisplayFunctionLibrary.h"
#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
#include "Components/InputComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "GameFramework/Controller.h"
#include "GameFramework/SpringArmComponent.h"
//////////////////////////////////////////////////////////////////////////
// AInterfaceCharacter
AInterfaceCharacter::AInterfaceCharacter()
{
...
...
...
// 인터페이스로 전달한 변수
MaxWalkSpeed = 600.0f;
}
ICAnimInstace.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Animation/AnimInstance.h"
#include "ICAnimInstance.generated.h"
/**
*
*/
UCLASS()
class INTERFACE_API UICAnimInstance : public UAnimInstance
{
GENERATED_BODY()
public:
UICAnimInstance();
public:
virtual void NativeUpdateAnimation(float DeltaSeconds) override;
};
ICAnimInstance.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "ICAnimInstance.h"
UICAnimInstance::UICAnimInstance()
{
}
void UICAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
{
Super::NativeUpdateAnimation(DeltaSeconds);
auto Pawn = TryGetPawnOwner();
if (IsValid(Pawn))
{
CurrentCharacterSpeed = Pawn->GetVelocity().Size();
auto Character = Cast<ACharacter>(Pawn);
if (Character)
{
bIsInAir = Character->GetMovementComponent()->IsFalling();
// Interface함수 호출
if (Character->GetClass()->ImplementsInterface(UInterface_PCECharacterInfo::StaticClass()))
{
PCE_LOG_SCREEN_INFO(0, "Run Speed From Interface: %f", IInterface_PCECharacterInfo::Execute_GetCharacterMovementInfo(Character));
}
}
}
}
2. Unreal Interface Class 생성
Interface_CharacterInfo.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "Interface_CharacterInfo.generated.h"
// This class does not need to be modified.
UINTERFACE(MinimalAPI)
class UInterface_CharacterInfo : public UInterface
{
GENERATED_BODY()
};
/**
*
*/
class INTERFACE_API IInterface_CharacterInfo
{
GENERATED_BODY()
// Interface 함수 추가
// 하나의 Interface에 여러 개의 함수를 추가 할 수 있습니다.
public:
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "MaxWalkSpeed")
float GetMaxWalkSpeed();
};
Interface_CharacterInfo.cpp 파일은 수정하지 않습니다.
3. InterfaceCharacter 클래스에 Interface_Character 인터페이스 상속
InterfaceCharacter.h
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "Interface_CharacterInfo.h" // Interface 헤더 파일 추가
#include "InterfaceCharacter.generated.h"
UCLASS(config = Game)
class AInterfaceCharacter : public ACharacter, public IInterface_CharacterInfo // UInterface_CharacterInfo가 아닌 접두사가 'I'인 IInterface_CharacterInfo를 상속해야합니다.
{
GENERATED_BODY()
...
...
...
// 인터페이스로 전달할 변수
private:
float MaxWalkSpeed;
// Interface 함수 구현
// '_Implementation'이 붙은 함수와 붙지 않은 함수를 정의 했습니다.
// cpp 파일에서는 _Implementation이 붙은 함수만 작성합니다.
public:
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "MaxWalkSpeed")
float GetMaxWalkSpeed();
virtual float GetMaxWalkSpeed_Implementation() override;
};
InterfaceCharacter.cpp
// Copyright Epic Games, Inc. All Rights Reserved.
#include "InterfaceCharacter.h"
#include "HeadMountedDisplayFunctionLibrary.h"
#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
#include "Components/InputComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "GameFramework/Controller.h"
#include "GameFramework/SpringArmComponent.h"
//////////////////////////////////////////////////////////////////////////
// AInterfaceCharacter
AInterfaceCharacter::AInterfaceCharacter()
{
...
...
...
MaxWalkSpeed = 600.0f;
}
// Interface 함수 호출시 호출될 함수
float AInterfaceCharacter::GetMaxWalkSpeed_Implementation()
{
return MaxWalkSpeed;
}
4. ICAnimInstance 함수에서 Interface 함수 호출 후 결과 확인
ICAnimInstace.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "ICAnimInstance.h"
#include "Engine/Engine.h" // GEngine을 사용하기 위해서 추가
#include "InterfaceCharacter.h"
UICAnimInstance::UICAnimInstance()
{
}
void UICAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
{
Super::NativeUpdateAnimation(DeltaSeconds);
auto Pawn = TryGetPawnOwner();
if (IsValid(Pawn))
{
auto Character = Cast<ACharacter>(Pawn);
if (Character)
{
// 클래스에 Interface클래스가 존재하는지 확인합니다.
if (Character->GetClass()->ImplementsInterface(UInterface_CharacterInfo::StaticClass()))
{
// 존재한다면 Interface함수를 호출합니다.
// 호출할때는 호출할 Interface함수명 앞에 'Execute_'를 추가합니다.
// 1번 인자: 호출할 클래스, 그 이후의 인자는 정의한 함수의 인자를 입력합니다.
// 이 경우는 정의한 함수의 인자가 없기때문에 1번 인자로 호출할 클래스를 넣었습니다.
// Interface 함수로 받은 정보를 뷰포트 화면에 출력합니다.
GEngine->AddOnScreenDebugMessage(0, 0.0f, FColor::Cyan, FString::Printf(TEXT("Run Speed From Interface: %f"), IInterface_CharacterInfo::Execute_GetMaxWalkSpeed(Character)));
}
}
}
}
InterfaceCharacter 클래스에서 정의한 MaxWalkSpeed 변수의 값이 인터페이스를 통해 ICAnimInstace로 전달되어 정상적으로 출력된 것을 확인하였습니다.
참고자료
jollymonsterstudio.com/2019/05/30/unreal-engine-c-fundamentals-interfaces/
'Unreal Engine > C++' 카테고리의 다른 글
[Unreal Engine 4 C++] class 키워드와 전방선언 (0) | 2020.11.08 |
---|---|
[Unreal Engine 4 C++] 범위 기반 For 루프 (0) | 2020.11.04 |
[Unreal Engine 4 C++] 유효성 검사, nullptr과 IsValid 그리고 Pending Kill (0) | 2020.10.30 |
[Unreal Engine 4 C++] 뷰포트에 텍스트 출력 (0) | 2020.10.15 |
[Unreal Engine 4 C++] 비주얼 스튜디오에서 BreakPoint 사용하기 (2) | 2020.09.07 |