355 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
		
		
			
		
	
	
			355 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| 
								 | 
							
								## UGameplayEffect
							 | 
						|||
| 
								 | 
							
								UGameplayEffect在框架中主要负责各种数值上的效果,如果技能cd、类似黑魂中的异常效果堆叠与buff,甚至连角色升级时的属性点添加都可以使用它来实现。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								因为大多数逻辑都是设置数据子类的操作,所以对于这个类,本人推荐使用蓝图来进行操作。
							 | 
						|||
| 
								 | 
							
								## 简单使用教程
							 | 
						|||
| 
								 | 
							
								通过继承UGameplayEffect来创建一个新的GameplayEffect类,并在构造函数中对相应的属性进行设置。之后在Ability类中调用ApplyGameplayEffectToOwner函数让GameplayEffect生效。
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								if (CommitAbility(Handle, ActorInfo, ActivationInfo))		// ..then commit the ability...
							 | 
						|||
| 
								 | 
							
								{			
							 | 
						|||
| 
								 | 
							
									//	Then do more stuff...
							 | 
						|||
| 
								 | 
							
									const UGameplayEffect* GameplayEffect = NewObject<UGE_DamageBase>();
							 | 
						|||
| 
								 | 
							
									ApplyGameplayEffectToOwner(CurrentSpecHandle, CurrentActorInfo, CurrentActivationInfo, GameplayEffect, 5, 1);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									K2_EndAbility();
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								具体操作可以参考ActionRPG模板,或者是我的项目代码。
							 | 
						|||
| 
								 | 
							
								## Modifiers
							 | 
						|||
| 
								 | 
							
								本质是一个FGameplayModifierInfo结构体数组用于存储所有数值修改信息。FGameplayModifierInfo包含以下属性:
							 | 
						|||
| 
								 | 
							
								- Attribute 修改的目标属性集中的属性。
							 | 
						|||
| 
								 | 
							
								- ModifierOp 修改方式。例如Override、Add、Multiply。
							 | 
						|||
| 
								 | 
							
								- Magnitude(已被废弃)
							 | 
						|||
| 
								 | 
							
								- ModifierMagnitude 修改的数值与类型,可以配置数据表。
							 | 
						|||
| 
								 | 
							
								- EvaluationChannelSettings (不知道为什么没在编辑器中显示,而且代码中只有一处调用,所以直接跳过)
							 | 
						|||
| 
								 | 
							
								- SourceTags  本身标签行为(Effect生效所需或者忽略的标签)
							 | 
						|||
| 
								 | 
							
								- TargetTags  目标标签行为(Effect生效所需或者忽略的标签)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								可以看得出ModifierMagnitude才是Modifiers的关键,而它的本质是FGameplayEffectModifierMagnitude结构体。但是我们只需要学会初始化它即可。它具有以下四种类型:
							 | 
						|||
| 
								 | 
							
								- ScalableFloat 较为简单的使用方式,使用ScalableFloat进行计算
							 | 
						|||
| 
								 | 
							
								- AttributeBased 基于属性执行计算。
							 | 
						|||
| 
								 | 
							
								- CustomCalculationClass 能够捕获多个属性进行自定义计算
							 | 
						|||
| 
								 | 
							
								- SetByCaller 被蓝图或者代码显式设置
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								### ScalableFloat的调用示例
							 | 
						|||
| 
								 | 
							
								ScalableFloat类型是用于设置固定值的简单方式,同时它也支持通过CurveTable配合技能等级设置倍率。(最后结果=固定值*倍率)当然如果你向完全通过CurveTable来控制参数,那就把固定值设置为1即可。
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								FGameplayModifierInfo info;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								info.Attribute = FGameplayAttribute(FindFieldChecked<UProperty>(URPGAttributeSet::StaticClass(), GET_MEMBER_NAME_CHECKED(URPGAttributeSet, Health)));
							 | 
						|||
| 
								 | 
							
								info.ModifierOp = EGameplayModOp::Additive;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								//固定值
							 | 
						|||
| 
								 | 
							
								//info.ModifierMagnitude = FGameplayEffectModifierMagnitude(FScalableFloat(100.0));
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								//CurveTable控制倍率
							 | 
						|||
| 
								 | 
							
								FScalableFloat damageValue = {1.0};
							 | 
						|||
| 
								 | 
							
								FCurveTableRowHandle damageCurve;
							 | 
						|||
| 
								 | 
							
								static ConstructorHelpers::FObjectFinder<UCurveTable> curveAsset(TEXT("/Game/ActionRPG/DataTable/Damage"));
							 | 
						|||
| 
								 | 
							
								damageCurve.CurveTable = curveAsset.Object;
							 | 
						|||
| 
								 | 
							
								damageCurve.RowName = FName("Damage");
							 | 
						|||
| 
								 | 
							
								damageValue.Curve = damageCurve;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								info.ModifierMagnitude = FGameplayEffectModifierMagnitude(damageValue);
							 | 
						|||
| 
								 | 
							
								Modifiers.Add(info);
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								PS.技能等级在ApplyGameplayEffectToOwner函数中设置。
							 | 
						|||
| 
								 | 
							
								### AttributeBased的调用示例
							 | 
						|||
| 
								 | 
							
								最终计算过程可以在CalculateMagnitude函数中找到。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								1. 如果尝试捕获到数值(不为None),则将赋值给AttribValue。
							 | 
						|||
| 
								 | 
							
								2. 判断AttributeCalculationType,来计算对应的AttribValue。(我不太了解代码中channel的概念,如果channel不存在,AttribValue为原本值)
							 | 
						|||
| 
								 | 
							
								3. 如果AttributeCurve存在,则将AttribValue作为x轴值来查找y轴值,并进行插值计算,最后将结果赋值给AttribValue。
							 | 
						|||
| 
								 | 
							
								4. 最终计算公式:`$((Coefficient * (AttribValue + PreMultiplyAdditiveValue)) + PostMultiplyAdditiveValue)$`
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								### BackingAttribute
							 | 
						|||
| 
								 | 
							
								为GameplayEffect捕获GameplayAttribute的选项。(你可以理解为Lambda表达式的捕获)
							 | 
						|||
| 
								 | 
							
								- AttributeToCapture:捕获属性
							 | 
						|||
| 
								 | 
							
								- AttributeSource:捕获的目标(自身还是目标对象)
							 | 
						|||
| 
								 | 
							
								- bSnapshot:属性是否需要被快照(没仔细看,如果为false,每次都会重新获取吧)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								### AttributeCalculationType
							 | 
						|||
| 
								 | 
							
								默认值为AttributeMagnitude。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								- AttributeMagnitude:使用最后通过属性计算出来的级数
							 | 
						|||
| 
								 | 
							
								- AttributeBaseValue:使用属性基础值
							 | 
						|||
| 
								 | 
							
								- AttributeBonusMagnitude:使用(最后计算值-基础值)
							 | 
						|||
| 
								 | 
							
								- AttributeMagnitudeEvaluatedUpToChannel:不清楚使用方法,关键是在编辑器中,这个选项默认是不显示的
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								FGameplayModifierInfo info;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								info.Attribute = FGameplayAttribute(FindFieldChecked<UProperty>(URPGAttributeSet::StaticClass(), GET_MEMBER_NAME_CHECKED(URPGAttributeSet, Health)));
							 | 
						|||
| 
								 | 
							
								info.ModifierOp = EGameplayModOp::Additive;
							 | 
						|||
| 
								 | 
							
								FAttributeBasedFloat damageValue;
							 | 
						|||
| 
								 | 
							
								damageValue.Coefficient = { 1.2f };
							 | 
						|||
| 
								 | 
							
								damageValue.PreMultiplyAdditiveValue = { 1.0f };
							 | 
						|||
| 
								 | 
							
								damageValue.PostMultiplyAdditiveValue = { 2.0f };
							 | 
						|||
| 
								 | 
							
								damageValue.BackingAttribute = FGameplayEffectAttributeCaptureDefinition(FGameplayAttribute(FindFieldChecked<UProperty>(URPGAttributeSet::StaticClass(), GET_MEMBER_NAME_CHECKED(URPGAttributeSet, Health)))
							 | 
						|||
| 
								 | 
							
									, EGameplayEffectAttributeCaptureSource::Source, false);
							 | 
						|||
| 
								 | 
							
								FCurveTableRowHandle damageCurve;
							 | 
						|||
| 
								 | 
							
								static ConstructorHelpers::FObjectFinder<UCurveTable> curveAsset(TEXT("/Game/ActionRPG/DataTable/Damage"));
							 | 
						|||
| 
								 | 
							
								damageCurve.CurveTable = curveAsset.Object;
							 | 
						|||
| 
								 | 
							
								damageCurve.RowName = FName("Damage");
							 | 
						|||
| 
								 | 
							
								damageValue.AttributeCurve = damageCurve;
							 | 
						|||
| 
								 | 
							
								damageValue.AttributeCalculationType = EAttributeBasedFloatCalculationType::AttributeMagnitude;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								info.ModifierMagnitude = damageValue;
							 | 
						|||
| 
								 | 
							
								Modifiers.Add(info);
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								### CustomCalculationClass的调用示例
							 | 
						|||
| 
								 | 
							
								与AttributeCalculationType相比,少了属性捕获,多了CalculationClassMagnitude(UGameplayModMagnitudeCalculation类)。
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								FGameplayModifierInfo info;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								info.Attribute = FGameplayAttribute(FindFieldChecked<UProperty>(URPGAttributeSet::StaticClass(), GET_MEMBER_NAME_CHECKED(URPGAttributeSet, Health)));
							 | 
						|||
| 
								 | 
							
								info.ModifierOp = EGameplayModOp::Additive;
							 | 
						|||
| 
								 | 
							
								FCustomCalculationBasedFloat damageValue;
							 | 
						|||
| 
								 | 
							
								damageValue.CalculationClassMagnitude = UDamageMagnitudeCalculation::StaticClass();
							 | 
						|||
| 
								 | 
							
								damageValue.Coefficient = { 1.2f };
							 | 
						|||
| 
								 | 
							
								damageValue.PreMultiplyAdditiveValue = { 1.0f };
							 | 
						|||
| 
								 | 
							
								damageValue.PostMultiplyAdditiveValue = { 2.0f };
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								info.ModifierMagnitude = damageValue;
							 | 
						|||
| 
								 | 
							
								Modifiers.Add(info);
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								PS.如果这个计算过程还取决于外部非GameplayAbility框架的条件,那么你可能需要重写GetExternalModifierDependencyMulticast()函数,以获得FOnExternalGameplayModifierDependencyChange委托。从而实现:当外部条件发生改变时,及时更新计算结果。
							 | 
						|||
| 
								 | 
							
								### UGameplayModMagnitudeCalculation
							 | 
						|||
| 
								 | 
							
								你可以通过继承UGameplayModMagnitudeCalculation来创建自定义的Calculation类。所需实现步骤如下:
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								1. 在构造函数中,向RelevantAttributesToCapture数组添加需要捕获的属性。
							 | 
						|||
| 
								 | 
							
								2. 实现CalculateBaseMagnitude事件。(因为BlueprintNativeEvent类型,所以既可以在c++里实现也可以在蓝图中实现,关于两者结合可以参考UGameplayAbility类中ActivateAbility()的写法。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								案例代码如下:
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								UCLASS(BlueprintType, Blueprintable, Abstract)
							 | 
						|||
| 
								 | 
							
								class ACTIONRPG_API UDamageMagnitudeCalculation : public UGameplayModMagnitudeCalculation
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									GENERATED_BODY()
							 | 
						|||
| 
								 | 
							
								public:
							 | 
						|||
| 
								 | 
							
									UDamageMagnitudeCalculation();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									float CalculateBaseMagnitude_Implementation(const FGameplayEffectSpec& Spec) const override;
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								UDamageMagnitudeCalculation::UDamageMagnitudeCalculation()
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									RelevantAttributesToCapture.Add(FGameplayEffectAttributeCaptureDefinition(FGameplayAttribute(FindFieldChecked<UProperty>(URPGAttributeSet::StaticClass(), GET_MEMBER_NAME_CHECKED(URPGAttributeSet, Health)))
							 | 
						|||
| 
								 | 
							
										, EGameplayEffectAttributeCaptureSource::Source, false));
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								float UDamageMagnitudeCalculation::CalculateBaseMagnitude_Implementation(const FGameplayEffectSpec& Spec) const
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									float damage{ 0.0f};
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									FAggregatorEvaluateParameters InEvalParams;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									//捕获失败的容错语句
							 | 
						|||
| 
								 | 
							
									if (!GetCapturedAttributeMagnitude(FGameplayEffectAttributeCaptureDefinition(FGameplayAttribute(FindFieldChecked<UProperty>(URPGAttributeSet::StaticClass(), GET_MEMBER_NAME_CHECKED(URPGAttributeSet, Health)))
							 | 
						|||
| 
								 | 
							
										, EGameplayEffectAttributeCaptureSource::Source, false), Spec, InEvalParams, damage)) {
							 | 
						|||
| 
								 | 
							
										
							 | 
						|||
| 
								 | 
							
										//如果这个变量会作为除数的话,不能为0
							 | 
						|||
| 
								 | 
							
										damage = 1.0f;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									return damage;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								## Executions
							 | 
						|||
| 
								 | 
							
								Executions更为简单,而且更加自由。只需要编写Calculation Class即可。它与Modifiers的不同之处在于:一个Modifiers只能修改一个属性,而Executions可以同时改动多个属性。
							 | 
						|||
| 
								 | 
							
								### UGameplayEffectExecutionCalculation    
							 | 
						|||
| 
								 | 
							
								这里我就直接复制actionRPG模板的代码了。
							 | 
						|||
| 
								 | 
							
								开头的RPGDamageStatics结构体与DamageStatics函数,可以减少后面的代码量。可以算是FGameplayEffectAttributeCaptureDefinition的语法糖吧。
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								UCLASS()
							 | 
						|||
| 
								 | 
							
								class ACTIONRPG_API UDamageExecutionCalculation : public UGameplayEffectExecutionCalculation
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									GENERATED_BODY()
							 | 
						|||
| 
								 | 
							
								public:
							 | 
						|||
| 
								 | 
							
									UDamageExecutionCalculation();
							 | 
						|||
| 
								 | 
							
									virtual void Execute_Implementation(const FGameplayEffectCustomExecutionParameters& ExecutionParams, OUT FGameplayEffectCustomExecutionOutput& OutExecutionOutput) const override;
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								struct RPGDamageStatics
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									DECLARE_ATTRIBUTE_CAPTUREDEF(DefensePower);
							 | 
						|||
| 
								 | 
							
									DECLARE_ATTRIBUTE_CAPTUREDEF(AttackPower);
							 | 
						|||
| 
								 | 
							
									DECLARE_ATTRIBUTE_CAPTUREDEF(Damage);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									RPGDamageStatics()
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										// Capture the Target's DefensePower attribute. Do not snapshot it, because we want to use the health value at the moment we apply the execution.
							 | 
						|||
| 
								 | 
							
										DEFINE_ATTRIBUTE_CAPTUREDEF(URPGAttributeSet, DefensePower, Target, false);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										// Capture the Source's AttackPower. We do want to snapshot this at the moment we create the GameplayEffectSpec that will execute the damage.
							 | 
						|||
| 
								 | 
							
										// (imagine we fire a projectile: we create the GE Spec when the projectile is fired. When it hits the target, we want to use the AttackPower at the moment
							 | 
						|||
| 
								 | 
							
										// the projectile was launched, not when it hits).
							 | 
						|||
| 
								 | 
							
										DEFINE_ATTRIBUTE_CAPTUREDEF(URPGAttributeSet, AttackPower, Source, true);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										// Also capture the source's raw Damage, which is normally passed in directly via the execution
							 | 
						|||
| 
								 | 
							
										DEFINE_ATTRIBUTE_CAPTUREDEF(URPGAttributeSet, Damage, Source, true);
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								static const RPGDamageStatics& DamageStatics()
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									static RPGDamageStatics DmgStatics;
							 | 
						|||
| 
								 | 
							
									return DmgStatics;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								UDamageExecutionCalculation::UDamageExecutionCalculation()
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									RelevantAttributesToCapture.Add(DamageStatics().DefensePowerDef);
							 | 
						|||
| 
								 | 
							
									RelevantAttributesToCapture.Add(DamageStatics().AttackPowerDef);
							 | 
						|||
| 
								 | 
							
									RelevantAttributesToCapture.Add(DamageStatics().DamageDef);
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								void UDamageExecutionCalculation::Execute_Implementation(const FGameplayEffectCustomExecutionParameters& ExecutionParams, OUT FGameplayEffectCustomExecutionOutput& OutExecutionOutput) const
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									UAbilitySystemComponent* TargetAbilitySystemComponent = ExecutionParams.GetTargetAbilitySystemComponent();
							 | 
						|||
| 
								 | 
							
									UAbilitySystemComponent* SourceAbilitySystemComponent = ExecutionParams.GetSourceAbilitySystemComponent();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									AActor* SourceActor = SourceAbilitySystemComponent ? SourceAbilitySystemComponent->AvatarActor : nullptr;
							 | 
						|||
| 
								 | 
							
									AActor* TargetActor = TargetAbilitySystemComponent ? TargetAbilitySystemComponent->AvatarActor : nullptr;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									const FGameplayEffectSpec& Spec = ExecutionParams.GetOwningSpec();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// Gather the tags from the source and target as that can affect which buffs should be used
							 | 
						|||
| 
								 | 
							
									const FGameplayTagContainer* SourceTags = Spec.CapturedSourceTags.GetAggregatedTags();
							 | 
						|||
| 
								 | 
							
									const FGameplayTagContainer* TargetTags = Spec.CapturedTargetTags.GetAggregatedTags();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									FAggregatorEvaluateParameters EvaluationParameters;
							 | 
						|||
| 
								 | 
							
									EvaluationParameters.SourceTags = SourceTags;
							 | 
						|||
| 
								 | 
							
									EvaluationParameters.TargetTags = TargetTags;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// --------------------------------------
							 | 
						|||
| 
								 | 
							
									//	Damage Done = Damage * AttackPower / DefensePower
							 | 
						|||
| 
								 | 
							
									//	If DefensePower is 0, it is treated as 1.0
							 | 
						|||
| 
								 | 
							
									// --------------------------------------
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									//计算捕获属性的数值。
							 | 
						|||
| 
								 | 
							
									float DefensePower = 0.f;
							 | 
						|||
| 
								 | 
							
									ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().DefensePowerDef, EvaluationParameters, DefensePower);
							 | 
						|||
| 
								 | 
							
									//因为要做除数所以需要加入容错语句
							 | 
						|||
| 
								 | 
							
									if (DefensePower == 0.0f)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										DefensePower = 1.0f;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									float AttackPower = 0.f;
							 | 
						|||
| 
								 | 
							
									ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().AttackPowerDef, EvaluationParameters, AttackPower);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									float Damage = 0.f;
							 | 
						|||
| 
								 | 
							
									ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().DamageDef, EvaluationParameters, Damage);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									//伤害计算公式
							 | 
						|||
