惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

K
Kaspersky official blog
Engineering at Meta
Engineering at Meta
D
DataBreaches.Net
Stack Overflow Blog
Stack Overflow Blog
Microsoft Security Blog
Microsoft Security Blog
Y
Y Combinator Blog
B
Blog RSS Feed
GbyAI
GbyAI
P
Proofpoint News Feed
aimingoo的专栏
aimingoo的专栏
MyScale Blog
MyScale Blog
D
Docker
阮一峰的网络日志
阮一峰的网络日志
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Recorded Future
Recorded Future
美团技术团队
The Register - Security
The Register - Security
V
Visual Studio Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
T
Tailwind CSS Blog
爱范儿
爱范儿
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
The Blog of Author Tim Ferriss
博客园 - 司徒正美
量子位
B
Blog
F
Fortinet All Blogs
Martin Fowler
Martin Fowler
博客园 - 【当耐特】
MongoDB | Blog
MongoDB | Blog
A
About on SuperTechFans
I
InfoQ
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
有赞技术团队
有赞技术团队
雷峰网
雷峰网
大猫的无限游戏
大猫的无限游戏
J
Java Code Geeks
L
LangChain Blog
Latest news
Latest news
S
SegmentFault 最新的问题
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Blog — PlanetScale
Blog — PlanetScale
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Cisco Talos Blog
Cisco Talos Blog
F
Full Disclosure
C
Cisco Blogs
D
Darknet – Hacking Tools, Hacker News & Cyber Security
W
WeLiveSecurity
T
Tenable Blog
T
Tor Project blog

博客园 - HenryRead

OpenGL 像素在内存中的排列方式 Unreal Engine 4 一些小技巧或提示 Project Euler Problem 17 一种简单定义FourCC常量的方法 (C/C++) [翻译]进化游戏的层次结构 - 用组件来重构你的游戏实体 [转载]Netmsg 局域网聊天程序 [转载]使用 WSAAsyncSelect 的 Winsock 编程模型 [转载]Singleton的一个基类实现 [转载] VC6 STLport-5.1.4 /STLport-4.6.2 编译,安装 [转载] 跨平台C++程序开发系列文章 计算机科学数学理论浅谈 (转载) 致初学作曲的业余音乐爱好者 (转载) 搜集的优良OpenGL教程 (转载) OpenGL教程 "Top Ten" (转载) fltk2更新简介 FLTK简介 开发者:我们应该在哪个层次编写代码? [Linux 书籍合集] Linux eBooks collection CodeLite可以媲美Code::Blocks 不指定
介绍Unreal Engine 4中的接口(Interface)使用C++和蓝图
HenryRead · 2015-05-21 · via 博客园 - HenryRead

这个教程是从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

3402568203

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

3523847589

那怎调用这个蓝图实现的接口在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 = "1", ClampMax = "32", UIMin = "1", UIMax = "32"))
    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

参考文章: