Refactor of interactable stuff, use the plugin and new interface for this, tweaks to SSGI shader so it's usable in game

This commit is contained in:
2026-09-03 23:40:00 +02:00
parent c13ad6c99f
commit 7327c7f98a
66 changed files with 229 additions and 186 deletions

View File

@@ -7,7 +7,6 @@
#include "Kismet/KismetMathLibrary.h"
#include "Kismet/GameplayStatics.h"
#include "EnhancedInputSubsystems.h"
#include "Interface/ZoneInteractableInterface.h"
#include "../GameObjects/RemovableStaticMeshActor.h"
#include "../Public/EleriPlayerController.h"
#include "../Public/MyCharacter.h"

View File

@@ -35,6 +35,9 @@ ABaseCharacter::ABaseCharacter()
PrimaryActorTick.bCanEverTick = true;
StateTreeComponent = CreateDefaultSubobject<UStateTreeAIComponent>("State Tree Component");
StateTreeComponent->SetStartLogicAutomatically(false);
WidgetComponent = CreateDefaultSubobject<UInteractionWidgetComponent>(TEXT("WidgetComponent"));
WidgetComponent->SetupAttachment(RootComponent);
}
// Called when the game starts or when spawned
@@ -113,9 +116,19 @@ void ABaseCharacter::ChangeFaceAnimation(EDialogueEmotion Emotion)
CurrentFaceFrameIndex = 0;
}
void ABaseCharacter::Interact_Implementation()
void ABaseCharacter::ToggleInteractableUI_Implementation(bool bActive)
{
IZoneInteractableInterface::Interact_Implementation();
if (bActive && !IInteractableActorInterface::Execute_IsInteractable(this))
{
return;
}
IInteractableActorInterface::ToggleInteractableUI_Implementation(bActive);
if (WidgetComponent)
{
WidgetComponent->ToggleWidget(bActive);
}
}
// Called every frame

View File

@@ -3,8 +3,9 @@
#pragma once
#include "CoreMinimal.h"
#include "Components/InteractionWidgetComponent.h"
#include "GameFramework/Pawn.h"
#include "ProjectEleri/Public/Interface/ZoneInteractableInterface.h"
#include "Interface/InteractableActorInterface.h"
#include "ProjectEleri/Public/Interface/NpcSpeakerDataInterface.h"
#include "ProjectEleri/Data/FaceExpressionDataAsset.h"
#include "StateTreeModule/Public/StateTree.h"
@@ -18,7 +19,7 @@ class UCapsuleComponent;
class USkeletalMeshComponent;
UCLASS(BlueprintType)
class PROJECTELERI_API ABaseCharacter : public APawn, public IZoneInteractableInterface, public INpcSpeakerDataInterface
class PROJECTELERI_API ABaseCharacter : public APawn, public IInteractableActorInterface, public INpcSpeakerDataInterface
{
GENERATED_BODY()
@@ -39,8 +40,7 @@ public:
UFUNCTION(BlueprintCallable, BlueprintPure)
UCapsuleComponent* GetCapsuleComponent() { return Capsule; }
virtual FText GetInteractionText_Implementation() override { return FText::FromString("Talk"); }
virtual void Interact_Implementation() override;
virtual void ToggleInteractableUI_Implementation(bool bActive) override;
protected:
UPROPERTY(Category = Character, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
@@ -62,6 +62,9 @@ protected:
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Movement")
UExtendedPawnMovement* MovementComponent;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
UInteractionWidgetComponent* WidgetComponent;
// Called when the game starts or when spawned
virtual void BeginPlay() override;

View File

@@ -10,6 +10,12 @@ AEleriBaseActor::AEleriBaseActor()
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
PersistentId = FGuid::NewGuid();
RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent"));
SetRootComponent(RootComponent);
WidgetComponent = CreateDefaultSubobject<UInteractionWidgetComponent>(TEXT("WidgetComponent"));
WidgetComponent->SetupAttachment(RootComponent);
}
// Called when the game starts or when spawned
@@ -69,6 +75,21 @@ void AEleriBaseActor::RequestLoad(FActorSaveData& Data)
ISaveableObjectInterface::Execute_OnDataLoaded(this);
}
void AEleriBaseActor::ToggleInteractableUI_Implementation(bool bActive)
{
if (bActive && !IInteractableActorInterface::Execute_IsInteractable(this))
{
return;
}
IInteractableActorInterface::ToggleInteractableUI_Implementation(bActive);
if (WidgetComponent)
{
WidgetComponent->ToggleWidget(bActive);
}
}
void AEleriBaseActor::OnDataLoaded_Implementation() {}

