介绍Unreal Engine 4中的接口(Interface)使用C++和蓝图
这个教程是从UE4 Wiki上整理而来.
在C++中直接使用Interface大家应该很熟悉。只是简单先定义一个个有虚函数的基类,然后在子类中实现相应的虚函数。像这样的虚函数的基类一般概念上叫接口。那接下来看看UE4中怎样在C++中定义接口的。
.h
#pragma once
#include "TargetInterface.generated.h"
UINTERFACE(MinimalAPI)
class UTargetInterface :
public UInterface
{
GENERATED_UINTERFACE_BODY()
}; class ITargetInterface{
GENERATED_IINTERFACE_BODY()
public:
UFUNCTION(BlueprintImplementableEvent, meta=(FriendlyName = "On Interact"))
void OnInteract(bool bNewOpen);
virtual float GetHealth(); };
.cpp
#include "YourProject.h"
#include "TargetInterface.h" UTargetInterface::UTargetInterface(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
}
// Give GetHealth a default implementation
float ITargetInterface::GetHealth(){
    return 0.0f;
}
首先定义一个UTargetInterface这个是给引擎内部模块用的,一般不会用到,但是要定义。
ITargetInterface是你要使用的类,你要声明的函数接口都放在这里面。如果是定义函数给C++用的,那么你就直接按标准的C++声明一个虚函数就OK了,然后你要实现这个接口的子类继承ITargetInterface实现GetHealth函数就可以了。如果是给Blueprint用的,就要在函数前一行声明的UFUNCTION内加上BlueprintImplementableEvent,这样蓝图就可以实现这个接口了,蓝图中就像普通事件一样实现。
.h
#pragma once #include "GameFramework/Actor.h"
#include "TargetInterface.h"
#include "NPCActor.generated.h" UCLASS()
class MMWORLD_API NPCActor
: public AActor
, public ITargetInterface
{
    GENERATED_BODY()
public:
    AInteractiveTargetActor();
virtual float GetHealth() override;
protected:
float Health;
};
.cpp
#include "YourProject.h"
#include "NPCActor.h" NPCActor::NPCActor()
{
Health = 100.0f;
} float NPCActor::GetHealth()
{
return Health;
}
在C++代码中这样调用.如果是你知道Actor类的实际类型,直接调用就可以了。你不知道Actor的类型时候Interface才有实际的用处。
auto MyInterface = Cast<ITargetInterface>(ActorInstance);
if (MyInterface)
{
float ActorHealth = MyInterface->GetHealth();
}
但是这样的接口蓝图中是无法使用的,蓝图完全无法知道它的存在。你可以再用Blueprint Function Library的方式再包装一层,但是我觉得这不是很好。
在蓝图中实现Event接口:
之前的NPCActor因为已经继承了ITargetInterface所以,你在蓝图编辑器里可以直接实现OnInteract接口事件。
那如果你纯蓝图的Actor怎么办。
进入蓝图编辑点Class Settings

在Interfaces面板点Add加入Target Interface就好了

