diff --git a/Pawn_Unreal/Content/Characters/BP_Judy.uasset b/Pawn_Unreal/Content/Characters/BP_Judy.uasset index 1264e16..d21f3c3 100644 --- a/Pawn_Unreal/Content/Characters/BP_Judy.uasset +++ b/Pawn_Unreal/Content/Characters/BP_Judy.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d7d0fdd6df220879b984100630b91e569a44aaba57509ab66f3339b25b389fb2 -size 93984 +oid sha256:688fd36e25836113024533b73015000e02d1e110cdc1377eba4301450be33207 +size 92219 diff --git a/Pawn_Unreal/Content/Developers/maxim/BP_TriggerTest.uasset b/Pawn_Unreal/Content/Developers/maxim/BP_TriggerTest.uasset index 8d46ede..142e972 100644 --- a/Pawn_Unreal/Content/Developers/maxim/BP_TriggerTest.uasset +++ b/Pawn_Unreal/Content/Developers/maxim/BP_TriggerTest.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:73d72c783d6e954807ab780c4aca2325e966dc6183d47d1b34570f451595dab9 -size 109860 +oid sha256:74f0e15b324ce560fe9e595c7917b484d70b8c1eec6b8a190b5dd9a1dea4d526 +size 105126 diff --git a/Pawn_Unreal/Content/Systems/Camera/BP_CameraModule.uasset b/Pawn_Unreal/Content/Systems/Camera/BP_CameraModule.uasset index cdc259e..3ff0f45 100644 --- a/Pawn_Unreal/Content/Systems/Camera/BP_CameraModule.uasset +++ b/Pawn_Unreal/Content/Systems/Camera/BP_CameraModule.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3eae1712e3dd064ea4e5a1871eaf21e6ca292066c02132260d5606bebeb64e38 -size 119605 +oid sha256:0c0e733865be39f9af564684310c3ac1abf31d00877715172a527924c8834e75 +size 131495 diff --git a/Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/4/NQ/Z9R3R8MQW9G5EO9PP83XSR.uasset b/Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/4/NQ/Z9R3R8MQW9G5EO9PP83XSR.uasset index e0fad16..0486244 100644 --- a/Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/4/NQ/Z9R3R8MQW9G5EO9PP83XSR.uasset +++ b/Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/4/NQ/Z9R3R8MQW9G5EO9PP83XSR.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9626873130faf87a21f2acc43c709ef6107f6ae405c62c8286a4e66d419dcf23 -size 6210 +oid sha256:58d4a9742469f202565406e5789980798f8d684d06c6e53ba72ff9a52701d096 +size 6786 diff --git a/Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/8/TK/ZQ7ASK35W30VGOG5S3CY8N.uasset b/Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/8/TK/ZQ7ASK35W30VGOG5S3CY8N.uasset new file mode 100644 index 0000000..ede3caf --- /dev/null +++ b/Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/8/TK/ZQ7ASK35W30VGOG5S3CY8N.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:19bb9a5195de64ea2c30bf65331aa12c6b930ba65a8d56ecd1fdced92db02080 +size 4307 diff --git a/Pawn_Unreal/Source/Pawn/Pawn.Build.cs b/Pawn_Unreal/Source/Pawn/Pawn.Build.cs index 4e321a7..0f2c38e 100644 --- a/Pawn_Unreal/Source/Pawn/Pawn.Build.cs +++ b/Pawn_Unreal/Source/Pawn/Pawn.Build.cs @@ -8,7 +8,11 @@ public class Pawn : ModuleRules { "Core", "CoreUObject", "Engine", - "InputCore" + "InputCore", + "EditorStyle", + "Slate", + "SlateCore", + "PropertyEditor" }); PrivateDependencyModuleNames.AddRange(new string[] { }); diff --git a/Pawn_Unreal/Source/Pawn/PawnModule.cpp b/Pawn_Unreal/Source/Pawn/PawnModule.cpp index 811c419..3c7e363 100644 --- a/Pawn_Unreal/Source/Pawn/PawnModule.cpp +++ b/Pawn_Unreal/Source/Pawn/PawnModule.cpp @@ -1,12 +1,24 @@ #include "PawnModule.h" + +#include "PropertyEditorModule.h" +#include "Interaction/PwnInteractableActor.h" +#include "Interaction/PwnInteractableActorCustomization.h" #include "Modules/ModuleManager.h" IMPLEMENT_PRIMARY_GAME_MODULE(FPawnModule, Pawn, "Pawn"); void FPawnModule::StartupModule() { - IModuleInterface::StartupModule(); + FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked("PropertyEditor"); + PropertyModule.RegisterCustomPropertyTypeLayout(FPwnInteractableActor::StaticStruct()->GetFName(), + FOnGetPropertyTypeCustomizationInstance::CreateStatic( + &UPwnInteractableActorCustomization::MakeInstance)); + PropertyModule.NotifyCustomizationModuleChanged(); } void FPawnModule::ShutdownModule() { - IModuleInterface::ShutdownModule(); + if (FModuleManager::Get().IsModuleLoaded("PropertyEditor")) { + FPropertyEditorModule& PropertyModule = FModuleManager::GetModuleChecked("PropertyEditor"); + PropertyModule.UnregisterCustomPropertyTypeLayout(FPwnInteractableActor::StaticStruct()->GetFName()); + PropertyModule.NotifyCustomizationModuleChanged(); + } } diff --git a/Pawn_Unreal/Source/Pawn/Private/Interaction/PwnInteractableActorCustomization.cpp b/Pawn_Unreal/Source/Pawn/Private/Interaction/PwnInteractableActorCustomization.cpp new file mode 100644 index 0000000..6498490 --- /dev/null +++ b/Pawn_Unreal/Source/Pawn/Private/Interaction/PwnInteractableActorCustomization.cpp @@ -0,0 +1,37 @@ +#include "Interaction/PwnInteractableActorCustomization.h" + +#include "PropertyCustomizationHelpers.h" +#include "PropertyHandle.h" +#include "Interaction/PwnInteractable.h" + +TSharedRef UPwnInteractableActorCustomization::MakeInstance() { + return MakeShareable(new UPwnInteractableActorCustomization()); +} + +void UPwnInteractableActorCustomization::CustomizeHeader(TSharedRef StructPropertyHandle, FDetailWidgetRow& HeaderRow, + IPropertyTypeCustomizationUtils& StructCustomizationUtils) { + const TSharedPtr 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 StructPropertyHandle, IDetailChildrenBuilder& StructBuilder, + IPropertyTypeCustomizationUtils& StructCustomizationUtils) { + // Do nothing +} + +bool UPwnInteractableActorCustomization::OnShouldFilterActor(const AActor* Actor) { + return Actor->GetClass()->ImplementsInterface(UPwnInteractable::StaticClass()); +} diff --git a/Pawn_Unreal/Source/Pawn/Private/Interaction/PwnTrigger.cpp b/Pawn_Unreal/Source/Pawn/Private/Interaction/PwnTrigger.cpp index 14cfc76..8c09aaf 100644 --- a/Pawn_Unreal/Source/Pawn/Private/Interaction/PwnTrigger.cpp +++ b/Pawn_Unreal/Source/Pawn/Private/Interaction/PwnTrigger.cpp @@ -5,6 +5,7 @@ UPwnTrigger::UPwnTrigger() { PrimaryComponentTick.bCanEverTick = false; + bAutoActivate = true; } void UPwnTrigger::BeginPlay() { @@ -29,6 +30,8 @@ void UPwnTrigger::OnOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActo const FHitResult& SweepResult) { if (UPwnTriggerRegister* Register = OtherActor->GetComponentByClass()) { Register->RegisterTrigger(this); + OnTriggerEnter.Broadcast(OtherActor); + ExecuteActions(EnterActions); } } @@ -36,6 +39,34 @@ void UPwnTrigger::OnOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* UPrimitiveComponent* OtherComp, int32 OtherBodyIndex) { if (UPwnTriggerRegister* Register = OtherActor->GetComponentByClass()) { 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; } + +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); + } +} diff --git a/Pawn_Unreal/Source/Pawn/Public/Interaction/PwnInteractable.h b/Pawn_Unreal/Source/Pawn/Public/Interaction/PwnInteractable.h new file mode 100644 index 0000000..7bcd2de --- /dev/null +++ b/Pawn_Unreal/Source/Pawn/Public/Interaction/PwnInteractable.h @@ -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); +}; diff --git a/Pawn_Unreal/Source/Pawn/Public/Interaction/PwnInteractableActor.h b/Pawn_Unreal/Source/Pawn/Public/Interaction/PwnInteractableActor.h new file mode 100644 index 0000000..ae33431 --- /dev/null +++ b/Pawn_Unreal/Source/Pawn/Public/Interaction/PwnInteractableActor.h @@ -0,0 +1,11 @@ +#pragma once + +#include "PwnInteractableActor.generated.h" + +USTRUCT(BlueprintType) +struct PAWN_API FPwnInteractableActor { + GENERATED_BODY() + + UPROPERTY(EditAnywhere) + FSoftObjectPath ActorReference; +}; diff --git a/Pawn_Unreal/Source/Pawn/Public/Interaction/PwnInteractableActorCustomization.h b/Pawn_Unreal/Source/Pawn/Public/Interaction/PwnInteractableActorCustomization.h new file mode 100644 index 0000000..400c555 --- /dev/null +++ b/Pawn_Unreal/Source/Pawn/Public/Interaction/PwnInteractableActorCustomization.h @@ -0,0 +1,17 @@ +#pragma once + +#include "IPropertyTypeCustomization.h" + +class PAWN_API UPwnInteractableActorCustomization : public IPropertyTypeCustomization { +public: + static TSharedRef MakeInstance(); + + virtual void CustomizeHeader(TSharedRef StructPropertyHandle, + FDetailWidgetRow& HeaderRow, + IPropertyTypeCustomizationUtils& StructCustomizationUtils) override; + + virtual void CustomizeChildren(TSharedRef StructPropertyHandle, + IDetailChildrenBuilder& StructBuilder, + IPropertyTypeCustomizationUtils& StructCustomizationUtils) override; + static bool OnShouldFilterActor(const AActor* Actor); +}; diff --git a/Pawn_Unreal/Source/Pawn/Public/Interaction/PwnTrigger.h b/Pawn_Unreal/Source/Pawn/Public/Interaction/PwnTrigger.h index d71df5e..e1473d0 100644 --- a/Pawn_Unreal/Source/Pawn/Public/Interaction/PwnTrigger.h +++ b/Pawn_Unreal/Source/Pawn/Public/Interaction/PwnTrigger.h @@ -1,19 +1,49 @@ #pragma once #include "CoreMinimal.h" +#include "PwnInteractable.h" +#include "PwnInteractableActor.h" #include "Components/ActorComponent.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 InteractionType; +}; + +USTRUCT(BlueprintType) +struct FInteractableActions { + GENERATED_BODY() + + UPROPERTY(EditAnywhere) + TArray Actions; + + UPROPERTY(EditAnywhere) + bool SelfInteract; + + UPROPERTY(EditAnywhere, meta=(EditCondition="SelfInteract", EditConditionHides)) + TEnumAsByte SelfInteractionType; +}; + UCLASS(ClassGroup="Interaction", - HideCategories=("Activation", "Cooking", "Replication", "Collision"), + HideCategories=("Cooking", "Replication", "Collision"), meta=(BlueprintSpawnableComponent, DisplayName="Trigger")) -class PAWN_API UPwnTrigger : public UActorComponent { +class PAWN_API UPwnTrigger : public UActorComponent, public IPwnInteractable { GENERATED_BODY() public: UPwnTrigger(); protected: + // Unreal Engine overrides virtual void BeginPlay() override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; @@ -26,10 +56,37 @@ protected: void OnOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex); + virtual void Activate(bool bReset) override; + + virtual void Deactivate() override; + // End of Unreal Engine overrides public: + // IPwnInteractable overrides + virtual void Interact_Implementation(const EInteractionType InteractionType) override; + // End of IPwnInteractable overrides + UFUNCTION() 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: UPROPERTY(EditAnywhere, meta=(UseComponentPicker, AllowedClasses="ShapeComponent")) FComponentReference TriggerVolume;