c++中获取蓝图组件_【UE4_C++】<8-4>类与接口之间的通信-蓝图部分——从C++调用蓝图定义的接口函数...

四、从C++调用蓝图定义的接口函数

之前的例子关注的是C++在 Blueprint 中的可用性,比如能够从 Blueprint 中的C++调用函数,以及用 Blueprint 覆盖C++函数,但这个例子讲述的是相反的: 从C++调用 Blueprint 定义的接口函数。

首先创建新类:

添加代码:

Talker.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragmaonce

#include"CoreMinimal.h"

#include"UObject/Interface.h"

#include"Talker.generated.h"

// This class does not need to be modified.

UINTERFACE(MinimalAPI)

classUTalker:publicUInterface

{

GENERATED_BODY()

};

/**

*

*/

classNEWTUTORIALPROJECT_APIITalker

{

GENERATED_BODY()

// Add interface functions to this class. This is the class that will be inherited to implement this interface.

public:

UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = Talk)

voidStartTalking();

};

Talker.cpp

// Fill out your copyright notice in the Description page of Project Settings.

#include"Talker.h"

// Add default functionality here for any ITalker functions that are not pure virtual.

TalkingMesh.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragmaonce

#include"CoreMinimal.h"

#include"Engine/StaticMeshActor.h"

#include"Talker.h"

#include"TalkingMesh.generated.h"

/**

*

*/

UCLASS()

classNEWTUTORIALPROJECT_APIATalkingMesh :publicAStaticMeshActor,publicITalker

{

GENERATED_BODY()

public:

ATalkingMesh();

voidStartTalking_Implementation();

};

TalkingMesh.cpp

// Fill out your copyright notice in the Description page of Project Settings.

#include"TalkingMesh.h"

#include"ConstructorHelpers.h"

#include"Engine/StaticMesh.h"

#include"Components/StaticMeshComponent.h"

#include"Engine/Engine.h"

ATalkingMesh::ATalkingMesh():Super()

{

autoMeshAsset =ConstructorHelpers::FObjectFinder(TEXT("StaticMesh'/Engine/BasicShapes/Cube.Cube'"));

UStaticMeshComponent * SM =GetStaticMeshComponent();

if(SM !=nullptr) {

if(MeshAsset.Object!=nullptr)

{

SM->SetStaticMesh(MeshAsset.Object);SM->SetGenerateOverlapEvents(true);

}

SM->SetMobility(EComponentMobility::Movable);

}

SetActorEnableCollision(true);

}

voidATalkingMesh::StartTalking_Implementation()

{

GEngine->AddOnScreenDebugMessage(-1,1,FColor::Red,TEXT("Hello there. What is your name?"));

}

TalkingPawn.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragmaonce

#include"CoreMinimal.h"

#include"GameFramework/DefaultPawn.h"

#include"Components/BoxComponent.h"

#include"TalkingPawn.generated.h"

/**

*

*/

UCLASS()

classNEWTUTORIALPROJECT_APIATalkingPawn :publicADefaultPawn

{

GENERATED_BODY()

public:// Sets default values for this character's properties

ATalkingPawn();

UPROPERTY()

UBoxComponent* TalkCollider;

UFUNCTION()

voidOnTalkOverlap(UPrimitiveComponent*OverlappedComponent,AActor*OtherActor,UPrimitiveComponent*OtherComp,int32OtherBodyIndex,boolbFromSweep,constFHitResult&SweepResult);

};

TalkingPawn.cpp

// Fill out your copyright notice in the Description page of Project Settings.

#include"TalkingPawn.h"

#include"Talker.h"

ATalkingPawn::ATalkingPawn()

{

PrimaryActorTick.bCanEverTick=true;

TalkCollider =CreateDefaultSubobject("TalkCollider");

TalkCollider->SetBoxExtent(FVector(200,200,100));

TalkCollider->OnComponentBeginOverlap.AddDynamic(this, &ATalkingPawn::OnTalkOverlap);

TalkCollider->AttachToComponent(RootComponent,FAttachmentTransformRules::SnapToTargetIncludingScale);

}