| 
								 | 
							
									float DamageDone = Damage * AttackPower / DefensePower;
							 | 
						|||
| 
								 | 
							
									if (DamageDone > 0.f)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										//这里可以修改多个属性
							 | 
						|||
| 
								 | 
							
										OutExecutionOutput.AddOutputModifier(FGameplayModifierEvaluatedData(DamageStatics().DamageProperty, EGameplayModOp::Additive, DamageDone));
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								## Period
							 | 
						|||
| 
								 | 
							
								Period指的是周期,一般用于制作周期性技能。
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								//持续类型,只有设置为HasDuration,技能才能变成周期性的
							 | 
						|||
| 
								 | 
							
								DurationPolicy = EGameplayEffectDurationType::HasDuration;
							 | 
						|||
| 
								 | 
							
								//持续时间
							 | 
						|||
| 
								 | 
							
								DurationMagnitude = FGameplayEffectModifierMagnitude(1.0);
							 | 
						|||
| 
								 | 
							
								//周期,技能生效次数=持续时间/周期
							 | 
						|||
| 
								 | 
							
								Period = 2.0;
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								# FGameplayEffectContainer与Spec
							 | 
						|||
| 
								 | 
							
								EPIC实现了这个结构体
							 | 
						|||
| 
								 | 
							
								调用URPGGameplayAbility::MakeEffectContainerSpecFromContainer
							 | 
						|||
