completed attack combo with GameplayEffects and GameplayCues
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -1,5 +1,4 @@
|
|||||||
;METADATA=(Diff=true, UseCommands=true)
|
;METADATA=(Diff=true, UseCommands=true)
|
||||||
|
|
||||||
[/Script/GameplayTags.GameplayTagsSettings]
|
[/Script/GameplayTags.GameplayTagsSettings]
|
||||||
ImportTagsFromConfig=True
|
ImportTagsFromConfig=True
|
||||||
WarnOnInvalidTags=True
|
WarnOnInvalidTags=True
|
||||||
@@ -18,4 +17,8 @@ NetIndexFirstBitSegment=16
|
|||||||
+GameplayTagList=(Tag="ability.combo.change.combo03",DevComment="")
|
+GameplayTagList=(Tag="ability.combo.change.combo03",DevComment="")
|
||||||
+GameplayTagList=(Tag="ability.combo.change.combo04",DevComment="")
|
+GameplayTagList=(Tag="ability.combo.change.combo04",DevComment="")
|
||||||
+GameplayTagList=(Tag="ability.combo.change.end",DevComment="")
|
+GameplayTagList=(Tag="ability.combo.change.end",DevComment="")
|
||||||
|
+GameplayTagList=(Tag="ability.combo.damage",DevComment="")
|
||||||
|
+GameplayTagList=(Tag="GameplayCue.cameraShake",DevComment="")
|
||||||
|
+GameplayTagList=(Tag="GameplayCue.hit.crunch.punch",DevComment="")
|
||||||
|
+GameplayTagList=(Tag="GameplayCue.hit.reaction",DevComment="")
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
BIN
Content/Characters/Crunch/GameplayAbility/Combo/Animations/AM_HitReaction.uasset
LFS
Normal file
BIN
Content/Characters/Crunch/GameplayAbility/Combo/Animations/AM_HitReaction.uasset
LFS
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/Cosmetics/CS_Default_BP.uasset
LFS
Normal file
BIN
Content/Cosmetics/CS_Default_BP.uasset
LFS
Normal file
Binary file not shown.
BIN
Content/GameplayCueNotifies/GC_cameraShake.uasset
LFS
Normal file
BIN
Content/GameplayCueNotifies/GC_cameraShake.uasset
LFS
Normal file
Binary file not shown.
BIN
Content/GameplayCueNotifies/GC_hit_crunch_punch.uasset
LFS
Normal file
BIN
Content/GameplayCueNotifies/GC_hit_crunch_punch.uasset
LFS
Normal file
Binary file not shown.
BIN
Content/GameplayCueNotifies/GC_hit_reaction.uasset
LFS
Normal file
BIN
Content/GameplayCueNotifies/GC_hit_reaction.uasset
LFS
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
30
Source/Crunch/Private/Animations/AN_SendTargetGroup.cpp
Normal file
30
Source/Crunch/Private/Animations/AN_SendTargetGroup.cpp
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// Multiplayer By Caleb
|
||||||
|
|
||||||
|
|
||||||
|
#include "Animations/AN_SendTargetGroup.h"
|
||||||
|
|
||||||
|
#include "AbilitySystemBlueprintLibrary.h"
|
||||||
|
|
||||||
|
void UAN_SendTargetGroup::Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation,
|
||||||
|
const FAnimNotifyEventReference& EventReference)
|
||||||
|
{
|
||||||
|
Super::Notify(MeshComp, Animation, EventReference);
|
||||||
|
|
||||||
|
if (!MeshComp || !MeshComp->GetOwner()) return;
|
||||||
|
if (!TargetSocketNames.Num()) return;
|
||||||
|
if (!UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(MeshComp->GetOwner())) return;
|
||||||
|
|
||||||
|
FGameplayEventData Data;
|
||||||
|
for (int i = 1; i < TargetSocketNames.Num(); ++i)
|
||||||
|
{
|
||||||
|
// const auto LocationInfo{NewObject<FGameplayAbilityTargetData_LocationInfo>()};
|
||||||
|
const auto LocationInfo{new FGameplayAbilityTargetData_LocationInfo()}; // heap allocation
|
||||||
|
FVector StartLoc{MeshComp->GetSocketLocation(TargetSocketNames[i - 1])};
|
||||||
|
FVector EndLoc{MeshComp->GetSocketLocation(TargetSocketNames[i])};
|
||||||
|
LocationInfo->SourceLocation.LiteralTransform.SetLocation(StartLoc);
|
||||||
|
LocationInfo->TargetLocation.LiteralTransform.SetLocation(EndLoc);
|
||||||
|
|
||||||
|
Data.TargetData.Add(LocationInfo);
|
||||||
|
}
|
||||||
|
UAbilitySystemBlueprintLibrary::SendGameplayEventToActor(MeshComp->GetOwner(), EventTag, Data);
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "GAS/CAttributeSet.h"
|
#include "GAS/CAttributeSet.h"
|
||||||
|
|
||||||
|
#include "GameplayEffectExtension.h"
|
||||||
#include "Net/UnrealNetwork.h"
|
#include "Net/UnrealNetwork.h"
|
||||||
|
|
||||||
void UCAttributeSet::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
|
void UCAttributeSet::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
|
||||||
@@ -14,6 +15,31 @@ void UCAttributeSet::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLi
|
|||||||
DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, MaxMana, COND_None, REPNOTIFY_Always);
|
DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, MaxMana, COND_None, REPNOTIFY_Always);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UCAttributeSet::PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue)
|
||||||
|
{
|
||||||
|
if (Attribute == GetHealthAttribute())
|
||||||
|
{
|
||||||
|
NewValue = FMath::Clamp(NewValue, 0.0f, GetMaxHealth());
|
||||||
|
}
|
||||||
|
if (Attribute == GetManaAttribute())
|
||||||
|
{
|
||||||
|
NewValue = FMath::Clamp(NewValue, 0.0f, GetMaxMana());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UCAttributeSet::PostGameplayEffectExecute(const struct FGameplayEffectModCallbackData& Data)
|
||||||
|
{
|
||||||
|
// Super::PostGameplayEffectExecute(Data);
|
||||||
|
if (Data.EvaluatedData.Attribute == GetHealthAttribute())
|
||||||
|
{
|
||||||
|
SetHealth(FMath::Clamp(GetHealth(), 0, GetMaxHealth()));
|
||||||
|
}
|
||||||
|
if (Data.EvaluatedData.Attribute == GetManaAttribute())
|
||||||
|
{
|
||||||
|
SetMana(FMath::Clamp(GetMana(), 0, GetMaxMana()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void UCAttributeSet::OnRep_Health(const FGameplayAttributeData& OldValue)
|
void UCAttributeSet::OnRep_Health(const FGameplayAttributeData& OldValue)
|
||||||
{
|
{
|
||||||
GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, Health, OldValue);
|
GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, Health, OldValue);
|
||||||
|
|||||||
@@ -3,7 +3,9 @@
|
|||||||
|
|
||||||
#include "GAS/CGameplayAbility.h"
|
#include "GAS/CGameplayAbility.h"
|
||||||
|
|
||||||
UAnimInstance* UCGameplayAbility::GetOwnerAnimInstance()
|
#include "Kismet/KismetSystemLibrary.h"
|
||||||
|
|
||||||
|
UAnimInstance* UCGameplayAbility::GetOwnerAnimInstance() const
|
||||||
{
|
{
|
||||||
if (const auto OwnerSkeletalMeshComp{GetOwningComponentFromActorInfo()})
|
if (const auto OwnerSkeletalMeshComp{GetOwningComponentFromActorInfo()})
|
||||||
{
|
{
|
||||||
@@ -11,3 +13,46 @@ UAnimInstance* UCGameplayAbility::GetOwnerAnimInstance()
|
|||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TArray<FHitResult> UCGameplayAbility::GetHitResultFromSweepLocationTargetData(
|
||||||
|
const FGameplayAbilityTargetDataHandle& TargetDataHandle, float SphereSweepRadius, bool bDrawDebug,
|
||||||
|
bool bIgnoreSelf) const
|
||||||
|
{
|
||||||
|
TArray<FHitResult> OutResults;
|
||||||
|
TSet<AActor*> HitActors;
|
||||||
|
for (const auto TargetData : TargetDataHandle.Data)
|
||||||
|
{
|
||||||
|
const FVector StartLoc{TargetData->GetOrigin().GetTranslation()};
|
||||||
|
const FVector EndLoc{TargetData->GetEndPoint()};
|
||||||
|
|
||||||
|
TArray<TEnumAsByte<EObjectTypeQuery>> ObjectTypes;
|
||||||
|
ObjectTypes.Add(UEngineTypes::ConvertToObjectType(ECC_Pawn));
|
||||||
|
|
||||||
|
TArray<AActor*> ActorsToIgnore;
|
||||||
|
if (bIgnoreSelf) ActorsToIgnore.Add(GetAvatarActorFromActorInfo());
|
||||||
|
const auto DrawDebugTrace{bDrawDebug ? EDrawDebugTrace::ForDuration : EDrawDebugTrace::None};
|
||||||
|
|
||||||
|
TArray<FHitResult> Results;
|
||||||
|
UKismetSystemLibrary::SphereTraceMultiForObjects(
|
||||||
|
this,
|
||||||
|
StartLoc,
|
||||||
|
EndLoc,
|
||||||
|
SphereSweepRadius,
|
||||||
|
ObjectTypes,
|
||||||
|
false,
|
||||||
|
ActorsToIgnore,
|
||||||
|
DrawDebugTrace,
|
||||||
|
Results,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const auto Result : Results)
|
||||||
|
{
|
||||||
|
if (HitActors.Contains(Result.GetActor())) continue;
|
||||||
|
HitActors.Add(Result.GetActor());
|
||||||
|
OutResults.Add(Result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return OutResults;
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "GAS/GA_Combo.h"
|
#include "GAS/GA_Combo.h"
|
||||||
|
|
||||||
|
#include "AbilitySystemBlueprintLibrary.h"
|
||||||
#include "GameplayTagsManager.h"
|
#include "GameplayTagsManager.h"
|
||||||
#include "Abilities/Tasks/AbilityTask_PlayMontageAndWait.h"
|
#include "Abilities/Tasks/AbilityTask_PlayMontageAndWait.h"
|
||||||
#include "Abilities/Tasks/AbilityTask_WaitGameplayEvent.h"
|
#include "Abilities/Tasks/AbilityTask_WaitGameplayEvent.h"
|
||||||
@@ -60,6 +61,17 @@ void UGA_Combo::ActivateAbility(const FGameplayAbilitySpecHandle Handle,
|
|||||||
WaitComboChangeEventTask->EventReceived.AddDynamic(this, &UGA_Combo::ComboChangedEventReceived);
|
WaitComboChangeEventTask->EventReceived.AddDynamic(this, &UGA_Combo::ComboChangedEventReceived);
|
||||||
WaitComboChangeEventTask->ReadyForActivation();
|
WaitComboChangeEventTask->ReadyForActivation();
|
||||||
}
|
}
|
||||||
|
if (K2_HasAuthority())
|
||||||
|
{
|
||||||
|
const auto WaitTargetingEventTask{
|
||||||
|
UAbilityTask_WaitGameplayEvent::WaitGameplayEvent(
|
||||||
|
this,
|
||||||
|
GetComboTargetEventTag()
|
||||||
|
)
|
||||||
|
};
|
||||||
|
WaitTargetingEventTask->EventReceived.AddDynamic(this, &UGA_Combo::DoDamage);
|
||||||
|
WaitTargetingEventTask->ReadyForActivation();
|
||||||
|
}
|
||||||
|
|
||||||
SetupWaitComboInputPressed();
|
SetupWaitComboInputPressed();
|
||||||
}
|
}
|
||||||
@@ -91,6 +103,11 @@ FGameplayTag UGA_Combo::GetComboChangedEventEndTag()
|
|||||||
return FGameplayTag::RequestGameplayTag("ability.combo.change.end");
|
return FGameplayTag::RequestGameplayTag("ability.combo.change.end");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FGameplayTag UGA_Combo::GetComboTargetEventTag()
|
||||||
|
{
|
||||||
|
return FGameplayTag::RequestGameplayTag("ability.combo.damage");
|
||||||
|
}
|
||||||
|
|
||||||
void UGA_Combo::SetupWaitComboInputPressed()
|
void UGA_Combo::SetupWaitComboInputPressed()
|
||||||
{
|
{
|
||||||
const auto WaitInputPress{UAbilityTask_WaitInputPress::WaitInputPress(this)};
|
const auto WaitInputPress{UAbilityTask_WaitInputPress::WaitInputPress(this)};
|
||||||
@@ -117,3 +134,49 @@ void UGA_Combo::TryCommitCombo()
|
|||||||
ComboMontage
|
ComboMontage
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TSubclassOf<UGameplayEffect> UGA_Combo::GetDamageEffectForCurrentCombo() const
|
||||||
|
{
|
||||||
|
if (const auto OwnerAnimInstance{GetOwnerAnimInstance()})
|
||||||
|
{
|
||||||
|
const FName CurrentSectionName{OwnerAnimInstance->Montage_GetCurrentSection(ComboMontage)};
|
||||||
|
const auto FoundEffectPtr{DamageEffectMap.Find(CurrentSectionName)};
|
||||||
|
|
||||||
|
if (FoundEffectPtr) return *FoundEffectPtr;
|
||||||
|
}
|
||||||
|
return DefaultEffectClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UGA_Combo::DoDamage(FGameplayEventData Data)
|
||||||
|
{
|
||||||
|
auto HitResults{
|
||||||
|
GetHitResultFromSweepLocationTargetData(
|
||||||
|
Data.TargetData,
|
||||||
|
TargetSweepSphereRadius,
|
||||||
|
false,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const FHitResult& HitResult : HitResults)
|
||||||
|
{
|
||||||
|
const auto GameplayEffect{GetDamageEffectForCurrentCombo()};
|
||||||
|
const auto AbilityLevel{GetAbilityLevel(GetCurrentAbilitySpecHandle(), GetCurrentActorInfo())};
|
||||||
|
const auto EffectSpecHandle{MakeOutgoingGameplayEffectSpec(GameplayEffect, AbilityLevel)};
|
||||||
|
const auto AbilityTargetData{UAbilitySystemBlueprintLibrary::AbilityTargetDataFromActor(HitResult.GetActor())};
|
||||||
|
|
||||||
|
auto EffectContextHandle{MakeEffectContext(GetCurrentAbilitySpecHandle(), GetCurrentActorInfo())};
|
||||||
|
EffectContextHandle.AddHitResult(HitResult);
|
||||||
|
EffectSpecHandle.Data->SetContext(EffectContextHandle);
|
||||||
|
|
||||||
|
const auto ActiveGameplayEffectHandles{
|
||||||
|
ApplyGameplayEffectSpecToTarget(
|
||||||
|
GetCurrentAbilitySpecHandle(),
|
||||||
|
CurrentActorInfo,
|
||||||
|
CurrentActivationInfo,
|
||||||
|
EffectSpecHandle,
|
||||||
|
AbilityTargetData
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
26
Source/Crunch/Public/Animations/AN_SendTargetGroup.h
Normal file
26
Source/Crunch/Public/Animations/AN_SendTargetGroup.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// Multiplayer By Caleb
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "GameplayTagContainer.h"
|
||||||
|
#include "Animation/AnimNotifies/AnimNotify.h"
|
||||||
|
#include "AN_SendTargetGroup.generated.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
UCLASS()
|
||||||
|
class CRUNCH_API UAN_SendTargetGroup : public UAnimNotify
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation,
|
||||||
|
const FAnimNotifyEventReference& EventReference) override;
|
||||||
|
private:
|
||||||
|
UPROPERTY(EditAnywhere, Category="Ability")
|
||||||
|
FGameplayTag EventTag;
|
||||||
|
UPROPERTY(EditAnywhere, Category="Ability")
|
||||||
|
TArray<FName> TargetSocketNames;
|
||||||
|
};
|
||||||
@@ -39,6 +39,26 @@ class CRUNCH_API UCAttributeSet : public UAttributeSet
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
|
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
|
||||||
|
/**
|
||||||
|
* An "On Aggregator Change" type of event could go here, and that could be called when active gameplay effects are added or removed to an attribute aggregator.
|
||||||
|
* It is difficult to give all the information in these cases though - aggregators can change for many reasons: being added, being removed, being modified, having a modifier change, immunity, stacking rules, etc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ---------------------------------------------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Called just before any modification happens to an attribute. This is lower level than PreAttributeModify/PostAttribute modify.
|
||||||
|
* There is no additional context provided here since anything can trigger this. Executed effects, duration based effects, effects being removed, immunity being applied, stacking rules changing, etc.
|
||||||
|
* This function is meant to enforce things like "Health = Clamp(Health, 0, MaxHealth)" and NOT things like "trigger this extra thing if damage is applied, etc".
|
||||||
|
*
|
||||||
|
* NewValue is a mutable reference so you are able to clamp the newly applied value as well.
|
||||||
|
*/
|
||||||
|
virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override;
|
||||||
|
/**
|
||||||
|
* Called just after a GameplayEffect is executed to modify the base value of an attribute. No more changes can be made.
|
||||||
|
* Note this is only called during an 'execute'. E.g., a modification to the 'base value' of an attribute. It is not called during an application of a GameplayEffect, such as a 5 ssecond +10 movement speed buff.
|
||||||
|
*/
|
||||||
|
virtual void PostGameplayEffectExecute(const struct FGameplayEffectModCallbackData& Data) override;
|
||||||
|
|
||||||
ATTRIBUTE_ACCESSORS(UCAttributeSet, Health);
|
ATTRIBUTE_ACCESSORS(UCAttributeSet, Health);
|
||||||
ATTRIBUTE_ACCESSORS(UCAttributeSet, MaxHealth);
|
ATTRIBUTE_ACCESSORS(UCAttributeSet, MaxHealth);
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ UCLASS()
|
|||||||
class CRUNCH_API UCGameplayAbility : public UGameplayAbility
|
class CRUNCH_API UCGameplayAbility : public UGameplayAbility
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
UAnimInstance* GetOwnerAnimInstance();
|
UAnimInstance* GetOwnerAnimInstance() const;
|
||||||
|
TArray<FHitResult> GetHitResultFromSweepLocationTargetData(const FGameplayAbilityTargetDataHandle& TargetDataHandle,
|
||||||
|
float SphereSweepRadius = 30.f, bool bDrawDebug = false,
|
||||||
|
bool bIgnoreSelf = true) const;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ public:
|
|||||||
const FGameplayEventData* TriggerEventData) override;
|
const FGameplayEventData* TriggerEventData) override;
|
||||||
static FGameplayTag GetComboChangedEventTag();
|
static FGameplayTag GetComboChangedEventTag();
|
||||||
static FGameplayTag GetComboChangedEventEndTag();
|
static FGameplayTag GetComboChangedEventEndTag();
|
||||||
|
static FGameplayTag GetComboTargetEventTag();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UFUNCTION()
|
UFUNCTION()
|
||||||
@@ -29,11 +30,24 @@ private:
|
|||||||
void SetupWaitComboInputPressed();
|
void SetupWaitComboInputPressed();
|
||||||
void TryCommitCombo();
|
void TryCommitCombo();
|
||||||
|
|
||||||
|
UPROPERTY(EditDefaultsOnly, Category="Targetting")
|
||||||
|
float TargetSweepSphereRadius{30.f};
|
||||||
|
|
||||||
|
UPROPERTY(EditDefaultsOnly, Category="Gameplay Effect")
|
||||||
|
TSubclassOf<UGameplayEffect> DefaultEffectClass;
|
||||||
|
UPROPERTY(EditDefaultsOnly, Category="Gameplay Effect")
|
||||||
|
TMap<FName, TSubclassOf<UGameplayEffect>> DamageEffectMap;
|
||||||
|
|
||||||
|
TSubclassOf<UGameplayEffect> GetDamageEffectForCurrentCombo() const;
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, Category="Amination")
|
UPROPERTY(EditDefaultsOnly, Category="Amination")
|
||||||
TObjectPtr<UAnimMontage> ComboMontage;
|
TObjectPtr<UAnimMontage> ComboMontage;
|
||||||
|
|
||||||
UFUNCTION()
|
UFUNCTION()
|
||||||
void ComboChangedEventReceived(FGameplayEventData Data);
|
void ComboChangedEventReceived(FGameplayEventData Data);
|
||||||
|
|
||||||
|
UFUNCTION()
|
||||||
|
void DoDamage(FGameplayEventData Data);
|
||||||
|
|
||||||
FName NextComboName;
|
FName NextComboName;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user