主要有三大部分:角色(Character),物品(Actor)以及接口(Interface)。
首先定义接口
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "Interact.generated.h"
// This class does not need to be modified.
UINTERFACE(MinimalAPI,Blueprintable)
class UInteract : public UInterface
{
GENERATED_BODY()
};
/**
*
*/
class RPG_API IInteract
{
GENERATED_BODY()
// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
void Interact();
};
这里我定义了一个接口,并有一个BlueprintNativeEvent属性的函数Interact(),用于实现交互功能。
接着给角色添上一个碰撞体(默认物品有自己的碰撞体),注意头文件的包含。
#include "Components/SphereComponent.h"
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Collsion, meta = (AllowPrivateAccess = "true"))
class USphereComponent* InteractRadius;
InteractRadius= CreateDefaultSubobject<USphereComponent>(TEXT("InteractRadius"));
InteractRadius->SetupAttachment(GetMesh());
之后定义碰撞函数,分为开始碰撞以及结束碰撞。
private:
//Set collision events
UFUNCTION()
void OnInteractBeginOverlap(class UPrimitiveComponent* Component, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
UFUNCTION()
void OnInteractEndOverlap(class UPrimitiveComponent* Component, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
要在BeginPlay中绑定碰撞。
void ARPGCharacter::BeginPlay()
{
// Call the base class
Super::BeginPlay();
//Add Input Mapping Context
if (APlayerController* PlayerController = Cast<APlayerController>(Controller))
{
if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
{
Subsystem->AddMappingContext(DefaultMappingContext, 0);
}
}
InteractRadius->OnComponentBeginOverlap.AddDynamic(this,&ARPGCharacter::OnInteractBeginOverlap);
InteractRadius->OnComponentEndOverlap.AddDynamic(this,&ARPGCharacter::OnInteractEndOverlap);
}
这里实现的是拾取碰撞的第一个物品(注意,角色为碰撞的第一个物品,所以索引从1开始),首先把碰撞到的物品添加到一个TArray<AActor*> InteractableInRange中。
void ARPGCharacter::OnInteractBeginOverlap(class UPrimitiveComponent* Component, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
if (UKismetSystemLibrary::DoesImplementInterface(OtherActor, UInteract::StaticClass()))
{
InteractableInRange.AddUnique(OtherActor);
}
}
void ARPGCharacter::OnInteractEndOverlap(UPrimitiveComponent* Component, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
if (UKismetSystemLibrary::DoesImplementInterface(OtherActor, UInteract::StaticClass()))
{
UKismetSystemLibrary::PrintString(this, "error");
InteractableInRange.Remove(OtherActor);
}
}
然后在物品基类中继承接口,之后覆写Interact函数(最后一行),PickupItem可以自己在角色类中定义实现自己想要的功能,比如添加进背包等。
UCLASS()
class RPG_API ABasicInteractable : public AActor,public IInteract
{
GENERATED_BODY()
};
public:
UFUNCTION(BlueprintCallable)
virtual void Interact_Implementation() override;
void ABasicInteractable::Interact_Implementation()
{
Cast<ARPGCharacter>(UGameplayStatics::GetPlayerCharacter(this,0))->PickupItem(ItemInfo);
this->Destroy();
}
最后按键绑定后(这里自己绑定吧),执行Interact函数。
void ARPGCharacter::Interact()
{
if (InteractableInRange.Num()>1)
{
IInteract::Execute_Interact(InteractableInRange[1]);
}
}