| 
								 | 
							
								使用FGameplayEffectContainer生成FGameplayEffectContainerSpec结构体。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Spec是实例版本,存储TargetDataHandle与EffectSpecHandle。通过MakeEffectContainerSpecFromContainer进行实例化(但本质是通过Spec的AddTarget进行数据填充)。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								之后再通过
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								ReturnSpec.TargetGameplayEffectSpecs.Add(MakeOutgoingGameplayEffectSpec(EffectClass, OverrideGameplayLevel));
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								填充EffectSpec数据。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								**MakeEffectContainerSpec则是个快捷函数**
							 | 
						|||
| 
								 | 
							
								通过FGameplayTag寻找对应的Effect与Target数据。EventData则用于调用TargetType类的GetTarget函数,用于获取符合要求的目标(Actor)。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								在ActionRPG中URPGTargetType_UseEventData的GetTarget用到了EventData。大致逻辑为首先寻找EventData里是否带有EventData.HitResult信息(可以在Send Event To Actor中设置),如果没有则返回EventData.Target信息。
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								void URPGTargetType_UseEventData::GetTargets_Implementation(ARPGCharacterBase* TargetingCharacter, AActor* TargetingActor, FGameplayEventData EventData, TArray<FHitResult>& OutHitResults, TArray<AActor*>& OutActors) const
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									const FHitResult* FoundHitResult = EventData.ContextHandle.GetHitResult();
							 | 
						|||
