목표 : 언리얼이 제공하는 인터페이스 기능 실습.
인터페이스 기능을 제공하지 않는 C++과 달리, 언리얼은 자체적으로 인터페이스 기능을 제공한다.
이런 인터페이스의 사용법을 실습해본다.
툴 - 새로운 C++ 클래스 - (맨 아래) 언리얼 인터페이스를 통해 인터페이스를 생성할 수 있다.
BurnableInterface
라는 이름으로 '태울 수 있는' 액터를 만들려 한다.
인터페이스를 생성하면 U
가 붙은 클래스와 I
가 붙은 클래스 생성된다. U
쪽은 건드리지 말고, I
쪽에서 필요한 함수를 구현하면 된다.
블루프린트 쪽에서 이 함수를 구현하기 위해 UFUNCTION 매크로에 BlueprintImplementableEvent
키워드를 붙였다.
이 인터페이스를 원하는 클래스에서 구현하기 위해서는 다음과 같이 I
가 붙은 인터페이스 이름을 상속하면 된다.
블루프린트에선 블루프린트 인터페이스
를 택해 인터페이스를 생성할 수 있다.
원하는 블루프린트의 클래스 세팅
탭의 디테일 패널에서 인터페이스를 다음과 같이 구현할 인터페이스를 추가한다. C++로 만든 인터페이스도 선택할 수 있다.
블루프린트의 함수 오버라이드, 혹은 인터페이스 탭에서 원하는 함수를 택하여 인터페이스 함수를 구현한다. 여기서는 기본 폰 캐릭터를 사용했다.
다음과 같이Burn
함수 실행시 불타는 이펙트가 실행되게 구현하였다.
테스트를 위해 인터페이스를 구현한 또 다른 액터와,
안에 들어간 액터의 Burn
을 호출하는 Burning Zone
을 만들었다.
플레이를 시작하고 두 액터를 Burning Zone
에 넣으면 두 액터가 구현한 각각의 Burn
함수가 호출된다.
서로 다른 클래스여도 인터페이스를 구현하였다면 구현한 인터페이스를 통해 로직을 실행할 수 있다.
만약 인터페이스를 사용하지 않고 이를 구현하고자 했다면
1) Burn
을 실행하기 위해선Burn
을 구현한 모든 클래스를 고려해야 되거나,
2) 대상이 되는 모든 클래스가 Burn
을 구현한 클래스의 자식 클래스여야 했을 것이다.
이것이 인터페이스를 쓰는 의의라고 할 수 있다.
UFUNCTION
매크로 없이 인터페이스에서 함수를 선언하고 이를 구현하지 않고 다른 클래스에서 구현하려고 하면 에러가 난다.
virtual void function() = 0;
같이 = 0
을 붙여 순수 추상 함수로 만들어야 한다.
인터페이스에서 같은 인터페이스의 포인터 객체를 파라미터로 갖는 함수를 선언한 후, 다른 클래스에서 이를 구현하려 하면 다음과 같은 에러가 뜬다.
warning C4263: 'void ABossFightTestCharacter::FireSpread_Implementation(IBurnableInterface *)': 멤버 함수가 기본 클래스 가상 멤버 함수를 재정의하지 않습니다.
warning C4264: 'void IBurnableInterface::FireSpread_Implementation(const TScriptInterface<IBurnableInterface> &)': 기본 'IBurnableInterface'의 가상 멤버 함수에 대해 재정의를 사용할 수 없습니다. 함수가 숨겨집니다.
'IBurnableInterface::FireSpread_Implementation' 선언을 참조하십시오.
로그를 읽어보면 원본의 함수는 IBurnableInterface *
이 아닌 const TScriptInterface<IBurnableInterface> &
를 파라미터로 갖는 것을 알 수 있다.
그래서 파라미터를 고치면 에러없이 컴파일된다. TScriptInterface
는 언리얼이 제공하는 객체인데, 인터페이스 포인터처럼 사용할 수 있다. 내부적으로 TScriptInterface
와 const 참조를 사용하게 바뀌는 듯 한데 공부가 얕아서 아직 잘 모르겠다.