Rework trigger and interactable

This commit is contained in:
Maxime Maurin 2023-08-03 23:22:54 +02:00
parent 74cff36b19
commit fbe4129df8
13 changed files with 219 additions and 13 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -8,7 +8,11 @@ public class Pawn : ModuleRules {
"Core", "Core",
"CoreUObject", "CoreUObject",
"Engine", "Engine",
"InputCore" "InputCore",
"EditorStyle",
"Slate",
"SlateCore",
"PropertyEditor"
}); });
PrivateDependencyModuleNames.AddRange(new string[] { }); PrivateDependencyModuleNames.AddRange(new string[] { });

View File

@ -1,12 +1,24 @@
#include "PawnModule.h" #include "PawnModule.h"
#include "PropertyEditorModule.h"
#include "Interaction/PwnInteractableActor.h"
#include "Interaction/PwnInteractableActorCustomization.h"
#include "Modules/ModuleManager.h" #include "Modules/ModuleManager.h"
IMPLEMENT_PRIMARY_GAME_MODULE(FPawnModule, Pawn, "Pawn"); IMPLEMENT_PRIMARY_GAME_MODULE(FPawnModule, Pawn, "Pawn");
void FPawnModule::StartupModule() { void FPawnModule::StartupModule() {
IModuleInterface::StartupModule(); FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");
PropertyModule.RegisterCustomPropertyTypeLayout(FPwnInteractableActor::StaticStruct()->GetFName(),
FOnGetPropertyTypeCustomizationInstance::CreateStatic(
&UPwnInteractableActorCustomization::MakeInstance));
PropertyModule.NotifyCustomizationModuleChanged();
} }
void FPawnModule::ShutdownModule() { void FPawnModule::ShutdownModule() {
IModuleInterface::ShutdownModule(); if (FModuleManager::Get().IsModuleLoaded("PropertyEditor")) {
FPropertyEditorModule& PropertyModule = FModuleManager::GetModuleChecked<FPropertyEditorModule>("PropertyEditor");
PropertyModule.UnregisterCustomPropertyTypeLayout(FPwnInteractableActor::StaticStruct()->GetFName());
PropertyModule.NotifyCustomizationModuleChanged();
}
} }

View File

@ -0,0 +1,37 @@
#include "Interaction/PwnInteractableActorCustomization.h"
#include "PropertyCustomizationHelpers.h"
#include "PropertyHandle.h"
#include "Interaction/PwnInteractable.h"
TSharedRef<IPropertyTypeCustomization> UPwnInteractableActorCustomization::MakeInstance() {
return MakeShareable(new UPwnInteractableActorCustomization());
}
void UPwnInteractableActorCustomization::CustomizeHeader(TSharedRef<IPropertyHandle> StructPropertyHandle, FDetailWidgetRow& HeaderRow,
IPropertyTypeCustomizationUtils& StructCustomizationUtils) {
const TSharedPtr<IPropertyHandle> ActorReferenceProperty = StructPropertyHandle->GetChildHandle(TEXT("ActorReference"));
HeaderRow
.NameContent()
[
StructPropertyHandle->CreatePropertyNameWidget()
]
.ValueContent()
[
SNew(SObjectPropertyEntryBox)
.PropertyHandle(ActorReferenceProperty)
.OnShouldFilterActor(FOnShouldFilterActor::CreateStatic(OnShouldFilterActor))
.AllowedClass(AActor::StaticClass())
.AllowClear(true)
];
}
void UPwnInteractableActorCustomization::CustomizeChildren(TSharedRef<IPropertyHandle> StructPropertyHandle, IDetailChildrenBuilder& StructBuilder,
IPropertyTypeCustomizationUtils& StructCustomizationUtils) {
// Do nothing
}
bool UPwnInteractableActorCustomization::OnShouldFilterActor(const AActor* Actor) {
return Actor->GetClass()->ImplementsInterface(UPwnInteractable::StaticClass());
}

View File

@ -5,6 +5,7 @@
UPwnTrigger::UPwnTrigger() { UPwnTrigger::UPwnTrigger() {
PrimaryComponentTick.bCanEverTick = false; PrimaryComponentTick.bCanEverTick = false;
bAutoActivate = true;
} }
void UPwnTrigger::BeginPlay() { void UPwnTrigger::BeginPlay() {
@ -29,6 +30,8 @@ void UPwnTrigger::OnOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActo
const FHitResult& SweepResult) { const FHitResult& SweepResult) {
if (UPwnTriggerRegister* Register = OtherActor->GetComponentByClass<UPwnTriggerRegister>()) { if (UPwnTriggerRegister* Register = OtherActor->GetComponentByClass<UPwnTriggerRegister>()) {
Register->RegisterTrigger(this); Register->RegisterTrigger(this);
OnTriggerEnter.Broadcast(OtherActor);
ExecuteActions(EnterActions);
} }
} }
@ -36,6 +39,34 @@ void UPwnTrigger::OnOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor*
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex) { UPrimitiveComponent* OtherComp, int32 OtherBodyIndex) {
if (UPwnTriggerRegister* Register = OtherActor->GetComponentByClass<UPwnTriggerRegister>()) { if (UPwnTriggerRegister* Register = OtherActor->GetComponentByClass<UPwnTriggerRegister>()) {
Register->UnregisterTrigger(this); Register->UnregisterTrigger(this);
OnTriggerExit.Broadcast(OtherActor);
ExecuteActions(ExitActions);
}
}
void UPwnTrigger::Activate(const bool bReset) {
if (bReset || ShouldActivate() == true) {
VolumeComponent->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
SetActiveFlag(true);
OnComponentActivated.Broadcast(this, bReset);
}
}
void UPwnTrigger::Deactivate() {
if (ShouldActivate() == false) {
VolumeComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision);
SetActiveFlag(false);
OnComponentDeactivated.Broadcast(this);
}
}
void UPwnTrigger::Interact_Implementation(const EInteractionType InteractionType) {
if (InteractionType == Enable) {
Activate(true);
} else if (InteractionType == Disable) {
Deactivate();
} else if (InteractionType == Toggle) {
ExecuteActions(ManualActions);
} }
} }
@ -45,3 +76,12 @@ FVector UPwnTrigger::GetVolumeCenter() const {
} }
return FVector::ZeroVector; return FVector::ZeroVector;
} }
void UPwnTrigger::ExecuteActions(const FInteractableActions& InteractableActions) const {
for (const FInteractableAction &Action : InteractableActions.Actions) {
Execute_Interact(Action.Interactable.ActorReference.TryLoad(), Action.InteractionType);
}
if (InteractableActions.SelfInteract) {
Execute_Interact(GetOwner(), InteractableActions.SelfInteractionType);
}
}