| 
								 | 
							
									if (FoundHitResult)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										OutHitResults.Add(*FoundHitResult);
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
									else if (EventData.Target)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										OutActors.Add(const_cast<AActor*>(EventData.Target));
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								ApplyEffectContainer则是个方便函数。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								# 实现在AnimNotify中向指定目标引用GameplayEffect
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								从GameplayAbilityComponent或者从GameplayAbility中设置.
							 | 
						|||
| 
								 | 
							
								MakeOutgoingGameplayEffectSpec=>
							 | 
						|||
| 
								 | 
							
								ApplyGameplayEffectSpecToTarget 位于UGameplayAbility
							 | 
						|||
| 
								 | 
							
								ApplyGameplayEffectToTarget
							 | 
						|||
| 
								 | 
							
								GameplayEffectSpec.GetContext().AddTarget()
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								RemoveGrantedByEffect()函数可以移除Ability中Instance类型的Effect。非常适合来清除翻滚免伤、技能硬直效果。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								FRPGGameplayEffectContainerSpec URPGBlueprintLibrary::AddTargetsToEffectContainerSpec(const FRPGGameplayEffectContainerSpec& ContainerSpec, const TArray<FHitResult>& HitResults, const TArray<AActor*>& TargetActors)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									FRPGGameplayEffectContainerSpec NewSpec = ContainerSpec;
							 | 
						|||