那怎调用这个蓝图实现的接口在C++里?
看下面的代码
if (ActorInstance->GetClass()->ImplementsInterface(ITargetInterface::StaticClass()))
{
ITargetInterface::Execute_OnInteract(ActorInstance, true);
}
ActorInstance->GetClass()->ImplementsInterface(ITargetInterface::StaticClass())) 是用来判断这个Actor是否实现了TargetInterface,不管是在蓝图还是C++中都可以正确的判断(但是只有BlueprintImplementableEvent和BlueprintNativeEvent(这个后面再介绍)的函数才可以被蓝图实现)。Execute_OnInteract执行蓝图事件,第一个参数是UObject对象(接口调用的执行目标对象),后面的参数就是OnInteract函数的参数。这个函数是UHT自动生成的。其实这个函数本质上就是调用的UObject的ProcessEvent,具体你可以看生成的代码。(你到这个目录下的文件看看就知道了,Yourproject\Intermediate\Build\Win64\Inc\Yourproject\Yourproject.generated.cpp,Yourproject是你的项目名称)
最后一个问题,那如果想要这个函数接口既可以被C++实现又要被Blueprint实现怎么办?
你只要简单的把BlueprintImplementableEvent改成BlueprintNativeEvent就可以了。
.h
#pragma once #include "InteractionsInterface.generated.h" UINTERFACE()
class MMWORLD_API UInteractionsInterface : public UInterface
{
GENERATED_UINTERFACE_BODY()
}; class MMWORLD_API IInteractionsInterface
{
GENERATED_IINTERFACE_BODY()
public:
UFUNCTION(BlueprintNativeEvent)
void SwitchTurned(bool bNewOnOrOff, int32 CustomParam);
};
.cpp
#include "MMWorld.h"
#include "InteractionsInterface.h" UInteractionsInterface::UInteractionsInterface(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{ }
实现的Actor
.h
#pragma once #include "GameFramework/Actor.h"
#include "InteractionsInterface.h"
#include "InteractiveTargetActor.generated.h" UCLASS()
class MMWORLD_API AInteractiveTargetActor
: public AActor
, public IInteractionsInterface
{
GENERATED_BODY()
public:
AInteractiveTargetActor(); virtual void SwitchTurned_Implementation(bool bNewOnOrOff, int32 CustomParam) override; UFUNCTION(BlueprintImplementableEvent, Category = Interactive)
void SwitchAllTurnedOnOrOff(bool bOnOrOff); UFUNCTION(BlueprintCallable, Category = Interactive)
bool IsSwitchTurned(int32 Index); UFUNCTION(BlueprintCallable, Category = Interactive)
bool IsSwitchAllTurnedOn(); UFUNCTION(BlueprintCallable, Category = Interactive)
bool IsSwitchAllTurnedOff(); protected:
UPROPERTY(EditAnywhere, BlueprintReadOnly, meta = (ClampMin = "", ClampMax = "", UIMin = "", UIMax = ""))
int32 NeedSwitchTurnedNum; uint32 SwitchTurnedStates;
};
SwitchTurned在C++中要实现的函数是virtual void SwitchTurned_Implementation(bool bNewOnOrOff, int32 CustomParam) override; (BlueprintNativeEvent的函数名字_Implementation)。这个函数也是UHT自动生成的。
如果是你在Blueprint中是实现了SwitchTurned接口,那么C++的实现就会被覆盖隐藏掉。
那如果你的蓝图又要掉用C++接口实现怎么办?
UE4中没有直接实现这样的机制。但是你可以把SwitchTurned_Implementation实现提取出来一个新函数,然后把这个函数定义成UFUNCTION(BlueprintCallable, Category = Interactive),然后在蓝图中调用这个函数就解决了。
好了就介绍到这里,第一次写关于UE4的东西,不对的地方希望大家指正。希望这个对你有帮助。
参考例子:
https://github.com/henrya2/MMWorld
参考文章:
介绍Unreal Engine 4中的接口(Interface)使用C++和蓝图的更多相关文章
- Unreal Engine 4 中的 UI 优化技巧
		
转自:https://mp.weixin.qq.com/s/bybEHM9tF-jBPxxqXfrPOQ## Unreal Open Day 2017 活动上 Epic Games 开发者支持工程师郭 ...
 - java中的接口interface
		
关于接口 接口描述了实现了它的类拥有什么功能.因为Java是强类型的,所以有些操作必须用接口去约束和标记.接口作为类的能力的证明,它表明了实现了接口的类能做什么. 类似与class,interface ...
 - 在编写Arcgis Engine 过程中对于接口引用和实现过程过产生的感悟
		
Engine10.2版本 在vs里面新建类GeoMaoAO,并定义接口,在class中定义并实现,如下代码 以平时练习为例,我定义了一个接口,在里面定义了许多的控件,并在类中想要实现这一接口.如果在v ...
 - go语言中的接口interface
		