View File

@@ -7,6 +7,8 @@
#include "ProjectEleri/Public/Interface/SaveableObjectInterface.h"
#include "ProjectEleri/Public/Interface/ActorPersistentIdInterface.h"
#include "GameplayTagContainer.h"
#include "Components/InteractionWidgetComponent.h"
#include "Interface/InteractableActorInterface.h"
#include "EleriBaseActor.generated.h"
@@ -14,7 +16,8 @@ UCLASS()
class PROJECTELERI_API AEleriBaseActor :
public AActor,
public ISaveableObjectInterface,
public IActorPersistentIdInterface
public IActorPersistentIdInterface,
public IInteractableActorInterface
{
GENERATED_BODY()
@@ -29,6 +32,8 @@ public:
virtual void RequestLoad(FActorSaveData &Data) override;
virtual FGuid GetPersistentId() const override { return PersistentId; }
virtual void ToggleInteractableUI_Implementation(bool bActive) override;
protected:
virtual void OnDataLoaded_Implementation() override;
@@ -43,6 +48,9 @@ protected:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "ID")
FGuid PersistentId;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
UInteractionWidgetComponent* WidgetComponent;
UFUNCTION(BlueprintCallable, Category = "Saveable Tag Data", meta = (GameplayTagFilter = "SaveGameTags"))
void SetSaveableTagData(FGameplayTag Tag, int32 NewValue);

View File

@@ -13,6 +13,12 @@
ARemovableStaticMeshActor::ARemovableStaticMeshActor()
{
PrimaryActorTick.bCanEverTick = true;
RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent"));
SetRootComponent(RootComponent);
WidgetComponent = CreateDefaultSubobject<UInteractionWidgetComponent>(TEXT("WidgetComponent"));
WidgetComponent->SetupAttachment(RootComponent);
}
void ARemovableStaticMeshActor::BeginPlay()
@@ -29,6 +35,26 @@ void ARemovableStaticMeshActor::BeginPlay()
CurrentMemorizedTransform = GetActorTransform();
}
void ARemovableStaticMeshActor::ToggleInteractableUI_Implementation(bool bActive)
{
if (bActive && !IInteractableActorInterface::Execute_IsInteractable(this))
{
return;
}
IInteractableActorInterface::ToggleInteractableUI_Implementation(bActive);
if (WidgetComponent)
{
WidgetComponent->ToggleWidget(bActive);
}
}
bool ARemovableStaticMeshActor::IsInteractable_Implementation() const
{
return true;
}
void ARemovableStaticMeshActor::BindToItem(UInventoryComponent* InInventory, FItemStack InItemStack)
{
InventoryRef = InInventory;

View File

@@ -5,6 +5,8 @@
#include "CoreMinimal.h"
#include "Engine/StaticMeshActor.h"
#include "../Public/InventoryComponent.h"
#include "Components/InteractionWidgetComponent.h"
#include "Interface/InteractableActorInterface.h"
#include "RemovableStaticMeshActor.generated.h"
@@ -17,7 +19,7 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnPickup);
*
*/
UCLASS(BlueprintType)
class PROJECTELERI_API ARemovableStaticMeshActor : public AStaticMeshActor
class PROJECTELERI_API ARemovableStaticMeshActor : public AStaticMeshActor, public IInteractableActorInterface
{
GENERATED_BODY()
@@ -26,6 +28,9 @@ public:
ARemovableStaticMeshActor();
virtual void BeginPlay() override;
virtual void ToggleInteractableUI_Implementation(bool bActive) override;
virtual bool IsInteractable_Implementation() const override;
UPROPERTY()
bool bFromInventory;
@@ -84,6 +89,9 @@ public:
FOnPlaced OnPlaced;
UPROPERTY(BlueprintAssignable, EditAnywhere, BLueprintReadWrite)
FOnPickup OnPickup;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
UInteractionWidgetComponent* WidgetComponent;
//Used when placing stuff from inventory so we can return it to inventory
//if we cancel placing item
@@ -106,4 +114,6 @@ public:
UFUNCTION(BlueprintImplementableEvent, BlueprintCallable)
void K2_TogglePlaceableEffects(bool bIsPlaceable);
};

View File

