98 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			98 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
## 前言
 | 
						||
之前使用GameplayTasks的事件处理会出现延迟问题。具体体现在如果使用机制来添加BlockAbilityTag,在狂按技能的情况下会出现Tag不能正常生成导致可以不停ActivateAbility的问题。
 | 
						||
 | 
						||
## 问题成因
 | 
						||
1. 问题的原因就是使用GameplayTasks不能即时添加GE,会有一定延迟。
 | 
						||
2. 清除GameplayEffect方式有问题,应该使用只清除该技能所附加的GE。
 | 
						||
 | 
						||
## 解决思路
 | 
						||
在解决清除GE问题的情况下:
 | 
						||
 | 
						||
1. GASDocument中的解决方法:使用AbilityTag作为BlockAbilityTag,之后通过AnimNotify发送EndAbility事件Tag,提前结束Ability。(不会结束掉Montage播放)
 | 
						||
2. 在AnimNotifyBegin函数中直接添加GE,根据TotalDuration设置持续时间。(但如果Montage突然被中断,就很难操作了,而且这样会与Ability耦合)
 | 
						||
3. 增加公共CD(测试过效果不佳)
 | 
						||
 | 
						||
## PlayMontage修改
 | 
						||
1. 传递事件使用专门的Event.Montage.xxxx作为事件标签
 | 
						||
2. 重写AnimNotify的GetNotifyName函数,使用标签名作为AnimNotify的显示名称。
 | 
						||
 | 
						||
 | 
						||
```
 | 
						||
void UGDGA_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);
 | 
						||
		}
 | 
						||
 | 
						||
		FVector Start = Hero->GetGunComponent()->GetSocketLocation(FName("Muzzle"));
 | 
						||
		FVector End = Hero->GetCameraBoom()->GetComponentLocation() + Hero->GetFollowCamera()->GetForwardVector() * Range;
 | 
						||
		FRotator Rotation = UKismetMathLibrary::FindLookAtRotation(Start, End);
 | 
						||
 | 
						||
		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);
 | 
						||
 | 
						||
		FTransform MuzzleTransform = Hero->GetGunComponent()->GetSocketTransform(FName("Muzzle"));
 | 
						||
		MuzzleTransform.SetRotation(Rotation.Quaternion());
 | 
						||
		MuzzleTransform.SetScale3D(FVector(1.0f));
 | 
						||
 | 
						||
		FActorSpawnParameters SpawnParameters;
 | 
						||
		SpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
 | 
						||
 | 
						||
		AGDProjectile* Projectile = GetWorld()->SpawnActorDeferred<AGDProjectile>(ProjectileClass, MuzzleTransform, GetOwningActorFromActorInfo(),
 | 
						||
			Hero, ESpawnActorCollisionHandlingMethod::AlwaysSpawn);
 | 
						||
		Projectile->DamageEffectSpecHandle = DamageEffectSpecHandle;
 | 
						||
		Projectile->Range = Range;
 | 
						||
		Projectile->FinishSpawning(MuzzleTransform);
 | 
						||
	}
 | 
						||
}
 | 
						||
```
 | 
						||
 | 
						||
 | 
						||
```
 | 
						||
	/** Apply a gameplay effect to the owner of this ability */
 | 
						||
	UFUNCTION(BlueprintCallable, Category = Ability, DisplayName="ApplyGameplayEffectToOwner", meta=(ScriptName="ApplyGameplayEffectToOwner"))
 | 
						||
	FActiveGameplayEffectHandle BP_ApplyGameplayEffectToOwner(TSubclassOf<UGameplayEffect> GameplayEffectClass, int32 GameplayEffectLevel = 1, int32 Stacks = 1);
 | 
						||
 | 
						||
	/** Non blueprintcallable, safe to call on CDO/NonInstance abilities */
 | 
						||
	FActiveGameplayEffectHandle ApplyGameplayEffectToOwner(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const UGameplayEffect* GameplayEffect, float GameplayEffectLevel, int32 Stacks = 1) const;
 | 
						||
 | 
						||
	/** Apply a previously created gameplay effect spec to the owner of this ability */
 | 
						||
	UFUNCTION(BlueprintCallable, Category = Ability, DisplayName = "ApplyGameplayEffectSpecToOwner", meta=(ScriptName = "ApplyGameplayEffectSpecToOwner"))
 | 
						||
	FActiveGameplayEffectHandle K2_ApplyGameplayEffectSpecToOwner(const FGameplayEffectSpecHandle EffectSpecHandle);
 | 
						||
 | 
						||
	FActiveGameplayEffectHandle ApplyGameplayEffectSpecToOwner(const FGameplayAbilitySpecHandle AbilityHandle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEffectSpecHandle SpecHandle) const;
 | 
						||
 | 
						||
	// -------------------------------------
 | 
						||
	//  Apply Gameplay effects to Target
 | 
						||
	// -------------------------------------
 | 
						||
 | 
						||
	/** Apply a gameplay effect to a Target */
 | 
						||
	UFUNCTION(BlueprintCallable, Category = Ability, DisplayName = "ApplyGameplayEffectToTarget", meta=(ScriptName = "ApplyGameplayEffectToTarget"))
 | 
						||
	TArray<FActiveGameplayEffectHandle> BP_ApplyGameplayEffectToTarget(FGameplayAbilityTargetDataHandle TargetData, TSubclassOf<UGameplayEffect> GameplayEffectClass, int32 GameplayEffectLevel = 1, int32 Stacks = 1);
 | 
						||
 | 
						||
	/** Non blueprintcallable, safe to call on CDO/NonInstance abilities */
 | 
						||
	TArray<FActiveGameplayEffectHandle> ApplyGameplayEffectToTarget(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayAbilityTargetDataHandle& Target, TSubclassOf<UGameplayEffect> GameplayEffectClass, float GameplayEffectLevel, int32 Stacks = 1) const;
 | 
						||
 | 
						||
	/** Apply a previously created gameplay effect spec to a target */
 | 
						||
	UFUNCTION(BlueprintCallable, Category = Ability, DisplayName = "ApplyGameplayEffectSpecToTarget", meta=(ScriptName = "ApplyGameplayEffectSpecToTarget"))
 | 
						||
	TArray<FActiveGameplayEffectHandle> K2_ApplyGameplayEffectSpecToTarget(const FGameplayEffectSpecHandle EffectSpecHandle, FGameplayAbilityTargetDataHandle TargetData);
 | 
						||
 | 
						||
	TArray<FActiveGameplayEffectHandle> ApplyGameplayEffectSpecToTarget(const FGameplayAbilitySpecHandle AbilityHandle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEffectSpecHandle SpecHandle, const FGameplayAbilityTargetDataHandle& TargetData) const;
 | 
						||
 | 
						||
``` |