Base interaction system, widgets manager, fixes

This commit is contained in:
Oleg Petruny 2024-05-08 22:46:00 +02:00
parent 9a2b717742
commit cbc92f6217
27 changed files with 596 additions and 130 deletions

View File

@ -73,3 +73,61 @@ ConnectionType=USBOnly
bUseManualIPAddress=False
ManualIPAddress=
[/Script/Engine.CollisionProfile]
-Profiles=(Name="NoCollision",CollisionEnabled=NoCollision,ObjectTypeName="WorldStatic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore)),HelpMessage="No collision",bCanModify=False)
-Profiles=(Name="BlockAll",CollisionEnabled=QueryAndPhysics,ObjectTypeName="WorldStatic",CustomResponses=,HelpMessage="WorldStatic object that blocks all actors by default. All new custom channels will use its own default response. ",bCanModify=False)
-Profiles=(Name="OverlapAll",CollisionEnabled=QueryOnly,ObjectTypeName="WorldStatic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Overlap),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldStatic object that overlaps all actors by default. All new custom channels will use its own default response. ",bCanModify=False)
-Profiles=(Name="BlockAllDynamic",CollisionEnabled=QueryAndPhysics,ObjectTypeName="WorldDynamic",CustomResponses=,HelpMessage="WorldDynamic object that blocks all actors by default. All new custom channels will use its own default response. ",bCanModify=False)
-Profiles=(Name="OverlapAllDynamic",CollisionEnabled=QueryOnly,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Overlap),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldDynamic object that overlaps all actors by default. All new custom channels will use its own default response. ",bCanModify=False)
-Profiles=(Name="IgnoreOnlyPawn",CollisionEnabled=QueryOnly,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that ignores Pawn and Vehicle. All other channels will be set to default.",bCanModify=False)
-Profiles=(Name="OverlapOnlyPawn",CollisionEnabled=QueryOnly,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Pawn",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that overlaps Pawn, Camera, and Vehicle. All other channels will be set to default. ",bCanModify=False)
-Profiles=(Name="Pawn",CollisionEnabled=QueryAndPhysics,ObjectTypeName="Pawn",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Pawn object. Can be used for capsule of any playerable character or AI. ",bCanModify=False)
-Profiles=(Name="Spectator",CollisionEnabled=QueryOnly,ObjectTypeName="Pawn",CustomResponses=((Channel="WorldStatic",Response=ECR_Block),(Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore),(Channel="WorldDynamic",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore),(Channel="PhysicsBody",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Destructible",Response=ECR_Ignore)),HelpMessage="Pawn object that ignores all other actors except WorldStatic.",bCanModify=False)
-Profiles=(Name="CharacterMesh",CollisionEnabled=QueryOnly,ObjectTypeName="Pawn",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Pawn object that is used for Character Mesh. All other channels will be set to default.",bCanModify=False)
-Profiles=(Name="PhysicsActor",CollisionEnabled=QueryAndPhysics,ObjectTypeName="PhysicsBody",CustomResponses=,HelpMessage="Simulating actors",bCanModify=False)
-Profiles=(Name="Destructible",CollisionEnabled=QueryAndPhysics,ObjectTypeName="Destructible",CustomResponses=,HelpMessage="Destructible actors",bCanModify=False)
-Profiles=(Name="InvisibleWall",CollisionEnabled=QueryAndPhysics,ObjectTypeName="WorldStatic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="WorldStatic object that is invisible.",bCanModify=False)
-Profiles=(Name="InvisibleWallDynamic",CollisionEnabled=QueryAndPhysics,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that is invisible.",bCanModify=False)
-Profiles=(Name="Trigger",CollisionEnabled=QueryOnly,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Ignore),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldDynamic object that is used for trigger. All other channels will be set to default.",bCanModify=False)
-Profiles=(Name="Ragdoll",CollisionEnabled=QueryAndPhysics,ObjectTypeName="PhysicsBody",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Simulating Skeletal Mesh Component. All other channels will be set to default.",bCanModify=False)
-Profiles=(Name="Vehicle",CollisionEnabled=QueryAndPhysics,ObjectTypeName="Vehicle",CustomResponses=,HelpMessage="Vehicle object that blocks Vehicle, WorldStatic, and WorldDynamic. All other channels will be set to default.",bCanModify=False)
-Profiles=(Name="UI",CollisionEnabled=QueryOnly,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Block),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldStatic object that overlaps all actors by default. All new custom channels will use its own default response. ",bCanModify=False)
+Profiles=(Name="NoCollision",CollisionEnabled=NoCollision,bCanModify=False,ObjectTypeName="WorldStatic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore)),HelpMessage="No collision")
+Profiles=(Name="BlockAll",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="WorldStatic",CustomResponses=,HelpMessage="WorldStatic object that blocks all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="OverlapAll",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldStatic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Overlap),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldStatic object that overlaps all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="BlockAllDynamic",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=,HelpMessage="WorldDynamic object that blocks all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="OverlapAllDynamic",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Overlap),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldDynamic object that overlaps all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="IgnoreOnlyPawn",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that ignores Pawn and Vehicle. All other channels will be set to default.")
+Profiles=(Name="OverlapOnlyPawn",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Pawn",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that overlaps Pawn, Camera, and Vehicle. All other channels will be set to default. ")
+Profiles=(Name="Pawn",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="Pawn",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Pawn object. Can be used for capsule of any playerable character or AI. ")
+Profiles=(Name="Spectator",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="Pawn",CustomResponses=((Channel="WorldStatic"),(Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore),(Channel="WorldDynamic",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore),(Channel="PhysicsBody",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Destructible",Response=ECR_Ignore)),HelpMessage="Pawn object that ignores all other actors except WorldStatic.")
+Profiles=(Name="CharacterMesh",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="Pawn",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Pawn object that is used for Character Mesh. All other channels will be set to default.")
+Profiles=(Name="PhysicsActor",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="PhysicsBody",CustomResponses=,HelpMessage="Simulating actors")
+Profiles=(Name="Destructible",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="Destructible",CustomResponses=,HelpMessage="Destructible actors")
+Profiles=(Name="InvisibleWall",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="WorldStatic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="WorldStatic object that is invisible.")
+Profiles=(Name="InvisibleWallDynamic",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that is invisible.")
+Profiles=(Name="Trigger",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Ignore),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldDynamic object that is used for trigger. All other channels will be set to default.")
+Profiles=(Name="Ragdoll",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="PhysicsBody",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Simulating Skeletal Mesh Component. All other channels will be set to default.")
+Profiles=(Name="Vehicle",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="Vehicle",CustomResponses=,HelpMessage="Vehicle object that blocks Vehicle, WorldStatic, and WorldDynamic. All other channels will be set to default.")
+Profiles=(Name="UI",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility"),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldStatic object that overlaps all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="Interactable",CollisionEnabled=QueryAndPhysics,bCanModify=True,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Interactable")),HelpMessage="WorldDynamic objects derived from AInteractable.")
+DefaultChannelResponses=(Channel=ECC_GameTraceChannel1,DefaultResponse=ECR_Ignore,bTraceType=True,bStaticObject=False,Name="Interactable")
-ProfileRedirects=(OldName="BlockingVolume",NewName="InvisibleWall")
-ProfileRedirects=(OldName="InterpActor",NewName="IgnoreOnlyPawn")
-ProfileRedirects=(OldName="StaticMeshComponent",NewName="BlockAllDynamic")
-ProfileRedirects=(OldName="SkeletalMeshActor",NewName="PhysicsActor")
-ProfileRedirects=(OldName="InvisibleActor",NewName="InvisibleWallDynamic")
+ProfileRedirects=(OldName="BlockingVolume",NewName="InvisibleWall")
+ProfileRedirects=(OldName="InterpActor",NewName="IgnoreOnlyPawn")
+ProfileRedirects=(OldName="StaticMeshComponent",NewName="BlockAllDynamic")
+ProfileRedirects=(OldName="SkeletalMeshActor",NewName="PhysicsActor")
+ProfileRedirects=(OldName="InvisibleActor",NewName="InvisibleWallDynamic")
-CollisionChannelRedirects=(OldName="Static",NewName="WorldStatic")
-CollisionChannelRedirects=(OldName="Dynamic",NewName="WorldDynamic")
-CollisionChannelRedirects=(OldName="VehicleMovement",NewName="Vehicle")
-CollisionChannelRedirects=(OldName="PawnMovement",NewName="Pawn")
+CollisionChannelRedirects=(OldName="Static",NewName="WorldStatic")
+CollisionChannelRedirects=(OldName="Dynamic",NewName="WorldDynamic")
+CollisionChannelRedirects=(OldName="VehicleMovement",NewName="Vehicle")
+CollisionChannelRedirects=(OldName="PawnMovement",NewName="Pawn")

Binary file not shown.

View File

@ -4,17 +4,18 @@
#include "CameraModeBase.h"
#include "Camera/CameraComponent.h"
#include "CustomGameUserSettings.h"
#include "EnhancedInputSubsystems.h"
#include "GameFramework/Character.h"
#include "GameFramework/PawnMovementComponent.h"
#include "InputMappingContext.h"
#include "Kismet/GameplayStatics.h"
#include "CustomGameUserSettings.h"
#include "MainGameModeBase.h"
ACameraModeBase::ACameraModeBase()
{
PrimaryActorTick.bCanEverTick = true;
}
void ACameraModeBase::BeginPlay()

View File

@ -4,7 +4,6 @@
#include "CoreMinimal.h"
#include "GameFramework/SpectatorPawn.h"
#include "InputMappingContext.h"
#include "CameraModeBase.generated.h"
@ -31,7 +30,7 @@ protected:
void SwitchRun(bool run);
UPROPERTY(EditDefaultsOnly)
TSoftObjectPtr<UInputMappingContext> inputMapping;
TSoftObjectPtr<class UInputMappingContext> inputMapping;
UPROPERTY(EditDefaultsOnly)
float moveSpeed = 200;

View File

@ -3,11 +3,17 @@
#include "CustomGameInstanceBase.h"
#include "CustomGameUserSettings.h"
#include "EnhancedInputLibrary.h"
#include "InputMappingContext.h"
#include "CustomGameUserSettings.h"
#include "Interactable/UsableInteractable.h"
void UCustomGameInstanceBase::Init()
{
// IN FUTURE ASSIGN FROM CONTENT LOADER MEMBER
interactionsCollection = { {UUsableInteractable::StaticClass()} };
UGameInstance::Init();
ApplyMouseSettings();

View File

@ -4,7 +4,6 @@
#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "InputMappingContext.h"
#include "CustomGameInstanceBase.generated.h"
@ -19,7 +18,9 @@ public:
UFUNCTION(BlueprintCallable, Category = Settings)
void ApplyMouseSettings();
TArray<TSubclassOf<class UInteractableComponent>> interactionsCollection;
protected:
UPROPERTY(EditDefaultsOnly)
TArray<TSoftObjectPtr<UInputMappingContext>> defaultInputContexts;
TArray<TSoftObjectPtr<class UInputMappingContext>> defaultInputContexts;
};

View File

@ -3,7 +3,6 @@
#include "CustomGameUserSettings.h"
#include "CustomGameInstanceBase.h"
#include "Kismet/GameplayStatics.h"
UCustomGameUserSettings::UCustomGameUserSettings(const FObjectInitializer& ObjectInitializer) :Super(ObjectInitializer)

View File

@ -0,0 +1,6 @@
// Oleg Petruny proprietary.
#include "Interactable.h"

View File

@ -0,0 +1,22 @@
// Oleg Petruny proprietary.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "UObject/ScriptInterface.h"
#include "Interactable.generated.h"
UCLASS(Abstract, MinimalAPI, Blueprintable, BlueprintType)
class AInteractable : public AActor
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
TArray<TSubclassOf<class UInteractableComponent>> GetInteractableComponents();
virtual TArray<TSubclassOf<class UInteractableComponent>> GetInteractableComponents_Implementation()
PURE_VIRTUAL(AInteractable::GetInteractableComponents_Implementation, return {};);
};

View File

@ -0,0 +1,59 @@
// Oleg Petruny proprietary.
#include "InteractableActivator.h"
#include "Engine/CollisionProfile.h"
#include "PlayerBase.h"
UInteractableActivator::UInteractableActivator(const FObjectInitializer& ObjectInitializer)
: USceneComponent(ObjectInitializer)
{
if(HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject))
{
return;
}
world = GetWorld();
player = Cast<APlayerBase>(GetOwner());
collisionChannel = ECC_GameTraceChannel1;
if(auto collisions = UCollisionProfile::Get())
{
for(int32 i = 0; i < ECC_MAX; ++i)
{
if(collisions->ReturnChannelNameFromContainerIndex(i) == FName{ TEXT("Interactable") })
{
collisionChannel = (ECollisionChannel)i;
break;
}
}
}
if(!world || !player || collisionChannel == ECC_MAX)
{
DestroyComponent();
return;
}
PrimaryComponentTick.TickInterval = 0.05f;
PrimaryComponentTick.bCanEverTick = true;
PrimaryComponentTick.bStartWithTickEnabled = true;
RegisterComponent();
}
void UInteractableActivator::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
USceneComponent::TickComponent(DeltaTime, TickType, ThisTickFunction);
switch(TickType)
{
case ELevelTick::LEVELTICK_TimeOnly:
case ELevelTick::LEVELTICK_ViewportsOnly:
case ELevelTick::LEVELTICK_All:
Scan_Implementation();
break;
default:
break;
}
}

View File

@ -0,0 +1,34 @@
// Oleg Petruny proprietary.
#pragma once
#include "Components/SceneComponent.h"
#include "CoreMinimal.h"
#include "InteractableActivator.generated.h"
DECLARE_DELEGATE(FInteractableActivated);
UCLASS(Blueprintable, BlueprintType)
class UInteractableActivator : public USceneComponent
{
GENERATED_BODY()
public:
UInteractableActivator(const FObjectInitializer& ObjectInitializer);
virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
protected:
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
inline void Scan();
inline virtual void Scan_Implementation() PURE_VIRTUAL(UInteractableActivator::Scan_Implementation, );
UPROPERTY(EditDefaultsOnly)
float scanDistance = 200;
class UWorld* world;
class APlayerBase* player;
bool isTrace = true;
enum ECollisionChannel collisionChannel;
FInteractableActivated interactableActivatedDelegate;
};

View File

@ -0,0 +1,6 @@
// Oleg Petruny proprietary.
#include "InteractableCaller.h"

View File

@ -0,0 +1,17 @@
// Oleg Petruny proprietary.
#pragma once
#include "Components/ActorComponent.h"
#include "CoreMinimal.h"
#include "InteractableCaller.generated.h"
UCLASS(Abstract, MinimalAPI, Blueprintable, BlueprintType)
class UInteractableCaller : public UActorComponent
{
GENERATED_BODY()
public:
};

View File

@ -0,0 +1,6 @@
// Oleg Petruny proprietary.
#include "InteractableComponent.h"
// Add default functionality here for any IInteractableInterface functions that are not pure virtual.

View File

@ -0,0 +1,54 @@
// Oleg Petruny proprietary.
#pragma once
#include "CoreMinimal.h"
#include "InputMappingContext.h"
#include "UObject/Interface.h"
#include "InteractableActivator.h"
#include "InteractableCaller.h"
#include "InteractableComponent.generated.h"
USTRUCT(BlueprintType)
struct FActivatorCallerPair
{
GENERATED_BODY()
public:
FActivatorCallerPair() {}
FActivatorCallerPair(TSubclassOf<UInteractableActivator> a, TSubclassOf<UInteractableCaller> c)
: activator(a), caller(c)
{}
UPROPERTY(EditAnywhere)
TSubclassOf<UInteractableActivator> activator;
UPROPERTY(EditAnywhere)
TSubclassOf<UInteractableCaller> caller;
};
UCLASS()
class UInteractableComponent : public UActorComponent
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
const FString GetName();
virtual const FString GetName_Implementation()
PURE_VIRTUAL(UInteractableComponent::GetInteractionName_Implementation, return "NONE";);
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
const UInputMappingContext* GetInputMapping();
virtual const UInputMappingContext* GetInputMapping_Implementation()
PURE_VIRTUAL(UInteractableComponent::GetInputMapping_Implementation, static UInputMappingContext _inputMapping{}; return &_inputMapping;);
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
const TArray<FActivatorCallerPair> GetActivatorsAndCallers();
virtual const TArray<FActivatorCallerPair> GetActivatorsAndCallers_Implementation()
PURE_VIRTUAL(UInteractableComponent::GetActivatorsAndCallers_Implementation,
TArray<FActivatorCallerPair> _activatorsAndCallers{}; return _activatorsAndCallers;);
};

View File

@ -0,0 +1,26 @@
// Oleg Petruny proprietary.
#include "RaycastInteractableActivator.h"
#include "DrawDebugHelpers.h"
#include "Engine/World.h"
void URaycastInteractableActivator::Scan_Implementation()
{
FHitResult result{};
FVector startLocation = GetComponentLocation();
FVector endLocation = startLocation + (GetComponentRotation().Vector() * scanDistance);
world->LineTraceSingleByChannel(
result,
startLocation,
endLocation,
collisionChannel
);
if(result.bBlockingHit)
DrawDebugLine(GetWorld(), startLocation, endLocation, FColor::Green, false, 0.5f, 0, 1.0f);
else
DrawDebugLine(GetWorld(), startLocation, endLocation, FColor::Red, false, 0.5f, 10, 1.0f);
}

View File

@ -0,0 +1,18 @@
// Oleg Petruny proprietary.
#pragma once
#include "CoreMinimal.h"
#include "InteractableActivator.h"
#include "RaycastInteractableActivator.generated.h"
UCLASS(Blueprintable, BlueprintType)
class URaycastInteractableActivator : public UInteractableActivator
{
GENERATED_BODY()
protected:
void Scan();
virtual void Scan_Implementation() override;
};

View File

@ -0,0 +1,27 @@
// Oleg Petruny proprietary.
#include "UsableInteractable.h"
#include "InteractableCaller.h"
#include "RaycastInteractableActivator.h"
const FString UUsableInteractable::GetName_Implementation()
{
static auto _name = TEXT("Use");
return _name;
}
const UInputMappingContext* UUsableInteractable::GetInputMapping_Implementation()
{
static auto _mapping = UInputMappingContext{};
return &_mapping;
}
const TArray<FActivatorCallerPair> UUsableInteractable::GetActivatorsAndCallers_Implementation()
{
static TArray<FActivatorCallerPair> _array = {
{{URaycastInteractableActivator::StaticClass()}, {UInteractableCaller::StaticClass()}}
};
return _array;
}

View File

@ -0,0 +1,26 @@
// Oleg Petruny proprietary.
#pragma once
#include "CoreMinimal.h"
#include "InteractableComponent.h"
#include "UsableInteractable.generated.h"
UCLASS()
class UUsableInteractable : public UInteractableComponent
{
GENERATED_BODY()
public:
const FString GetName();
virtual const FString GetName_Implementation() override;
const UInputMappingContext* GetInputMapping();
virtual const UInputMappingContext* GetInputMapping_Implementation() override;
const TArray<FActivatorCallerPair> GetActivatorsAndCallers();
virtual const TArray<FActivatorCallerPair> GetActivatorsAndCallers_Implementation() override;
};

View File

@ -6,23 +6,32 @@
#include "Engine/World.h"
#include "GameFramework/SpectatorPawn.h"
#include "Kismet/GameplayStatics.h"
#include "UObject/ScriptInterface.h"
#include "CustomGameInstanceBase.h"
#include "Interactable/InteractableComponent.h"
#include "WidgetsManager.h"
void AMainGameModeBase::StartPlay()
{
AGameModeBase::StartPlay();
InstantiateOverlayWidgets();
_widgetsManager = NewObject<UWidgetsManager>(this, widgetManagerClass);
_widgetsManager->Init();
}
bool AMainGameModeBase::SetPause(APlayerController* PC, FCanUnpause CanUnpauseDelegate)
{
if(IsPaused())
if(_widgetsManager)
{
HideOverlayWidgets();
}
else
{
ShowOverlayWidgets();
if(IsPaused())
{
_widgetsManager->HideOverlayWidgets();
}
else
{
_widgetsManager->ShowOverlayWidgets();
}
}
return AGameModeBase::SetPause(PC, CanUnpauseDelegate);
@ -36,7 +45,7 @@ void AMainGameModeBase::SwitchCameraMode()
{
if(auto pawn = PC->GetPawn())
{
if(_playerPawn.IsValid())
if(!_playerPawn.IsValid())
{
auto spawnLoc = pawn->GetActorLocation();
auto spawnRot = pawn->GetActorRotation();
@ -55,71 +64,8 @@ void AMainGameModeBase::SwitchCameraMode()
}
}
UpdateOverlayWidgetsOwner();
}
void AMainGameModeBase::InstantiateOverlayWidgets()
{
if(auto PC = UGameplayStatics::GetPlayerController(GetWorld(), 0))
if(_widgetsManager)
{
for(auto widget : permaOverlayWidgets)
{
if(auto instance = CreateWidget<UUserWidget>(PC, widget))
{
permaOverlayWidgetsInstances.Add(instance);
instance->AddToViewport();
}
}
for(auto widget : overlayWidgets)
{
if(auto instance = CreateWidget<UUserWidget>(PC, widget))
{
overlayWidgetsInstances.Add(instance);
instance->AddToViewport();
}
}
_widgetsManager->UpdateOverlayWidgetsOwner();
}
}
void AMainGameModeBase::HideOverlayWidgets()
{
for(auto widget : overlayWidgetsInstances)
{
if(widget.IsValid())
{
widget->SetVisibility(ESlateVisibility::Hidden);
}
}
}
void AMainGameModeBase::ShowOverlayWidgets()
{
for(auto widget : overlayWidgetsInstances)
{
if(widget.IsValid())
{
widget->SetVisibility(ESlateVisibility::Visible);
}
}
}
void AMainGameModeBase::UpdateOverlayWidgetsOwner()
{
if(auto PC = UGameplayStatics::GetPlayerController(GetWorld(), 0))
{
for(auto widget : permaOverlayWidgetsInstances)
{
if(widget.IsValid())
{
widget->SetOwningPlayer(PC);
}
}
for(auto widget : overlayWidgetsInstances)
{
if(widget.IsValid())
{
widget->SetOwningPlayer(PC);
}
}
}
}

View File

@ -2,10 +2,8 @@
#pragma once
#include "Blueprint/UserWidget.h"
#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "GameFramework/Pawn.h"
#include "MainGameModeBase.generated.h"
@ -20,21 +18,10 @@ public:
void SwitchCameraMode();
protected:
UPROPERTY(EditDefaultsOnly)
TArray<TSubclassOf<UUserWidget>> permaOverlayWidgets; // never hidden
TArray<TWeakObjectPtr<UUserWidget>> permaOverlayWidgetsInstances;
UPROPERTY(EditDefaultsOnly)
TArray<TSubclassOf<UUserWidget>> overlayWidgets; // hidden in pause
TArray<TWeakObjectPtr<UUserWidget>> overlayWidgetsInstances;
TSubclassOf<class UWidgetsManager> widgetManagerClass;
private:
inline void InstantiateOverlayWidgets();
void HideOverlayWidgets();
void ShowOverlayWidgets();
void UpdateOverlayWidgetsOwner();
class UWidgetsManager* _widgetsManager;
};

View File

@ -1,37 +1,61 @@
// Oleg Petruny proprietary.
#include "APlayerBase.h"
#include "PlayerBase.h"
#include "Camera/CameraComponent.h"
#include "CustomGameUserSettings.h"
#include "EnhancedInputSubsystems.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "InputMappingContext.h"
#include "Kismet/GameplayStatics.h"
#include "Kismet/KismetMathLibrary.h"
#include "CustomGameInstanceBase.h"
#include "Interactable/InteractableActivator.h"
#include "Interactable/InteractableCaller.h"
#include "Interactable/InteractableComponent.h"
#include "Interactable/UsableInteractable.h"
#include "CustomGameUserSettings.h"
#include "MainGameModeBase.h"
APlayerBase::APlayerBase()
{
PrimaryActorTick.bCanEverTick = true;
}
void APlayerBase::Tick(float DeltaTime)
{
ACharacter::Tick(DeltaTime);
// stabilize move speed by fps
AddActorLocalOffset(ConsumeMovementInputVector() * DeltaTime);
}
void APlayerBase::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
ACharacter::SetupPlayerInputComponent(PlayerInputComponent);
}
void APlayerBase::BeginPlay()
{
Super::BeginPlay();
ACharacter::BeginPlay();
auto world = GetWorld();
GetCharacterMovement()->MaxWalkSpeed = moveSpeed;
auto cameraManager = UGameplayStatics::GetPlayerCameraManager(world, 0);
cameraManager->ViewPitchMin = minPitch;
cameraManager->ViewPitchMax = maxPitch;
cameraManager = UGameplayStatics::GetPlayerCameraManager(world, 0);
if(cameraManager)
{
cameraManager->ViewPitchMin = minPitch;
cameraManager->ViewPitchMax = maxPitch;
}
auto gameSettings = UCustomGameUserSettings::GetCustomGameUserSettings();
if(auto camera = FindComponentByClass<UCameraComponent>())
camera = FindComponentByClass<UCameraComponent>();
if(camera)
{
camera->PostProcessSettings.MotionBlurAmount = gameSettings->bUseMotionBlur ? 1.0f : 0.0f;
}
@ -48,19 +72,7 @@ void APlayerBase::BeginPlay()
}
}
}
void APlayerBase::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// stabilize move speed by fps
AddActorLocalOffset(ConsumeMovementInputVector() * DeltaTime);
}
void APlayerBase::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
LoadInteractable();
}
void APlayerBase::SwitchToCameraPawn()
@ -97,7 +109,7 @@ void APlayerBase::Jump()
if(jumpLocked)
return;
Super::Jump();
ACharacter::Jump();
}
void APlayerBase::SwitchRun(bool run)
@ -109,4 +121,41 @@ void APlayerBase::SwitchRun(bool run)
GetCharacterMovement()->MaxWalkSpeed = moveSpeed * runSpeedMultiplier;
else
GetCharacterMovement()->MaxWalkSpeed = moveSpeed;
}
}
void APlayerBase::UpdatePitch(float min, float max)
{
minPitch = min;
maxPitch = max;
if(cameraManager)
{
cameraManager->ViewPitchMin = minPitch;
cameraManager->ViewPitchMax = maxPitch;
}
}
void APlayerBase::LoadInteractable()
{
auto GI = Cast<UCustomGameInstanceBase>(GetWorld()->GetGameInstance());
if(!GI)
{
return;
}
TSet<TSubclassOf<UInteractableActivator>> activators;
for(auto& interaction : GI->interactionsCollection)
{
auto actAndCallArray = interaction->GetDefaultObject<UInteractableComponent>()->GetActivatorsAndCallers_Implementation();
for(auto& actAndCall : actAndCallArray)
{
activators.Add(actAndCall.activator);
}
}
for(auto& activator : activators)
{
auto component = NewObject<USceneComponent>(this, activator);
component->AttachToComponent(camera, FAttachmentTransformRules::SnapToTargetIncludingScale);
}
}

View File

@ -4,9 +4,8 @@
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "InputMappingContext.h"
#include "APlayerBase.generated.h"
#include "PlayerBase.generated.h"
UCLASS()
class APlayerBase : public ACharacter
@ -33,8 +32,11 @@ protected:
UFUNCTION(BlueprintCallable, Category = Character)
void SwitchRun(bool run);
UFUNCTION(BlueprintCallable, Category = Character)
void UpdatePitch(float min, float max);
UPROPERTY(EditDefaultsOnly)
TSoftObjectPtr<UInputMappingContext> inputMapping;
TSoftObjectPtr<class UInputMappingContext> inputMapping;
UPROPERTY(EditAnywhere)
float moveSpeed = 200;
@ -48,17 +50,15 @@ protected:
UPROPERTY(EditAnywhere)
bool runLocked = false;
UPROPERTY(EditAnywhere)
float minPitch = -80;
UPROPERTY(EditAnywhere)
float maxPitch = 65;
// not visible :(
//UPROPERTY(EditDefaultsOnly)
//UCameraComponent* camera;
APlayerCameraManager* cameraManager;
class UCameraComponent* camera;
UPROPERTY(EditAnywhere)
bool cameraLocked = false;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
float minPitch = -80;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
float maxPitch = 65;
private:
void LoadInteractable();
};

View File

@ -0,0 +1,85 @@
// Oleg Petruny proprietary.
#include "WidgetsManager.h"
#include "Blueprint/UserWidget.h"
#include "Engine/World.h"
#include "Kismet/GameplayStatics.h"
#include "UObject/ScriptInterface.h"
#include "CustomGameInstanceBase.h"
#include "Interactable/Interactable.h"
#include "Interactable/InteractableComponent.h"
void UWidgetsManager::Init()
{
if(auto PC = UGameplayStatics::GetPlayerController(GetWorld(), 0))
{
for(auto& widget : permaOverlayWidgets)
{
if(auto instance = CreateWidget<UUserWidget>(PC, widget))
{
permaOverlayWidgetsInstances.Add(instance);
instance->AddToViewport();
}
}
for(auto& widget : overlayWidgets)
{
if(auto instance = CreateWidget<UUserWidget>(PC, widget))
{
overlayWidgetsInstances.Add(instance);
instance->AddToViewport();
}
}
}
}
void UWidgetsManager::HideOverlayWidgets()
{
for(auto& widget : overlayWidgetsInstances)
{
if(widget.IsValid())
{
widget->SetVisibility(ESlateVisibility::Hidden);
}
}
}
void UWidgetsManager::ShowOverlayWidgets()
{
for(auto& widget : overlayWidgetsInstances)
{
if(widget.IsValid())
{
widget->SetVisibility(ESlateVisibility::Visible);
}
}
}
void UWidgetsManager::UpdateOverlayWidgetsOwner()
{
if(auto PC = UGameplayStatics::GetPlayerController(GetWorld(), 0))
{
for(auto& widget : permaOverlayWidgetsInstances)
{
if(widget.IsValid())
{
widget->SetOwningPlayer(PC);
}
}
for(auto& widget : overlayWidgetsInstances)
{
if(widget.IsValid())
{
widget->SetOwningPlayer(PC);
}
}
}
}
void UWidgetsManager::ShowInteractionHints(AInteractable* interactable)
{
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Yellow, TEXT("Interaction Hint"));
//interactable->GetInterfa
}

View File

@ -0,0 +1,34 @@
#pragma once
// Oleg Petruny proprietary.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "WidgetsManager.generated.h"
UCLASS(Blueprintable)
class UWidgetsManager : public UObject
{
GENERATED_BODY()
public:
void Init();
void HideOverlayWidgets();
void ShowOverlayWidgets();
void UpdateOverlayWidgetsOwner();
void ShowInteractionHints(class AInteractable* interactable);
protected:
UPROPERTY(EditDefaultsOnly)
TArray<TSubclassOf<class UUserWidget>> permaOverlayWidgets; // never hidden
TArray<TWeakObjectPtr<class UUserWidget>> permaOverlayWidgetsInstances;
UPROPERTY(EditDefaultsOnly)
TArray<TSubclassOf<class UUserWidget>> overlayWidgets; // hidden in pause
TArray<TWeakObjectPtr<class UUserWidget>> overlayWidgetsInstances;
};