@@ -2,15 +2,12 @@
#include "EleriPlayerController.h"
#include "EnhancedInputComponent.h"
#include "Kismet/KismetMathLibrary.h"
#include "GameFramework/Character.h"
#include "EnhancedInputSubsystems.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Interface/ZoneInteractableInterface.h"
#include "ProjectEleri/System/MainBlueprintFunctionLibrary.h"
#include "ProjectEleri/Components/MoveActorsComponent.h"
#include "../GameObjects/RemovableStaticMeshActor.h"
#include "Components/WidgetComponent.h"
#include "Kismet/GameplayStatics.h"
#include "BookOfAlchemyManager.h"
#include "AlchemyManager.h"
@@ -76,7 +73,7 @@ void AEleriPlayerController::Tick(float DeltaTime)
{
for (int32 i = 0; i < ActorsOverlappingWith.Num(); i++)
{
if (!ActorsOverlappingWith[i]->Implements<UZoneInteractableInterface>() || !IZoneInteractableInterface::Execute_IsInteractable(ActorsOverlappingWith[i]))
if (!ActorsOverlappingWith[i]->Implements<UInteractableActorInterface>() || !IInteractableActorInterface::Execute_IsInteractable(ActorsOverlappingWith[i]))
{
RemoveInteractableObject(ActorsOverlappingWith[i]);
i--;
@@ -680,16 +677,15 @@ void AEleriPlayerController::OnToggleGridAction(const FInputActionValue &Value)
void AEleriPlayerController::AddInteractableObject(UObject *ObjectToAdd)
{
if (IsValid(ObjectToAdd) && ObjectToAdd->Implements<UZoneInteractableInterface>() && IZoneInteractableInterface::Execute_IsInteractable(ObjectToAdd))
if (IsValid(ObjectToAdd) && ObjectToAdd->Implements<UInteractableActorInterface>() && IInteractableActorInterface::Execute_IsInteractable(ObjectToAdd))
{
FText InteractableText = IZoneInteractableInterface::Execute_GetInteractionText(ObjectToAdd);
FText InteractableText = IInteractableActorInterface::Execute_GetInteractionText(ObjectToAdd);
if (UMainGameWidget *MainWidget = UMainBlueprintFunctionLibrary::GetMainGameWidget(this))
{
if (UInteractionWidget *InteractionWidget = MainWidget->GetInteractionWidget())
{
InteractionWidget->PushInteractableObject(ObjectToAdd, InteractableText);
}
IZoneInteractableInterface::Execute_PlayerEntered(ObjectToAdd, true);
}
ActorsOverlappingWith.Add(ObjectToAdd);
}
@@ -708,9 +704,9 @@ void AEleriPlayerController::RemoveInteractableObject(UObject *ObjectToAdd)
if (IsPaused())
return;
if (IsValid(ObjectToAdd) && ObjectToAdd->Implements<UZoneInteractableInterface>())
if (IsValid(ObjectToAdd) && ObjectToAdd->Implements<UInteractableActorInterface>())
{
FText InteractableText = IZoneInteractableInterface::Execute_GetInteractionText(ObjectToAdd);
FText InteractableText = IInteractableActorInterface::Execute_GetInteractionText(ObjectToAdd);
if (UMainGameWidget *MainWidget = UMainBlueprintFunctionLibrary::GetMainGameWidget(this))
{
if (UInteractionWidget *InteractionWidget = MainWidget->GetInteractionWidget())
@@ -718,7 +714,6 @@ void AEleriPlayerController::RemoveInteractableObject(UObject *ObjectToAdd)
InteractionWidget->PopInteractableObject(ObjectToAdd);
}
}
IZoneInteractableInterface::Execute_PlayerEntered(ObjectToAdd, false);
}
ActorsOverlappingWith.Remove(ObjectToAdd);
if (SelectedInteractable == ObjectToAdd)
@@ -756,14 +751,7 @@ void AEleriPlayerController::ToggleInteractionMenu(bool bActive)
void AEleriPlayerController::OnInteractionMenuSelectAction(const FInputActionValue &Value)
{
if (SelectedInteractable)
{
IZoneInteractableInterface::Execute_Interact(SelectedInteractable);
if (!IZoneInteractableInterface::Execute_KeepInteractionMenuOpenWhenSelected(SelectedInteractable))
{
ToggleInteractionMenu(false);
}
}
}
void AEleriPlayerController::OnInteractionMenuUpAction(const FInputActionValue &Value)

View File

@@ -1,7 +0,0 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "Interface/ZoneInteractableInterface.h"
// Add default functionality here for any IZoneInteractableIntereface functions that are not pure virtual.

View File

@@ -4,20 +4,14 @@
#include "MyCharacter.h"
#include "EleriPlayerController.h"
#include "Kismet/GameplayStatics.h"
#include "Interface/ZoneInteractableInterface.h"
#include "EleriSaveGame.h"
#include "EleriGameInstance.h"
#include "PaperFlipbookComponent.h"
#include "Kismet/KismetMathLibrary.h"
#include "../GameObjects/WaterBall.h"
#include "ProjectEleri/GameObjects/BookActor.h"
#include "TimeOfDayManager.h"
#include "Components/PostProcessComponent.h"
#include "GameFramework/PawnMovementComponent.h"
#include "ProjectEleri/GameObjects/BenchmarkActor.h"
#include "ProjectEleri/System/MainBlueprintFunctionLibrary.h"
#include "ProjectEleri/UI/InteractionWidget.h"
#include "ProjectEleri/GameObjects/BookActor.h"
#include "ProjectEleri/GameObjects/BroomActor.h"
#include "Components/CapsuleComponent.h"
#include "Components/StatForgeComponent.h"

View File

@@ -56,6 +56,9 @@ ATimeOfDayManager::ATimeOfDayManager()
WeatherPresetDistributionMap.GetKeys(Keys);
CurrentWeatherPreset = Keys[0];
}
WidgetComponent = CreateDefaultSubobject<UInteractionWidgetComponent>(TEXT("WidgetComponent"));
WidgetComponent->SetupAttachment(RootComponent);
}
// Called when the game starts or when spawned
@@ -566,6 +569,21 @@ void ATimeOfDayManager::LoadSaveData(const FTimeOfDaySaveData &saveData)
QueuedWeatherPreset = Cast<UWeatherPresetDataAsset>(saveData.CurrentWeatherSoftObjectPath.TryLoad());
}
void ATimeOfDayManager::ToggleInteractableUI_Implementation(bool bActive)
{
if (bActive && !IInteractableActorInterface::Execute_IsInteractable(this))
{
return;
}
IInteractableActorInterface::ToggleInteractableUI_Implementation(bActive);
if (WidgetComponent)
{
WidgetComponent->ToggleWidget(bActive);
}
}
int32 ATimeOfDayManager::GetWeatherDistributionMaxValue() const
{
float Value = 0;

View File

@@ -1,44 +0,0 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "ZoneInteractableInterface.generated.h"
// This class does not need to be modified.
UINTERFACE(MinimalAPI, Blueprintable)
class UZoneInteractableInterface : public UInterface
{
GENERATED_BODY()
};
/**
*
*/
class PROJECTELERI_API IZoneInteractableInterface
{
GENERATED_BODY()
// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
/**A version of React To Trigger that can be implemented in C++ or Blueprint. */
UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
void Interact();
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
bool IsInteractable();
virtual bool IsInteractable_Implementation() { return true; }
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
bool KeepInteractionMenuOpenWhenSelected();
virtual bool KeepInteractionMenuOpenWhenSelected_Implementation() { return false; }
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
FText GetInteractionText();
virtual FText GetInteractionText_Implementation() { return FText(); }
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
void PlayerEntered(bool bIsPlayerInside);
};

View File

@@ -15,8 +15,10 @@
#include "UObject/NameTypes.h"
#include "../Items/ItemDatabase.h"
#include "GameplayTagContainer.h"
#include "Components/InteractionWidgetComponent.h"
#include "Components/VolumetricCloudComponent.h"
#include "Engine/ExponentialHeightFog.h"
#include "Interface/InteractableActorInterface.h"
#include "ProjectEleri/GameEventSystem/GameEventDataAsset.h"
#include "ProjectEleri/System/TimeOfDayStruct.h"
@@ -103,7 +105,7 @@ public:
};
UCLASS()
class PROJECTELERI_API ATimeOfDayManager : public AActor
class PROJECTELERI_API ATimeOfDayManager : public AActor, public IInteractableActorInterface
{
GENERATED_BODY()
@@ -322,6 +324,8 @@ public:
FTimeOfDaySaveData GetSaveData() const;
void LoadSaveData(const FTimeOfDaySaveData &saveData);
virtual void ToggleInteractableUI_Implementation(bool bActive) override;
protected:
// Called when the game starts or when spawned
@@ -359,6 +363,9 @@ protected:
TMap<UWeatherPresetDataAsset *, float> WeatherPresetDistributionMap;
UPROPERTY()
UMaterialInstanceDynamic* VolumetricCloudMaterialInstance;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
UInteractionWidgetComponent* WidgetComponent;
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite)