Skip to content

Created ability to task which waits for a character movement mode to change #356

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Source/GameBaseFramework/Private/Characters/GBFCharacter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,12 +141,13 @@ void AGBFCharacter::SetupPlayerInputComponent( UInputComponent * player_input_co

void AGBFCharacter::OnMovementModeChanged( EMovementMode prev_movement_mode, uint8 previous_custom_mode )
{
Super::OnMovementModeChanged( prev_movement_mode, previous_custom_mode );

// Update the tags before calling Super, which calls a delegate, and some code bound to this delegate may require the tags to be up-to-date
const auto * character_movement_component = GetCharacterMovement();

SetMovementModeTag( prev_movement_mode, previous_custom_mode, false );
SetMovementModeTag( character_movement_component->MovementMode, character_movement_component->CustomMovementMode, true );

Super::OnMovementModeChanged( prev_movement_mode, previous_custom_mode );
}

void AGBFCharacter::OnAbilitySystemInitialized()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#include "GAS/Tasks/GBFAT_WaitMovementModeChanged.h"

#include "GameFramework/CharacterMovementComponent.h"

#include <GameFramework/Character.h>

UGBFAT_WaitMovementModeChanged::UGBFAT_WaitMovementModeChanged() :
RequiredMode( MOVE_None ),
bTriggerInstantlyIfMovementModeChanges( true )
{
}

UGBFAT_WaitMovementModeChanged * UGBFAT_WaitMovementModeChanged::WaitMovementModeChange( UGameplayAbility * owning_ability, ACharacter * character /*= nullptr */, bool trigger_instantly_if_movement_mode_matches /*= true*/, EMovementMode required_mode /*= MOVE_None*/ )
{
auto * task = NewAbilityTask< UGBFAT_WaitMovementModeChanged >( owning_ability );
task->RequiredMode = required_mode;
task->Character = character;
task->bTriggerInstantlyIfMovementModeChanges = trigger_instantly_if_movement_mode_matches;
return task;
}

void UGBFAT_WaitMovementModeChanged::Activate()
{
Super::Activate();

if ( Character.IsValid() )
{
if ( const auto * movement_component = Cast< UCharacterMovementComponent >( Character->GetMovementComponent() ) )
{
if ( bTriggerInstantlyIfMovementModeChanges && ( RequiredMode == MOVE_None || movement_component->MovementMode == RequiredMode ) )
{
BroadcastEvent( movement_component->MovementMode );
return;
}
}
Character->MovementModeChangedDelegate.AddDynamic( this, &ThisClass::OnMovementModeChange );
}

SetWaitingOnAvatar();
}

void UGBFAT_WaitMovementModeChanged::OnDestroy( bool AbilityEnded )
{
Super::OnDestroy( AbilityEnded );

if ( Character.IsValid() )
{
Character->MovementModeChangedDelegate.RemoveDynamic( this, &ThisClass::OnMovementModeChange );
}
}

void UGBFAT_WaitMovementModeChanged::OnMovementModeChange( ACharacter * character, EMovementMode prev_movement_mode, uint8 previous_custom_node )
{
if ( Character.IsValid() )
{
if ( const auto * movement_component = Cast< UCharacterMovementComponent >( Character->GetMovementComponent() ) )
{
if ( RequiredMode == MOVE_None || movement_component->MovementMode == RequiredMode )
{
BroadcastEvent( movement_component->MovementMode );
}
}
}
}

void UGBFAT_WaitMovementModeChanged::BroadcastEvent( EMovementMode movement_mode )
{
if ( ShouldBroadcastAbilityTaskDelegates() )
{
OnChange.Broadcast( movement_mode );
}
EndTask();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#pragma once

#include <Abilities/Tasks/AbilityTask.h>
#include <CoreMinimal.h>

#include "GBFAT_WaitMovementModeChanged.generated.h"

class ACharacter;

UCLASS()
class GAMEBASEFRAMEWORK_API UGBFAT_WaitMovementModeChanged final : public UAbilityTask
{
GENERATED_BODY()

public:
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam( FGBFMovementModeChangedDelegate, EMovementMode, NewMovementMode );

UGBFAT_WaitMovementModeChanged();

/** Wait until movement mode changes (E.g., landing) */
UFUNCTION( BlueprintCallable, Category = "Ability|Tasks", DisplayName = "Wait for character movement changed", meta = ( HidePin = "owning_ability", DefaultToSelf = "owning_ability", BlueprintInternalUseOnly = "true" ) )
static UGBFAT_WaitMovementModeChanged * WaitMovementModeChange( UGameplayAbility * owning_ability, ACharacter * character = nullptr, bool trigger_instantly_if_movement_mode_matches = true, EMovementMode required_mode = MOVE_None );

void Activate() override;

protected:
void OnDestroy( bool AbilityEnded ) override;

UFUNCTION()
void OnMovementModeChange( ACharacter * character, EMovementMode prev_movement_mode, uint8 previous_custom_node );

void BroadcastEvent( EMovementMode movement_mode );

UPROPERTY( BlueprintAssignable )
FGBFMovementModeChangedDelegate OnChange;

EMovementMode RequiredMode;
TWeakObjectPtr< ACharacter > Character;
bool bTriggerInstantlyIfMovementModeChanges;
};