| 
								 | 
							
									NewSpec.AddTargets(HitResults, TargetActors);
							 | 
						|||
| 
								 | 
							
									return NewSpec;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								TArray<FActiveGameplayEffectHandle> URPGBlueprintLibrary::ApplyExternalEffectContainerSpec(const FRPGGameplayEffectContainerSpec& ContainerSpec)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									TArray<FActiveGameplayEffectHandle> AllEffects;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// Iterate list of gameplay effects
							 | 
						|||
| 
								 | 
							
									for (const FGameplayEffectSpecHandle& SpecHandle : ContainerSpec.TargetGameplayEffectSpecs)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										if (SpecHandle.IsValid())
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											// If effect is valid, iterate list of targets and apply to all
							 | 
						|||
| 
								 | 
							
											for (TSharedPtr<FGameplayAbilityTargetData> Data : ContainerSpec.TargetData.Data)
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												AllEffects.Append(Data->ApplyGameplayEffectSpec(*SpecHandle.Data.Get()));
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
									return AllEffects;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								FGameplayEffectSpecHandle SpecHandle = MakeOutgoingGameplayEffectSpec(Handle, ActorInfo, ActivationInfo, GameplayEffectClass, GameplayEffectLevel);
							 | 
						|||
| 
								 | 
							
								if (SpecHandle.Data.IsValid())
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									SpecHandle.Data->StackCount = Stacks;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									SCOPE_CYCLE_UOBJECT(Source, SpecHandle.Data->GetContext().GetSourceObject());
							 | 
						|||
| 
								 | 
							
									EffectHandles.Append(ApplyGameplayEffectSpecToTarget(Handle, ActorInfo, ActivationInfo, SpecHandle, Target));
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								# 实用函数
							 | 
						|||
| 
								 | 
							
								Wait Input Release
							 |