UE_Angelscript 绑定篇——解决方案:Unreal Interfaces 缺失的缓解药剂#

问题来源#

一句话:Hazelight 官方不支持。 Hazelight 在自己的项目中禁用了 UE 接口相关的一切功能,他们更喜欢在项目里使用 Actor + Component 的组合方式,对 Actor 和 ActorComponent 的支持就比较完善。

这种缺失会造成一个问题,如果有模块大量使用了 UE 接口功能,那么调用起来就是头疼的事了。如何解决这个头疼问题,除了修改脚本源码外,这里提供一些缓解疼痛的方案。

注:除了本文提到的以下方法外,调用的函数可以考虑手工绑定,也是一种选择,不过就复杂更多了,本文不做详细探讨。

Discord 上关于 AngelScript Unreal Interface 支持的讨论

Unreal Interfaces 的函数调用#

一句话: cpp 里用 Mixin 包装。

如果想要调用 Unreal Interface 的 BlueprintCallable 函数,那么需要包装,一般这种函数是 public 的,可以在 cpp 里用 Mixin 的方式进行包装。

函数名之前建议加上 BP_,其会在绑定到 AS 的时候自动去掉,使用起来和直接调用接口函数就一致了。不过我个人喜欢给这些函数加个后缀,提醒这是来自于 Unreal Interface ,要小心点的意思。

Unreal Interface 的包装函数,最好用 ScriptCallable ,不然蓝图里就可能有两个同样的函数了。

另外,如果不麻烦,顺便就将其他未标 BlueprintCallable 的函数也包装了吧,免得以后用还得来绑定。

有人提供方案,继承接口的时候再次标上 UFUNCTION 的标识符?也不是不行,都继承了,怎么处理都方便。

Unreal Interfaces 的函数覆写#

Unreal Interface 的 vitual 函数#

一句话: 继承下来,然后暴露出一个 BP\_版本专门给 Angelscript 使用。

其他任何想暴露给 Angelscript 覆写的函数,也是这个办法。有时候也可以暴露出一个动态单播或多播委托,这样也可以处理很多问题,甚至更方便一些。

Unreal Interfaces 的 BlueprintNativeEvent 或 BlueprintImplementableEvent#

BlueprintNativeEvent 的话,这有点类似 vitual 函数的处理方式,但是更麻烦一点。

BlueprintNativeEvent 很多时候会同时带有 BlueprintCallable,这时候参照 BlueprintCallable 的方式,Mixin 绑定。至于覆写这个函数,需要在实现里,暴露出一个 BP\_版本专门给 Angelscript 使用。

BlueprintImplementableEvent 的话,暂时没办法找到覆盖的办法。或许继承的类里,直接写个同名的函数覆盖?这种情况少见,忽略吧。

一个接口里一般不会有太多这种东西,可能因为以下内容导致一些标识符问题:BlueprintCallable 不带 BlueprintEvent 的函数,和 BlueprintCallable + BlueprintEvent 的函数,不能同时存在一个 Interface 里。因为 BlueprintCallable 不带 BlueprintEvent 的函数会要 UClass 里带上 NotBlueprintable,而 BlueprintEvent 需要 Blueprintable 或空着不写。

判断某个类是否实现了 Unreal Interface 的解决方案#

尽管可以实现判断 Class 是否实现了 Unreal Interface 的方法,但是没办法通过 Unreal Interface 的指针来调用某 Object 的接口方法,这没办法,接口在这里真的不受待见。

有时候我们还是希望知道一个类是否实现了某个接口,有几个方式。

1、最简单的就是查看类的继承关系。

2、通过 cpp 写一个有 Cast 代码的函数,然后给脚本调用。

3、通过反射,不过写起来复杂一些,性能也未必好。

以下是通过反射写的,可以参考。

用 cpp 包装一个专用的类,比如叫做 UInterfaceAddonLibrary,继承自 UBlueprintFunctionLibrary,写两个函数分别判断 UClass 和 UObject 是否实现了 Unreal Interface。

同时,通过 UObjectMixinLibrary 给 UObejct 注入一个 BP_HasInterface 函数,方便调用。

这是其中一种通过反射查询 Unreal Interface 的方法,比较简单,不过因为遍历了 ANY_PACKAGE ,可能性能一般。是可以有优化版本的,实现起来逻辑复杂一些,如果有需求,可以专门写来调试。

// ~~ InterfaceAddonLibrary.h
#pragma once

#include "Kismet/BlueprintFunctionLibrary.h"

#include "InterfaceAddonLibrary.generated.h"

