/** * Makes the Character try to jump using the standard Character->Jump. * This is an example of a non-instanced ability. */ UCLASS() classGASDOCUMENTATION_API UGDGA_CharacterJump : public UGDGameplayAbility { GENERATED_BODY()
// Play fire montage and wait for event telling us to spawn the projectile UGDAT_PlayMontageAndWaitForEvent* Task = UGDAT_PlayMontageAndWaitForEvent::PlayMontageAndWaitForEvent( this, NAME_None, MontageToPlay, FGameplayTagContainer(), 1.0f, NAME_None, false, 1.0f);
Task->OnBlendOut.AddDynamic(this, &UGDGA_FireGun::OnCompleted); Task->OnCompleted.AddDynamic(this, &UGDGA_FireGun::OnCompleted); Task->OnInterrupted.AddDynamic(this, &UGDGA_FireGun::OnCancelled); Task->OnCancelled.AddDynamic(this, &UGDGA_FireGun::OnCancelled); Task->EventReceived.AddDynamic(this, &UGDGA_FireGun::EventReceived); // ReadyForActivation() is how you activate the AbilityTask in C++. // Blueprint has magic from K2Node_LatentGameplayTaskCall that will automatically call ReadyForActivation(). Task->ReadyForActivation(); }
乍一看十分复杂,我们先不管 MontageToPlay 的选择部分,直接看最为核心的一段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// Play fire montage and wait for event telling us to spawn the projectile UGDAT_PlayMontageAndWaitForEvent* Task = UGDAT_PlayMontageAndWaitForEvent::PlayMontageAndWaitForEvent( this, NAME_None, MontageToPlay, FGameplayTagContainer(), 1.0f, NAME_None, false, 1.0f);
// ReadyForActivation() is how you activate the AbilityTask in C++. // Blueprint has magic from K2Node_LatentGameplayTaskCall that will automatically call ReadyForActivation(). Task->ReadyForActivation();
voidUGDGA_FireGun::EventReceived(FGameplayTag EventTag, FGameplayEventData EventData) { // Montage told us to end the ability before the montage finished playing. // Montage was set to continue playing animation even after ability ends so this is okay. if (EventTag == FGameplayTag::RequestGameplayTag(FName("Event.Montage.EndAbility"))) { EndAbility(CurrentSpecHandle, CurrentActorInfo, CurrentActivationInfo, true, false); return; }
// Only spawn projectiles on the Server. // Predicting projectiles is an advanced topic not covered in this example. if (GetOwningActorFromActorInfo()->GetLocalRole() == ROLE_Authority && EventTag == FGameplayTag::RequestGameplayTag(FName("Event.Montage.SpawnProjectile"))) { AGDHeroCharacter* Hero = Cast<AGDHeroCharacter>(GetAvatarActorFromActorInfo()); if (!Hero) { EndAbility(CurrentSpecHandle, CurrentActorInfo, CurrentActivationInfo, true, true); }
FGameplayEffectSpecHandle DamageEffectSpecHandle = MakeOutgoingGameplayEffectSpec(DamageGameplayEffect, GetAbilityLevel()); // Pass the damage to the Damage Execution Calculation through a SetByCaller value // on the GameplayEffectSpec DamageEffectSpecHandle.Data.Get()->SetSetByCallerMagnitude( FGameplayTag::RequestGameplayTag(FName("Data.Damage")), Damage);
// Pass the damage to the Damage Execution Calculation through a SetByCaller value // on the GameplayEffectSpec DamageEffectSpecHandle.Data.Get()->SetSetByCallerMagnitude( FGameplayTag::RequestGameplayTag(FName("Data.Damage")), Damage);
GDDamageStatics() { // Snapshot happens at time of GESpec creation // We're not capturing anything from the Source in this example, // but there could be like AttackPower attributes that you might want.
// Capture optional Damage set on the damage GE as a CalculationModifier under the ExecutionCalculation DEFINE_ATTRIBUTE_CAPTUREDEF(UGDAttributeSetBase, Damage, Source, true);
float Damage = 0.0f; // Capture optional damage value set on the damage GE as a CalculationModifier under the ExecutionCalculation ExecutionParams.AttemptCalculateCapturedAttributeMagnitude( DamageStatics().DamageDef, EvaluationParameters, Damage); // Add SetByCaller damage if it exists Damage += FMath::Max<float>( Spec.GetSetByCallerMagnitude(FGameplayTag::RequestGameplayTag(FName("Data.Damage")), false, -1.0f), 0.0f);
float UnmitigatedDamage = Damage; // Can multiply any damage boosters here
if (MitigatedDamage > 0.f) { // Set the Target's damage meta attribute OutExecutionOutput.AddOutputModifier( FGameplayModifierEvaluatedData( DamageStatics().DamageProperty, EGameplayModOp::Additive, MitigatedDamage ) ); }