package main; import "fmt" //接口interface //接口是一个或多个方法签名的集合 //只要某个类型拥有该接口的所有方法签名,即算实现该接口. / ...
 - php中的接口interface
		
* 接口 * 1.使用关键字:interface * 2.类是对象的模板,接口是类的模板 * 3.接口看作是一个特殊的类 * 4.接口中的方法,只声明不实现,与抽象类一样 * 5.接口中的方法必须是p ...
 - Ts中的接口interface(属性也能继承...)
		
接口ITest.ts interface ITest { name:string; age:number; run(); to(x:number,y:number):number; } 必须继承接口的 ...
 - Objective-C 中的协议(@protocol)和接口(@interface)的区别
		
Objective-C 中的协议(@protocol),依照我的理解,就是C#, Java, Pascal等语言中的接口(Interface).协议本身不实现任何方法,只是声明方法,使用协议的类必须实 ...
 - C# 实例解释面向对象编程中的接口隔离原则
		
在面向对象编程中,SOLID 是五个设计原则的首字母缩写,旨在使软件设计更易于理解.灵活和可维护.这些原则是由美国软件工程师和讲师罗伯特·C·马丁(Robert Cecil Martin)提出的许多原 ...
 - Unreal Engine 4 创建Destructible Mesh(可破坏网格)
		
Unreal Engine 4的物理引擎用的是PhysX. 支持网格破坏.布料.物理粒子等,非常强大.曾经须要编码才干完毕的工作,在Unreal Engine 4 中仅仅须要拖拖拽拽就完毕了,非常方便 ...
 
随机推荐
- 深入剖析ConcurrentHashMap(1)
			
转载自并发编程网 – ifeve.com本文链接地址: 深入剖析ConcurrentHashMap(1) ConcurrentHashMap是Java5中新增加的一个线程安全的Map集合,可以用来替代 ...
 - Swift解算法——台阶问题
			
题目:一个台阶总共有n级,如果一次可以跳1级,也可以跳2级. 求总共有多少总跳法,并分析算法的时间复杂度. 首先对题目进行分析: 台阶一共有n级 因此当n = 1时——只有一种跳法 当 ...
 - python的or操作符连接多个字符串含义是什么?
			
研究odoo代码的时候发现其中有一行语句让人费解 self.rcfile = os.path.abspath( self.config_file or opt.config or os.environ ...
 - 获取应用程序信息.h
			
//// 获取应用程序信息.h// IOS笔记// 一般会用来判断是否有新版本.是否需要强制更新 iOS的版本号,一个叫做Version,一个叫做Build,这两个值都可以在Xcode 中选中ta ...
 - javaIO-学习笔记
			
package IOTest; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream ...
 - 关于javascript中闭包的理解
			
闭包就是能够读取其他函数内部变量的函数. 在javascript中,只有函数内部的子函数可以读取局部变量,因此,我理解闭包就是定义在一个函数内部的函数. 例子: var f1 = function() ...
 - OpenStack Mitaka安装
			
http://egon09.blog.51cto.com/9161406/1839667 前言: openstack的部署非常简单,简单的前提建立在扎实的理论功底,本人一直觉得,玩技术一定是理论指导实 ...
 - LeetCode "477. Total Hamming Distance"
			
Fun one.. the punch line of this problem is quite common in Bit related problems on HackerRank - vis ...
 - Lua学习---Lua的控制结构
			
前言 由于之前有c/c++.javascript基础,所以学Lua的时候喜欢拿来和前面的语言比较,这里主要和C比较 1.if...else Lua的if语句格式: if 条件 then 条件成立,运行 ...
 - Java BigDecimal和double
			
BigDecimal类 对于不需要任何准确计算精度的数字可以直接使用float或double,但是如果需要精确计算的结果,则必须使用BigDecimal类,而且使用BigDecimal类也可以进行大数 ...