View File

@ -0,0 +1,25 @@
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "PwnInteractable.generated.h"
UENUM(BlueprintType)
enum EInteractionType {
Toggle,
Enable,
Disable,
};
UINTERFACE(BlueprintType, Blueprintable, DisplayName="Interactable")
class UPwnInteractable : public UInterface {
GENERATED_BODY()
};
class PAWN_API IPwnInteractable {
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category="Interaction")
void Interact(const EInteractionType InteractionType);
};

View File

@ -0,0 +1,11 @@
#pragma once
#include "PwnInteractableActor.generated.h"
USTRUCT(BlueprintType)
struct PAWN_API FPwnInteractableActor {
GENERATED_BODY()
UPROPERTY(EditAnywhere)
FSoftObjectPath ActorReference;
};

View File

@ -0,0 +1,17 @@
#pragma once
#include "IPropertyTypeCustomization.h"
class PAWN_API UPwnInteractableActorCustomization : public IPropertyTypeCustomization {
public:
static TSharedRef<IPropertyTypeCustomization> MakeInstance();
virtual void CustomizeHeader(TSharedRef<IPropertyHandle> StructPropertyHandle,
FDetailWidgetRow& HeaderRow,
IPropertyTypeCustomizationUtils& StructCustomizationUtils) override;
virtual void CustomizeChildren(TSharedRef<IPropertyHandle> StructPropertyHandle,
IDetailChildrenBuilder& StructBuilder,
IPropertyTypeCustomizationUtils& StructCustomizationUtils) override;
static bool OnShouldFilterActor(const AActor* Actor);
};

View File

@ -1,19 +1,49 @@
#pragma once #pragma once
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "PwnInteractable.h"
#include "PwnInteractableActor.h"
#include "Components/ActorComponent.h" #include "Components/ActorComponent.h"
#include "PwnTrigger.generated.h" #include "PwnTrigger.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FTriggerDelegate, AActor*, Actor);
USTRUCT(BlueprintType)
struct FInteractableAction {
GENERATED_BODY()
UPROPERTY(EditAnywhere)
FPwnInteractableActor Interactable;
UPROPERTY(EditAnywhere)
TEnumAsByte<EInteractionType> InteractionType;
};
USTRUCT(BlueprintType)
struct FInteractableActions {
GENERATED_BODY()
UPROPERTY(EditAnywhere)
TArray<FInteractableAction> Actions;
UPROPERTY(EditAnywhere)
bool SelfInteract;
UPROPERTY(EditAnywhere, meta=(EditCondition="SelfInteract", EditConditionHides))
TEnumAsByte<EInteractionType> SelfInteractionType;
};
UCLASS(ClassGroup="Interaction", UCLASS(ClassGroup="Interaction",
HideCategories=("Activation", "Cooking", "Replication", "Collision"), HideCategories=("Cooking", "Replication", "Collision"),
meta=(BlueprintSpawnableComponent, DisplayName="Trigger")) meta=(BlueprintSpawnableComponent, DisplayName="Trigger"))
class PAWN_API UPwnTrigger : public UActorComponent { class PAWN_API UPwnTrigger : public UActorComponent, public IPwnInteractable {
GENERATED_BODY() GENERATED_BODY()
public: public:
UPwnTrigger(); UPwnTrigger();
protected: protected:
// Unreal Engine overrides
virtual void BeginPlay() override; virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
@ -26,10 +56,37 @@ protected:
void OnOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, void OnOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp,
int32 OtherBodyIndex); int32 OtherBodyIndex);
virtual void Activate(bool bReset) override;
virtual void Deactivate() override;
// End of Unreal Engine overrides
public: public:
// IPwnInteractable overrides
virtual void Interact_Implementation(const EInteractionType InteractionType) override;
// End of IPwnInteractable overrides
UFUNCTION() UFUNCTION()
FVector GetVolumeCenter() const; FVector GetVolumeCenter() const;
private:
void ExecuteActions(const FInteractableActions &InteractableActions) const;
public:
UPROPERTY(EditAnywhere, Category="Interaction")
FInteractableActions EnterActions;
UPROPERTY(EditAnywhere, Category="Interaction")
FInteractableActions ExitActions;
UPROPERTY(EditAnywhere, Category="Interaction")
FInteractableActions ManualActions;
UPROPERTY(BlueprintAssignable)
FTriggerDelegate OnTriggerEnter;
UPROPERTY(BlueprintAssignable)
FTriggerDelegate OnTriggerExit;
protected: protected:
UPROPERTY(EditAnywhere, meta=(UseComponentPicker, AllowedClasses="ShapeComponent")) UPROPERTY(EditAnywhere, meta=(UseComponentPicker, AllowedClasses="ShapeComponent"))
FComponentReference TriggerVolume; FComponentReference TriggerVolume;