5. 常见的技能和效果 - Commonly Implemented Abilities and Effects

5.1 眩晕 - Stun

通常在眩晕效果下,我们希望取消Character所有的处于激活状态的GameplayAbilities,同时阻止新的GameplayAbility的激活甚至是移动。示例项目中的流星GameplayAbility就会给其命中的目标施加一个眩晕的效果。

要取消目标身上激活的GameplayAbilities,我们可以在相应GameplayTag被添加时时调用AbilitySystemComponent->CancelAbilities()

要实现阻止新的GameplayAbilities的激活的效果,可以在其他技能上把眩晕的GameplayTag设置到他们的Activation Blocked TagsGameplayTagContainer

要阻止角色的移动,我们可以重写CharacterMovementComponentGetMaxSpeed()函数,将其当所有者拥有眩晕的GameplayTag时令这个函数返回0。

5.2 冲刺 - Sprint

示例项目中还提供了一个关于冲刺的例子,即当Left Shift按下时角色可以跑得更快一些。

快速移动可以由CharacterMovementComponent负责预测处理,具体就是通过网络发送一个标记到服务器。参考GDCharacterMovementComponent.h/cpp

GA会处理Left Shift对应的输入响应,通知角色移动组件去开启或者停止冲刺,并且预测性得消耗体力值。参考GA_Sprint_BP

5.3 瞄准 - Aim Down Sights

示例项目中,瞄准的做法和冲刺的做法基本一致,只是把加速换成了减速。

具体参阅GDCharacterMovementComponent.h/cpp中关于减速的内容。

参阅GA_AimDownSight_BP中关于输入的处理的内容。当然,瞄准并不会消耗体力。

5.4 生命偷取 - Lifesteal

我将生命偷取内置在伤害计算的ExecutionCalculation内。GameplayEffect会有一个专门的GameplayTag,比如Effect.CanLifesteal这样的。ExecutionCalculation会去检查GameplayEffectSpec是否有这样的一个GameplayTag。如果这个GameplayTag存在,那么ExecutionCalculation 会去创建一个动态的Instant类型的GameplayEffect,并且给它一个增加生命值的modifier,然后把他应用到SourceASC

if (SpecAssetTags.HasTag(FGameplayTag::RequestGameplayTag(FName("Effect.Damage.CanLifesteal"))))
{
	float Lifesteal = Damage * LifestealPercent;

	UGameplayEffect* GELifesteal = NewObject<UGameplayEffect>(GetTransientPackage(), FName(TEXT("Lifesteal")));
	GELifesteal->DurationPolicy = EGameplayEffectDurationType::Instant;

	int32 Idx = GELifesteal->Modifiers.Num();
	GELifesteal->Modifiers.SetNum(Idx + 1);
	FGameplayModifierInfo& Info = GELifesteal->Modifiers[Idx];
	Info.ModifierMagnitude = FScalableFloat(Lifesteal);
	Info.ModifierOp = EGameplayModOp::Additive;
	Info.Attribute = UPAAttributeSetBase::GetHealthAttribute();

	SourceAbilitySystemComponent->ApplyGameplayEffectToSelf(GELifesteal, 1.0f, SourceAbilitySystemComponent->MakeEffectContext());
}

5.5 在服务端和客户端上生成随机数字 - Generating a Random Number on Client and Server

有些时候你需要在GameplayAbility里生成随机数,比如子弹后坐力和扩散等。客户端和服务器当然需要同样的随机数。为了实现这个效果,我们必须在GameplayAbility激活的时候设置相同的random seed。每次去激活GameplayAbility的时候你都需要设置random seed,防止客户端预测激活失败并且随机数序列和服务器不同步。

随机数种子设置方法描述
使用激活预测键GameplayAbility的激活预测键是一个int16类型的数据,并且保证在客户端和服务器的Activation()是同步的。你可以将它作为客户端和服务器的random seed。这种方式的不好的地方在于这个预测键总是在游戏开始时从0开始,并且在每次生成键的时候持续增长,这意味着虽然数字是随机的,但是每次游玩过程中得到的整个数列却不是随机的。意思是这种方法提供的随机性有限。
当你激活 GameplayAbility时,通过事件负载发送种子即使用事件激活GameplayAbility并且由客户端向服务器通过复制的事件负载来发送随机生成的种子。这种方法能够提供足够的随机性,但是客户端就变得更加容易被攻击从而每次只去发送相同的种子值。而且通过事件激活GameplayAbilities将无法和输入进行绑定。

如果你的随机编程很小,大部分玩家都不会之一到每次游戏的随机数序列是相同的,那么第一种使用预测键的方法足够用了。如果你需要做一些稍复杂的需要防黑客的事情,也许使用Server InitiatedGameplayAbility 更加合适,这样服务器可以创建预测键或是创建可以由事件负载发送的random seed

5.6 暴击 - Critical Hits

我将暴击效果的实现内置在了ExecutionCalculation中。GameplayEffect会有一个专门的GameplayTag,比如说像Effect.CanCritExecutionCalculation会去检查GameplayEffectSpec是否拥有这个GameplayTag。如果GameplayTag存在的话,ExecutionCalculation会去生成一个随机的数字对应着暴击几率(从Source中取到的对应的Attribute值),然后加到暴击伤害(另外一个从Source中取到的对应的Attribute值)中。因为我并没有去预测伤害,我并不需要去担心随机数生成的同步问题,因为ExecutionCalculation只会在服务器上运行。如果你希望预测性得去使用MMC来处理伤害计算,那么你就需要从GameplayEffectSpec->GameplayEffectContext->GameplayAbilityInstance中拿到random seed的引用。

可以参考GASShooter项目中是如何实现爆头的。其本质就是本小节的内容,当然它并没有暴击率的设计,而是去检查FHitResult中命中的骨头的名称。

5.7 非可叠加游戏效果(仅取对目标影响最大者的游戏效果) - Non-Stacking Gameplay Effects but Only the Greatest Magnitude Actually Affects the Target

Paragon里的减速效果并不会堆叠。每一个减速实例正常应用并且正常追踪其生命周期,但是只有值最大的那一个才会在真正影响Character。GAS利用AggregatorEvaluateMetaData将这个效果做得开箱即用。可以参考AggregatorEvaluateMetaData()中的具体实现。

5.8 游戏暂停时生成目标数据 - Generate Target Data While Game is Paused

如果你需要为你的玩家在利用WaitTargetData AbilityTask来生成TargetData时暂停游戏,我建议不去暂停游戏,而是使用slomo 0

5.9 单按键交互系统 - One Button Interaction System

GASShooter实现了一个一键交互系统,其中玩家可以通过按下"E"来与可交互物进行交互,比如复活玩家,打开武器箱,以及打开或者关闭滑动门。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值