- Create a new UInterface called Talker (Creating the UTalker/ITalker classes):
- Add the following UFUNCTION implementation:
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "Talker.generated.h"
// This class does not need to be modified.
UINTERFACE(MinimalAPI)
class UTalker : public UInterface
{
GENERATED_BODY()
};
/**
*
*/
class CHAPTER_08_API ITalker
{
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)
void StartTalking();
};
- Create a new C++ class based on StaticMeshActor. Remember to check Show All Classes and find the class that way:
.
- After clicking Next, name this new class TalkingMesh:
- Add #include and modify the class declaration to include the talker interface:
#pragma once
#include "CoreMinimal.h"
#include "Engine/StaticMeshActor.h"
#include "Talker.h"
#include "TalkingMesh.generated.h"
/**
*
*/
UCLASS()
class CHAPTER_08_API ATalkingMesh : public AStaticMeshActor, public ITalker
- Also, add the following functions to the class declaration:
UCLASS()
class CHAPTER_08_API ATalkingMesh : public AStaticMeshActor, public ITalker
{
GENERATED_BODY()
public:
ATalkingMesh();
void StartTalking_Implementation();
};
- Within the implementation, add the following to TalkingMesh.cpp:
#include "TalkingMesh.h"
#include "ConstructorHelpers.h"
ATalkingMesh::ATalkingMesh() : Super()
{
auto MeshAsset = ConstructorHelpers::FObjectFinder<UStaticMesh>(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);
}
void ATalkingMesh::StartTalking_Implementation()
{
GEngine->AddOnScreenDebugMessage(-1, 1, FColor::Red,
TEXT("Hello there. What is your name?"));
}
- Create a new class based on DefaultPawn to function as our player character:
- Once you select Next, give the class a Name of TalkingPawn and select Create Class:
- Add the following to our class header:
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/DefaultPawn.h"
#include "Components/BoxComponent.h" // UBoxComponent
#include "TalkingPawn.generated.h"
/**
*
*/
UCLASS()
class CHAPTER_08_API ATalkingPawn : public ADefaultPawn
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
ATalkingPawn();
UPROPERTY()
UBoxComponent* TalkCollider;
UFUNCTION()
void OnTalkOverlap(UPrimitiveComponent* OverlappedComponent,
AActor* OtherActor,
UPrimitiveComponent* OtherComp,
int32 OtherBodyIndex, bool bFromSweep,
const FHitResult & SweepResult);
};
- From the TalkingPawn.cpp file, make sure to include the following so that we have access to the ITalker and UTalker classes:
#include "TalkingPawn.h"
#include "Talker.h"
- Afterwards implement the constructor:
ATalkingPawn::ATalkingPawn() : Super()
{
// Set this character to call Tick() every frame. You can
// turn this off to improve performance if you
// don't need it.
PrimaryActorTick.bCanEverTick = true;
TalkCollider = CreateDefaultSubobject<UBoxComponent>("TalkCollider");
TalkCollider->SetBoxExtent(FVector(200, 200, 100));
TalkCollider->OnComponentBeginOverlap.AddDynamic(this, &ATalkingPawn::OnTalkOverlap);
TalkCollider->AttachTo(RootComponent);
}
- Implement OnTalkOverlap:
// Called to bind functionality to input
void ATalkingPawn::OnTalkOverlap(UPrimitiveComponent* OverlappedComponent,
AActor* OtherActor,
UPrimitiveComponent* OtherComp,
int32 OtherBodyIndex, bool bFromSweep,
const FHitResult & SweepResult)
{
auto Class = OtherActor->GetClass();
if (Class->ImplementsInterface(UTalker::StaticClass()))
{
ITalker::Execute_StartTalking(OtherActor);
}
}
- Compile your scripts. Create a new GameMode and set TalkingPawn as the default pawn class for the player. The quickest way to do this is to go to Settings | World Settings and then, under GameMode Override, click on the + button. From there, expand the Selected GameMode option and under Default Pawn Class, select TalkingPawn. Refer to the following screenshot:
- Drag an instance of your ATalkingMesh class into the level. If you play the game now, you should be able to walk close to the mesh and see it display a message:
- Create a new Blueprint class based on ATalkingMesh by right-clicking on it from the Content Browser and selecting the appropriate option from the context menu:
- Name it MyTalkingMesh and select Create Blueprint Class:
- Inside the Blueprint Editor, create an implementation for StartTalking. We can do this by going to the Event Graph and right-clicking within the graph. Then, in the search bar, we can type in start talking. Under Add Event, select the Event Start Talking option.
- If you would like to call the parent version of the event, you can right-click on the event node and select the Add call to parent function option:
- Afterward, you can connect the events together. To do something different from the original, create a Print String node and display a new In String message, such as I'm the overridden implementation in Blueprint. The final version of the example will look as follows:
- Compile your Blueprint. Afterwards, drag a copy of your new Blueprint into the level beside your ATalkingMesh instance.
- Walk up to the two actors and verify that your custom Pawn is correctly invoking either the default C++ implementation or the Blueprint implementation, as appropriate: