- Buffered inputs are no longer handled by a component on the PlayerController, but by a LocalPlayerSubsystem instead.
- Combo manager connects to this subsystem entirely on its own when its owner is the player character.
This commit is contained in:
parent
0c3b6fcf71
commit
cd4708449f
6
Source/ComboInput/Private/ComboInputAssets.cpp
Normal file
6
Source/ComboInput/Private/ComboInputAssets.cpp
Normal file
@ -0,0 +1,6 @@
|
||||
// ©2022 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#include "ComboInputAssets.h"
|
||||
|
||||
|
||||
|
||||
@ -2,8 +2,13 @@
|
||||
|
||||
#include "Components/ComboManagerComponent.h"
|
||||
|
||||
#include "Components/InputBufferComponent.h"
|
||||
#include "Interfaces/ComboHandlerInterface.h"
|
||||
#include "ComboInputAssets.h"
|
||||
#include "EnhancedInputComponent.h"
|
||||
#include "InputBufferLocalPlayerSubsystem.h"
|
||||
|
||||
#include "Engine/LocalPlayer.h"
|
||||
#include "GameFramework/Character.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogComboManagerComponent);
|
||||
|
||||
@ -18,20 +23,22 @@ UComboManagerComponent::UComboManagerComponent()
|
||||
void UComboManagerComponent::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
const AActor *OwningActor = this->GetOwner();
|
||||
if (const IComboHandlerInterface *ComboHandler = Cast<IComboHandlerInterface>(OwningActor))
|
||||
|
||||
// If this component's owner is the player character, attach it to the subsystem.
|
||||
ACharacter *PlayerCharacter = UGameplayStatics::GetPlayerCharacter(this, 0);
|
||||
if (this->GetOwner() == PlayerCharacter)
|
||||
{
|
||||
if (UInputBufferComponent *InputBuffer = IComboHandlerInterface::Execute_GetInputBuffer(OwningActor))
|
||||
{
|
||||
this->AttachedInputBuffer = InputBuffer;
|
||||
this->AttachedInputBuffer->NewComboInput.BindUObject(this, &UComboManagerComponent::ComboInputReceived);
|
||||
}
|
||||
APlayerController *Controller = UGameplayStatics::GetPlayerController(this, 0);
|
||||
UEnhancedInputComponent *InputComponent = Cast<UEnhancedInputComponent>(Controller->InputComponent);
|
||||
checkf(Controller, TEXT("Discovered controller is not a %s type."), *UEnhancedInputComponent::StaticClass()->GetName());
|
||||
|
||||
UInputBufferLocalPlayerSubsystem *InputBufferSubsystem = Controller->GetLocalPlayer()->GetSubsystem<UInputBufferLocalPlayerSubsystem>();
|
||||
InputBufferSubsystem->AttachComboManager(this, InputComponent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void UComboManagerComponent::ComboInputReceived(const UComboInputAsset *Input)
|
||||
void UComboManagerComponent::ActivateComboInput(const UComboInputAsset *Input)
|
||||
{
|
||||
/************ DEBUG ************/
|
||||
for (const TPair<TObjectPtr<const UComboInputAsset>, float> &Pair : this->DEBUG__UnlockTimers)
|
||||
@ -74,7 +81,9 @@ void UComboManagerComponent::ComboInputReceived(const UComboInputAsset *Input)
|
||||
}
|
||||
void UComboManagerComponent::DEBUG__UnlockAction(TObjectPtr<const UComboInputAsset> Unlock)
|
||||
{
|
||||
this->AttachedInputBuffer->UnlockComboInput(Unlock);
|
||||
APlayerController *Controller = UGameplayStatics::GetPlayerController(this, 0);
|
||||
UInputBufferLocalPlayerSubsystem *Subsystem = Controller->GetLocalPlayer()->GetSubsystem<UInputBufferLocalPlayerSubsystem>();
|
||||
Subsystem->UnlockComboInput(Unlock);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,189 +0,0 @@
|
||||
// ©2022 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#include "Components/InputBufferComponent.h"
|
||||
|
||||
#include "Components/InputComponent.h"
|
||||
#include "GameFramework/PlayerController.h"
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogInputBufferComponent);
|
||||
|
||||
|
||||
UInputBufferComponent::UInputBufferComponent()
|
||||
{
|
||||
PrimaryComponentTick.bStartWithTickEnabled = false;
|
||||
PrimaryComponentTick.bTickEvenWhenPaused = false;
|
||||
PrimaryComponentTick.bCanEverTick = false;
|
||||
}
|
||||
|
||||
void UInputBufferComponent::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
// Get all unique EnhancedInput actions bound to combo input actions.
|
||||
TSet<const UInputAction*> InputActionsToBind;
|
||||
for (const UComboInputAsset *ComboInput : this->ComboActions)
|
||||
{
|
||||
for (const UInputAction *InputAction : ComboInput->ActionGroup)
|
||||
{
|
||||
InputActionsToBind.Add(InputAction);
|
||||
}
|
||||
}
|
||||
|
||||
APlayerController *Controller = Cast<APlayerController>(this->GetOwner());
|
||||
checkf(Controller, TEXT("No player controller found as owner of %s"), *this->GetName());
|
||||
|
||||
if (this->EnhancedInputComponent = Cast<UEnhancedInputComponent>(Controller->InputComponent))
|
||||
{
|
||||
// Bind the input actions we found to the buffer management functions.
|
||||
for (const UInputAction *InputAction : InputActionsToBind)
|
||||
{
|
||||
this->EnhancedInputComponent->BindAction(InputAction, ETriggerEvent::Started, this, &UInputBufferComponent::AddActionToBuffer, InputAction);
|
||||
this->EnhancedInputComponent->BindAction(InputAction, ETriggerEvent::Completed, this, &UInputBufferComponent::ExpireAction, InputAction);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogInputBufferComponent, Error, TEXT("Parent of %s is not a UEnhancedInputComponent type."), *this->GetName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void UInputBufferComponent::AddActionToBuffer(const FInputActionValue &Value, const class UInputAction *Action)
|
||||
{
|
||||
this->MostRecentActions.Add(Action);
|
||||
this->ExpiringActions.Remove(Action);
|
||||
|
||||
// Find any combo input that matches this action, plus buffered actions.
|
||||
for (const UComboInputAsset *Combo : this->ComboActions)
|
||||
{
|
||||
if (Combo->MatchesInputActions(this->MostRecentActions))
|
||||
{
|
||||
this->ActivateComboInput(Combo);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this->GetWorld()->GetTimerManager().SetTimer(this->MultiPressTimerHandle, this, &UInputBufferComponent::ClearMultiPresses, this->MultiPressTimerLength);
|
||||
}
|
||||
void UInputBufferComponent::ClearMultiPresses()
|
||||
{
|
||||
#if WITH_EDITOR
|
||||
TArray<FString> ActionNames;
|
||||
for (const UInputAction *Action : this->MostRecentActions)
|
||||
{
|
||||
ActionNames.Add(Action->GetName());
|
||||
}
|
||||
UE_LOG(LogInputBufferComponent, Verbose, TEXT("Multi-press buffer cleared (%s)"), *FString::Join(ActionNames, TEXT(" | ")));
|
||||
#endif
|
||||
this->MostRecentActions.Empty();
|
||||
}
|
||||
|
||||
void UInputBufferComponent::ActivateComboInput(const UComboInputAsset *ComboInput)
|
||||
{
|
||||
checkf(ComboInput, TEXT("Invalid UComboInputAsset"));
|
||||
|
||||
// Make this combo input active if it isn't being locked, or if we are
|
||||
// overwriting a previous combo input with a multi-press combo input.
|
||||
const bool bMultiPressTimerActive = this->GetWorld()->GetTimerManager().IsTimerActive(this->MultiPressTimerHandle);
|
||||
const bool bComboInputLocked = this->LockedComboInputs.Contains(ComboInput);
|
||||
if (bMultiPressTimerActive || !bComboInputLocked)
|
||||
{
|
||||
if (!ComboInput->LockedComboInputs.IsEmpty())
|
||||
{
|
||||
// Set the combo input as active, and copy its lock data.
|
||||
this->InputBufferActive = ComboInput;
|
||||
this->LockedComboInputs = ComboInput->LockedComboInputs;
|
||||
|
||||
// Make sure the hold is clear if we're coming off of a multi-press action.
|
||||
if (bMultiPressTimerActive)
|
||||
{
|
||||
this->InputBufferHold = nullptr;
|
||||
}
|
||||
|
||||
UE_LOG(LogInputBufferComponent, Verbose, TEXT("%s is active."), *ComboInput->ComboInputName.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogInputBufferComponent, Verbose, TEXT("%s is active and won't lock inputs."), *ComboInput->ComboInputName.ToString());
|
||||
}
|
||||
|
||||
this->NewComboInput.Execute(ComboInput);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->InputBufferHold = ComboInput;
|
||||
|
||||
if (bComboInputLocked)
|
||||
{
|
||||
UE_LOG(LogInputBufferComponent, Verbose, TEXT("%s is locked and won't be activated yet."), *ComboInput->ComboInputName.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogInputBufferComponent, Verbose, TEXT("%s added to buffer."), *ComboInput->ComboInputName.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UInputBufferComponent::UnlockComboInput(const UComboInputAsset *Unlocked)
|
||||
{
|
||||
// Remove the newly-unlocked asset from the locked combo inputs.
|
||||
UE_CLOG(this->LockedComboInputs.Contains(Unlocked), LogInputBufferComponent, Verbose, TEXT("%s has unlocked."), *Unlocked->ComboInputName.ToString());
|
||||
this->LockedComboInputs.Remove(Unlocked);
|
||||
|
||||
// Check if the newly unlocked combo input is in the hold.
|
||||
if (Unlocked == this->InputBufferHold)
|
||||
{
|
||||
const UComboInputAsset *OriginalActive = this->InputBufferActive;
|
||||
|
||||
// Activate the held combo input.
|
||||
const UComboInputAsset *HeldAsset = this->InputBufferHold;
|
||||
this->InputBufferHold = nullptr;
|
||||
if (HeldAsset)
|
||||
{
|
||||
this->ActivateComboInput(HeldAsset);
|
||||
}
|
||||
|
||||
UE_LOG(LogInputBufferComponent, Verbose, TEXT("%s has expired."), *OriginalActive->ComboInputName.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
void UInputBufferComponent::ExpireAction(const FInputActionValue &Value, const class UInputAction *Action)
|
||||
{
|
||||
this->ExpiringActions.Add(Action);
|
||||
this->GetWorld()->GetTimerManager().SetTimer(this->InputReleaseExpirationTimerHandle, this, &UInputBufferComponent::ExpireBufferedActions, this->InputReleaseExpirationTimerLength);
|
||||
}
|
||||
void UInputBufferComponent::ExpireBufferedActions()
|
||||
{
|
||||
// Only bother dealing with this if there's something to deal with in the first place.
|
||||
if (!this->ExpiringActions.IsEmpty())
|
||||
{
|
||||
UE_SUPPRESS(LogInputBufferComponent, Verbose,
|
||||
{
|
||||
TArray<FString> ActionNames;
|
||||
for (const UInputAction *Action : this->ExpiringActions)
|
||||
{
|
||||
ActionNames.Add(Action->GetName());
|
||||
}
|
||||
UE_LOG(LogInputBufferComponent, Verbose, TEXT("Released actions expired (%s)"), *FString::Join(ActionNames, TEXT(" | ")));
|
||||
}
|
||||
);
|
||||
|
||||
// If there is an action in the hold, check if it's related
|
||||
// to our current released buttons, and if so cancel it.
|
||||
if (this->InputBufferHold)
|
||||
{
|
||||
for (const UInputAction *Action : this->ExpiringActions)
|
||||
{
|
||||
if (this->InputBufferHold->MatchesInputAction(Action))
|
||||
{
|
||||
UE_LOG(LogInputBufferComponent, Verbose, TEXT("%s has been cancelled."), *this->InputBufferHold->ComboInputName.ToString());
|
||||
this->InputBufferHold = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->ExpiringActions.Empty();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#include "GlobalSettings/InputBufferSubsystemGlobalSettings.h"
|
||||
|
||||
|
||||
|
||||
BIN
Source/ComboInput/Private/InputBufferLocalPlayerSubsystem.cpp
Normal file
BIN
Source/ComboInput/Private/InputBufferLocalPlayerSubsystem.cpp
Normal file
Binary file not shown.
@ -1,17 +0,0 @@
|
||||
// ©2022 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#include "Interfaces/ComboHandlerInterface.h"
|
||||
|
||||
#include "Components/ComboManagerComponent.h"
|
||||
#include "Components/InputBufferComponent.h"
|
||||
|
||||
|
||||
UInputBufferComponent *IComboHandlerInterface::GetInputBuffer_Implementation() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UComboManagerComponent *IComboHandlerInterface::GetComboManager_Implementation() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
90
Source/ComboInput/Public/ComboInputAssets.h
Normal file
90
Source/ComboInput/Public/ComboInputAssets.h
Normal file
@ -0,0 +1,90 @@
|
||||
// ©2022 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "ComboInputAssets.generated.h"
|
||||
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct COMBOINPUT_API FComboSequenceAction
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
// Action to perform when the associated combo sequence node is activated.
|
||||
UPROPERTY(BlueprintReadOnly, EditAnywhere)
|
||||
TObjectPtr<const class UComboAction> ComboAction;
|
||||
|
||||
// Sequence node to switch to once this action is complete.
|
||||
UPROPERTY(BlueprintReadOnly, EditAnywhere)
|
||||
TObjectPtr<const class UComboSequenceNode> NextNode;
|
||||
};
|
||||
|
||||
UCLASS(BlueprintType)
|
||||
class COMBOINPUT_API UComboAction : public UDataAsset
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
// Human-readable name of this combo action.
|
||||
UPROPERTY(BlueprintReadOnly, EditAnywhere)
|
||||
FName ActionName;
|
||||
};
|
||||
|
||||
UCLASS(BlueprintType)
|
||||
class COMBOINPUT_API UComboSequenceNode : public UDataAsset
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UPROPERTY(BlueprintReadOnly, EditAnywhere)
|
||||
TMap<const class UComboInputAsset *, struct FComboSequenceAction> ComboBranch;
|
||||
};
|
||||
|
||||
UCLASS(BlueprintType)
|
||||
class COMBOINPUT_API UComboInputAsset : public UDataAsset
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
bool MatchesInputAction(const class UInputAction* Action) const
|
||||
{
|
||||
if (this->ActionGroup.Num() == 1 && this->ActionGroup.Contains(Action))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool MatchesInputActions(TSet<const class UInputAction *> Actions) const
|
||||
{
|
||||
if (this->ActionGroup.Num() == Actions.Num())
|
||||
{
|
||||
for (const UInputAction *Action : Actions)
|
||||
{
|
||||
if (!this->ActionGroup.Contains(Action))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Human-readable name of this combo input.
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere)
|
||||
FName ComboInputName;
|
||||
|
||||
// Combined actions that add up to this combo input when activated
|
||||
// within a short time of one another. If only one is present, then
|
||||
// this combo input asset will simply represent that action.
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere)
|
||||
TSet<TObjectPtr<const class UInputAction>> ActionGroup;
|
||||
|
||||
// Combo inputs that should be prevented from occurring during this
|
||||
// action. These will be locked when the action is broadcast, and
|
||||
// should be unlocked by the receiving actor by sending an unlock
|
||||
// event.
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere)
|
||||
TSet<TObjectPtr<const class UComboInputAsset>> LockedComboInputs;
|
||||
};
|
||||
@ -12,41 +12,6 @@
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogComboManagerComponent, Log, All);
|
||||
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct COMBOINPUT_API FComboSequenceAction
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
// Action to perform when the associated combo sequence node is activated.
|
||||
UPROPERTY(BlueprintReadOnly, EditAnywhere)
|
||||
TObjectPtr<const class UComboAction> ComboAction;
|
||||
|
||||
// Sequence node to switch to once this action is complete.
|
||||
UPROPERTY(BlueprintReadOnly, EditAnywhere)
|
||||
TObjectPtr<const class UComboSequenceNode> NextNode;
|
||||
};
|
||||
|
||||
UCLASS(BlueprintType)
|
||||
class COMBOINPUT_API UComboAction : public UDataAsset
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
// Human-readable name of this combo action.
|
||||
UPROPERTY(BlueprintReadOnly, EditAnywhere)
|
||||
FName ActionName;
|
||||
};
|
||||
|
||||
UCLASS(BlueprintType)
|
||||
class COMBOINPUT_API UComboSequenceNode : public UDataAsset
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UPROPERTY(BlueprintReadOnly, EditAnywhere)
|
||||
TMap<const class UComboInputAsset*, struct FComboSequenceAction> ComboBranch;
|
||||
};
|
||||
|
||||
UCLASS(BlueprintType, ClassGroup=(Input), meta=(BlueprintSpawnableComponent))
|
||||
class COMBOINPUT_API UComboManagerComponent : public UActorComponent
|
||||
{
|
||||
@ -56,6 +21,9 @@ public:
|
||||
UComboManagerComponent();
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void ActivateComboInput(const class UComboInputAsset *Input);
|
||||
|
||||
protected:
|
||||
UPROPERTY(BlueprintReadOnly, EditDefaultsOnly)
|
||||
TObjectPtr<const class UComboSequenceNode> DefaultStartNode;
|
||||
@ -70,8 +38,6 @@ protected:
|
||||
TMap<TObjectPtr<const class UComboInputAsset>, float> DEBUG__UnlockTimers;
|
||||
|
||||
private:
|
||||
void ComboInputReceived(const class UComboInputAsset *Input);
|
||||
|
||||
void BeginNodeTransition(const class UComboSequenceNode *NextNode);
|
||||
void FinishTransition();
|
||||
|
||||
|
||||
@ -1,118 +0,0 @@
|
||||
// ©2022 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "EnhancedInputComponent.h"
|
||||
#include "Components/ActorComponent.h"
|
||||
|
||||
#include "InputBufferComponent.generated.h"
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogInputBufferComponent, Log, All);
|
||||
|
||||
|
||||
UCLASS(BlueprintType)
|
||||
class COMBOINPUT_API UComboInputAsset : public UDataAsset
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
bool MatchesInputAction(const class UInputAction* Action) const
|
||||
{
|
||||
if (this->ActionGroup.Num() == 1 && this->ActionGroup.Contains(Action))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool MatchesInputActions(TSet<const class UInputAction *> Actions) const
|
||||
{
|
||||
if (this->ActionGroup.Num() == Actions.Num())
|
||||
{
|
||||
for (const UInputAction *Action : Actions)
|
||||
{
|
||||
if (!this->ActionGroup.Contains(Action))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Human-readable name of this combo input.
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere)
|
||||
FName ComboInputName;
|
||||
|
||||
// Combined actions that add up to this combo input when activated
|
||||
// within a short time of one another. If only one is present, then
|
||||
// this combo input asset will simply represent that action.
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere)
|
||||
TSet<TObjectPtr<const class UInputAction>> ActionGroup;
|
||||
|
||||
// Combo inputs that should be prevented from occurring during this
|
||||
// action. These will be locked when the action is broadcast, and
|
||||
// should be unlocked by the receiving actor by sending an unlock
|
||||
// event.
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere)
|
||||
TSet<TObjectPtr<const class UComboInputAsset>> LockedComboInputs;
|
||||
};
|
||||
|
||||
|
||||
UCLASS(BlueprintType, ClassGroup=(Input), meta=(BlueprintSpawnableComponent))
|
||||
class COMBOINPUT_API UInputBufferComponent : public UActorComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UInputBufferComponent();
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void UnlockComboInput(const class UComboInputAsset *Unlocked);
|
||||
|
||||
// List of possible combo inputs that can be taken. A combo input is selected from this list
|
||||
// either if an action is made while the current combo is inactive, or when the previous
|
||||
// action expires.
|
||||
UPROPERTY(BlueprintReadOnly, EditDefaultsOnly)
|
||||
TSet<const class UComboInputAsset*> ComboActions;
|
||||
|
||||
// Length of time after releasing an input to keep the associated combo action buffered before clearing it.
|
||||
UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, meta=(UIMin="0.0", UIMax="0.5"))
|
||||
float InputReleaseExpirationTimerLength = 0.0666666666666666667f;
|
||||
|
||||
// Length of time within which we can recognise multiple button presses as one input.
|
||||
UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, meta=(UIMin="0.02", UIMax="0.25"))
|
||||
float MultiPressTimerLength = 0.025f;
|
||||
|
||||
DECLARE_DELEGATE_OneParam(FNewComboInput, const class UComboInputAsset*);
|
||||
FNewComboInput NewComboInput;
|
||||
|
||||
private:
|
||||
void AddActionToBuffer(const FInputActionValue &Value, const class UInputAction *Action);
|
||||
void ExpireAction(const FInputActionValue &Value, const class UInputAction *Action);
|
||||
|
||||
void ActivateComboInput(const class UComboInputAsset *ComboInput);
|
||||
|
||||
void ClearMultiPresses();
|
||||
void ExpireBufferedActions();
|
||||
|
||||
TObjectPtr<class UEnhancedInputComponent> EnhancedInputComponent;
|
||||
|
||||
// Currently active combo input.
|
||||
TObjectPtr<const class UComboInputAsset> InputBufferActive;
|
||||
|
||||
// Combo input held until the current input has expired.
|
||||
TObjectPtr<const class UComboInputAsset> InputBufferHold;
|
||||
|
||||
// Set of currently locked actions; will not be activated until an unlock signal is received.
|
||||
TSet<TObjectPtr<const class UComboInputAsset>> LockedComboInputs;
|
||||
|
||||
TSet<const class UInputAction*> MostRecentActions;
|
||||
TSet<const class UInputAction*> ExpiringActions;
|
||||
|
||||
FTimerHandle MultiPressTimerHandle;
|
||||
FTimerHandle InputReleaseExpirationTimerHandle;
|
||||
FTimerHandle ForceUnlockTimerHandle;
|
||||
};
|
||||
@ -0,0 +1,32 @@
|
||||
// ©2023 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/DeveloperSettingsBackedByCVars.h"
|
||||
|
||||
#include "InputBufferSubsystemGlobalSettings.generated.h"
|
||||
|
||||
|
||||
/**
|
||||
* Global settings for the input buffer subsystem
|
||||
*/
|
||||
UCLASS(Config=Game, defaultconfig, meta=(DisplayName="Input Buffer Subsystem"))
|
||||
class COMBOINPUT_API UInputBufferSubsystemGlobalSettings : public UDeveloperSettingsBackedByCVars
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
// List of possible combo inputs that can be taken. A combo input is selected from this list
|
||||
// either if an action is made while the current combo is inactive, or when the previous
|
||||
// action expires.
|
||||
UPROPERTY(Config, BlueprintReadOnly, EditDefaultsOnly)
|
||||
TSet<TSoftObjectPtr<const class UComboInputAsset>> ComboActions;
|
||||
|
||||
// Length of time after releasing an input to keep the associated combo action buffered before clearing it.
|
||||
UPROPERTY(Config, BlueprintReadOnly, EditDefaultsOnly, meta = (UIMin = "0.0", UIMax = "0.5"))
|
||||
float InputReleaseExpirationTimerLength = 0.0666666666666666667f;
|
||||
|
||||
// Length of time within which we can recognise multiple button presses as one input.
|
||||
UPROPERTY(Config, BlueprintReadOnly, EditDefaultsOnly, meta = (UIMin = "0.02", UIMax = "0.25"))
|
||||
float MultiPressTimerLength = 0.025f;
|
||||
};
|
||||
BIN
Source/ComboInput/Public/InputBufferLocalPlayerSubsystem.h
Normal file
BIN
Source/ComboInput/Public/InputBufferLocalPlayerSubsystem.h
Normal file
Binary file not shown.
@ -1,32 +0,0 @@
|
||||
// ©2022 Batty Bovine Productions, LLC. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "UObject/Interface.h"
|
||||
#include "ComboHandlerInterface.generated.h"
|
||||
|
||||
|
||||
// This class does not need to be modified.
|
||||
UINTERFACE(MinimalAPI, meta=(Blueprintable))
|
||||
class UComboHandlerInterface : public UInterface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
};
|
||||
/**
|
||||
* Interface for anything that handles combo inputs and contains a
|
||||
* UComboManagerComponent.
|
||||
*/
|
||||
class COMBOINPUT_API IComboHandlerInterface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
// Add interface functions to this class. This is the class that will be inherited to implement this interface.
|
||||
public:
|
||||
UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
|
||||
class UInputBufferComponent *GetInputBuffer() const;
|
||||
virtual class UInputBufferComponent *GetInputBuffer_Implementation() const;
|
||||
UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
|
||||
class UComboManagerComponent *GetComboManager() const;
|
||||
virtual class UComboManagerComponent *GetComboManager_Implementation() const;
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user