zoukankan      html  css  js  c++  java
  • 介绍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

    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,具体你可以看生成的代码。(你到这个目录下的文件看看就知道了,YourprojectIntermediateBuildWin64IncYourprojectYourproject.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

    参考文章:

  • 相关阅读:
    vue2.0对于数组变化不及时刷新视图的问题
    [Node]报错:gyp verb check python checking for Python executable "python2" in the PATH
    spring的@ControllerAdvice注解
    antdVue--Upload使用
    antd Vue--this.$confirm弹窗使用
    播放视频判断是否暂停_Javascript判断Video视频播放、暂停、结束完成及获取长度事件监听处理...
    P5400 [CTS2019]随机立方体
    P7502 「HMOI R1」不知道是啥的垃圾题
    vue3插槽使用
    cocos creator破解
  • 原文地址:https://www.cnblogs.com/Henrya2/p/4519479.html
Copyright © 2011-2022 走看看