UCLASS(MinimalAPI)
class UInterfaceAddonLibrary : public UBlueprintFunctionLibrary
{
    GENERATED_UCLASS_BODY()

public:
    /** Check if an UClass has Implemented an Unreal Interface by pass in an FName.
     * Example usage in Angelscript:     
     * \code     
     * Class ExampleActor : public AActor, public IExampleInterface     
     * InterfaceAddon::HasInterface_UClass(ExampleActor::StaticClass(),n"ExampleInterface");     
     * // Make the ExampleActor as ExampleActorObject     
     * InterfaceAddon::HasInterface_UClass(ExampleActorObject.Class,n"ExampleInterface");     
     * \endcode     
     **/
    UFUNCTION(BlueprintCallable)
    static bool HasInterface_UClass(UClass* ObjectClass, const FName& InterfaceName)
    {
       if (!ObjectClass || InterfaceName.IsNone())
       {
          UE_LOG(LogTemp, Warning, TEXT("Invalid input: ObjectClass or InterfaceName is null."));
          return false;
       }

       // Use FName to search the Interface class  (maybe it is not an Interface)
       const UClass* InterfaceClass = FindObject<UClass>(ANY_PACKAGE, *InterfaceName.ToString());
       if (!InterfaceClass)
       {
          UE_LOG(LogTemp, Warning, TEXT("Interface %s not found."), *InterfaceName.ToString());
          return false;
       }

       // Check if the Interface class found is exactly Interface
       if (!InterfaceClass->IsChildOf(UInterface::StaticClass()))
       {
          UE_LOG(LogTemp, Warning, TEXT("%s is not an interface class."), *InterfaceName.ToString());
          return false;
       }

       // check if the object class Implement the Interface
       if (ObjectClass->ImplementsInterface(InterfaceClass))
       {
          return true;
       }

       return false;
    }

     /** Check if an UObject has Implemented an Unreal Interface by pass in an FName.
     * Example usage in Angelscript:     
     * \code     
     * Class ExampleActor : public AActor, public IExampleInterface     
     * // Make the ExampleActor as ExampleActorObject     
     * InterfaceAddon::HasInterface(ExampleActorObject,n"ExampleInterface");      * \endcode     
     **/
    UFUNCTION(BlueprintCallable)
    static bool HasInterface(UObject* Object, const FName& InterfaceName)
    {
       if (!Object || InterfaceName.IsNone())
       {
          UE_LOG(LogTemp, Warning, TEXT("Invalid input: Object or InterfaceName is null."));
          return false;
       }

       return HasInterface_UClass(Object->GetClass(), InterfaceName);
    }
};

// ~~ InterfaceAddonLibrary.cpp
#pragma once

#include "InterfaceAddonLibrary.h"

UInterfaceAddonLibrary::UInterfaceAddonLibrary(
    const FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer)
{
};
// ~~ ObjectMixinLibrary.h
#pragma once

#include "CoreMinimal.h"
#include "InterfaceAddonLibrary.h"

#include "ObjectMixinLibrary.generated.h"

UCLASS(Meta = (ScriptMixin = "UObject"))
class DFMIXIN_API UObjectMixinLibrary : public UObject
{
    GENERATED_BODY()

public:
    /** Check if an UObject has Implemented an Unreal Interface by pass in an FName.
     * Example usage in Angelscript:     
     * \code     
     * Class ExampleActor : public AActor, public IExampleInterface     
     * // Make the ExampleActor as ExampleActorObject     
     * ExampleActorObject.HasInterface(n"ExampleInterface");     
     * \endcode     
     **/
    UFUNCTION(BlueprintPure, Category = "Unreal Interface", DisplayName="HasInterface")
    static bool BP_HasInterface(UObject* Object, const FName& InterfaceName)
    {
       return UInterfaceAddonLibrary::HasInterface(Object, InterfaceName);
    };
};
×

联系

问题反馈

问题与反馈请提交至 GitHub Issues。

合作

合作事宜请发送邮件至 contact@cuviss.com。

×

关于

服务条款

各插件的许可证见社区贡献页。

网站内容可在注明来源后引用。

软件和文档按“现状”提供,不作任何保证。

Unreal Engine 等第三方项目及名称相关商标归各自所有者所有。soloAS 与 Epic Games、Hazelight 均无关联。

致谢和案例展示请求均不具约束力,详见首页说明。

更新于 2026-10-24

隐私政策

本网站不使用分析工具、Cookie 或跟踪,也没有数据表单或第三方脚本。

网站托管于 GitHub Pages。GitHub 可能按其隐私声明处理标准访问日志。

通过邮件发送的内容会提供给我们;通过 GitHub Issues 发送的内容会提供给 GitHub。

更新于 2026-10-24

目录

页面列表

本页目录