voidATalkingPawn::OnTalkOverlap(UPrimitiveComponent*OverlappedComponent,AActor*OtherActor,UPrimitiveComponent*OtherComp,int32OtherBodyIndex,boolbFromSweep,constFHitResult&SweepResult)

{

autoClass =OtherActor->GetClass();

if(Class->ImplementsInterface(UTalker::StaticClass()))

{

ITalker::Execute_StartTalking(OtherActor);

}

}

编译完之后在编译器设置一下默认角色:

场景中布局:

运行后当角色靠近方块,会打印语句:

创建一个基于TakingMesh的蓝图类,并添加代码:

运行后角色靠近的打印语句改变:

这是因为方法在蓝图中被重写。

继续修改代码:

右击节点点击调用父类方法

会出现一个父类方法节点:

此时再运行结果如下:

总结:

像往常一样,我们创建一个新的接口,然后向 IInterface 类添加一些函数定义。 我们使用 BlueprintNativeEvent 说明符表示我们希望在C++中声明一个默认实现,然后可以在 Blueprint 中重写该实现。 我们创建一个新类(为方便起见从 StaticMeshActor 继承)并在其上实现接口。

在新类构造函数的实现中,我们加载了一个静态网格,并像往常一样设置了碰撞。 然后,我们为接口函数添加一个实现,它只是将一条消息打印到屏幕上。

如果我们在一个成熟的项目中使用它,我们可以播放动画,播放音频,改变用户界面,以及任何其他必要的东西来启动与你的谈话者的对话。

不过,在这一点上,我们还没有任何实际的东西可以在我们的TalkingMesh上称为 StartTalking。 实现这一点的最简单方法是创建一个新的 Pawn 子类(同样,为方便起见从 DefaultPawn 继承) ,它可以开始与任何与它相冲突的 Talker 参与者进行对话。

为了实现这一点,我们创建了一个新的 BoxComponent,以确定触发对话的半径。 像往常一样,它是一个 UPROPERTY,所以它不会被垃圾收集。 我们还为一个函数创建了定义,当新的 BoxComponent 与场景中的另一个 Actor 重叠时,这个函数将被触发。

我们 TalkingPawn 的构造函数初始化新的 BoxComponent,并适当地设置它的区段。 构造函数还将 OnTalkOverlap 函数绑定为事件处理程序,以处理 BoxComponent 的冲突。 它还将盒子组件附加到我们的 RootComponent 上,这样当玩家在关卡上移动时,它就可以跟随玩家角色的其余部分移动。

在 OnTalkOverlap 中,我们需要检查另一个参与者是否实现了 Talker 接口。 最可靠的方法是使用 UClass 中的 ImplementsInterface 函数。 该函数使用 Unreal Header Tool 在编译期间生成的类信息,并正确处理C++和 blueprint 实现的接口。

如果函数返回 true,我们可以使用 IInterface 中包含的一个特殊的自动生成函数来调用我们在实例上选择的 interface 方法。 这是表单 IInterface: : Execute_functionname 的静态方法。 在我们的实例中,我们的 IInterface 是 ITalker,函数是 StartTalking,因此我们要调用的函数是 ITalker: : Execute_StartTalking ()。

我们需要这个函数的原因是,当一个接口在 Blueprint 中实现时,这个关系实际上并不是在编译时建立的。 因此,C++ 没有意识到接口是实现的,所以我们不能将 Blueprint 类强制转换为 IInterface 来直接调用函数。

Execute 函数获取一个指向实现该接口的对象的指针,并调用许多内部方法来调用所需函数的 Blueprint 实现。

当我们控制角色走动时,当它的 BoxComponent 与其他对象重叠时,自定义的角色会不断地收到通知。 如果他们实现了 UTalker / ITalker 接口,角色就会尝试在有接口的 Actor 实例上调用 StartTalking,然后在屏幕上打印相应的消息。


版权声明:本文为weixin_39880150原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。