虚幻四Gameplay Ability System入门(9)-神罗天征!TargetActor

痛みを世界に与えて!
Untitled.png

哈哈,不开玩笑了。这一期我们实现一个类似Shinra Tensei的技能。技能可以将角色周围的敌人击飞,让他们感受痛苦!

首先大致描述一下技能的实现过程:

  1. 启动技能,PlayMontageAndWait。
  2. 通过TargetActor获取以角色为中心,球形碰撞体范围内的敌方角色,将数据传输给Gameplay Ability。
  3. 收到Anim Notify后,将得到数据中的全部敌人吸向角色。
  4. 收到Push Notify后,将敌人推开,让他们感受痛苦。

TargetActor

TargetActor是用来辅助Ability进行目标选取的,可以用来进行网络的数据传输。根据源码中的说明,TargetActor是比较消耗资源的。但是理论上我们同时启动的目标选择一般也不会很多。同时官方文档也强调了他们实现的基类是不靠谱的,建议自己通过subclass来实现类似功能避免消耗和安全性。

/**
 * TargetActors are spawned to assist with ability targeting. They are spawned by ability tasks and create/determine the outgoing targeting data passed from one task to another
 *
 * WARNING: These actors are spawned once per ability activation and in their default form are not very efficient
 * For most game
s you will need to subclass and heavily modify this actor, or you will want to implement similar functions in a game-specific actor or blueprint to avoid actor spawn costs
 * This class is not well tested by internal games, but it is a useful class to look at to learn how target replication occurs
 */

代码实现

这一部分要实现一个类能够获取以释放技能者为中心,球形范围内的Actor,然后将这部分的数据提供给技能。

首先新建GameplayAbilityTargetActor的派生类。这里我们就直接把它命名为AbilityShinraTenseiTargetActor了。

Untitled 1.png

打开AbilityShinraTenseiTargetActor.h。首先在public中创建派生类。重写两个方法StartTargeting和ConfirmTargetingAndContinue,然后创建一个float对象,表明技能的释放范围。

UCLASS()
class GAS_LEARN_API AAbilityShinraTenseiTargetActor : public AGameplayAbilityTargetActor
{
	GENERATED_BODY()

public:
	AAbilityShinraTenseiTargetActor();

	virtual void StartTargeting(UGameplayAbility* Ability) override;

	virtual void ConfirmTargetingAndContinue() override;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Ability Settings", meta=(ExposeOnSpawn=true))
	float Radius;
};

重写StartTargeting

这个函数会在TargetActor开始寻找目标时运行。OwningAbility顾名思义,值的就是拥有这个TargetActor的Ability。MasterPC是控制角色的Controller,在教程中我们并没有用到CharacterController,我们的逻辑都是在Character中实现的,所以这个对象我们其实并不需要赋值。SourceActor指的是拥有调用TargeActor的Ability的Actor(套娃)。这三个对象都是在基类GameplayAbilityTargetActor中定义完成的。

void AAbilityShinraTenseiTargetActor::StartTargeting(UGameplayAbility* Ability)
{
	OwningAbility = Ability;
	MasterPC = Cast<APlayerController>(Ability->GetOwningActorFromActorInfo()->GetInstigatorController());
	SourceActor = Ability->GetOwningActorFromActorInfo();
}

重写ConfirmTargetingAndContinue

函数中要实现的是获取技能范围内的敌人,将数据返回给Ability处理。

流程如下:

  1. 定义变量AbilityStartLocation用来存储技能释放位置,OverlapResults用来存储球形碰撞检测器的结果,OverlapActors用来记录在技能范围中的Actors,也是最终返回给技能的数据。
  2. 通过GetWorld()->OverlapMultiByObjectType建立一个球形碰撞器,如果成功,会将碰撞检测的结果写入OverlapResults。
  3. 如果碰撞成功,则将碰撞结果中的Actor存入OverlapActors。
  4. 如果OverlapActors的长度大于0,则将有效的数据通过Delegate广播出去。在Ability中就可以获取这些数据。
void AAbilityShinraTenseiTargetActor::ConfirmTargetingAndContinue()
{
	//函数需要用到的对象
	FVector AbilityStartLocation = FVector::ZeroVector;

	TArray<FOverlapResult> OverlapResults;
	TArray<TWeakObjectPtr<AActor>> OverlapActors;

	//构建碰撞检测的params
	FCollisionQueryParams QueryParams;
	QueryParams.bTraceComplex = false;
	QueryParams.bReturnPhysicalMaterial = false;
	if(SourceActor)
	{
		QueryParams.AddIgnoredActor(SourceActor->GetUniqueID());
		AbilityStartLocation = SourceActor->GetActorLocation();
	}

	//构建球形碰撞体,进行碰撞检测
	bool TryOverlap = GetWorld()->OverlapMultiByObjectType(
		OverlapResults,
		AbilityStartLocation,
		FQuat::Identity,
		FCollisionObjectQueryParams(ECC_Pawn),
		FCollisionShape::MakeSphere(Radius),
		QueryParams);

	//如果发生碰撞,将碰撞的actor写入OverlapActors
	if(TryOverlap)
	{
		for(const FOverlapResult& Result: OverlapResults)
		{
			APawn* OverlappedPawn = Cast<APawn>(Result.Actor);
			if(IsValid(OverlappedPawn))
			{
				OverlapActors.AddUnique(OverlappedPawn);
			}
		}
	}

	//如果OverlapActors存在数据,将数据通过delegate广播
	if(OverlapActors.Num() > 0)
	{
		const FGameplayAbilityTargetDataHandle TargetData = StartLocation.MakeTargetDataHandleFromActors(OverlapActors);
		TargetDataReadyDelegate.Broadcast(TargetData);
	}
}

角色蓝图

打开自己建立的角色蓝图。新建Custom Event,命名为Push Character,实现的功能是向指定的方向施加指定力量的Impluse,用于击飞或拉动角色。实现这个功能的方法是调用Character Movement Component中的Add Impulse函数。
Untitled 2.png

新建Custom Event,命名为ShinraTensei,它有一个bool变量的输入。这个事件用来表明技能的状态,当调用该事件且输入为true,表明此时需要将敌人拉向自己。当调用该事件且输入为false时,表明此时需要将敌人击飞。

当输入为true,则向自己的ASC发送一个Gameplay Event,标签为Ability.ShinraTensei.Pull,表明将敌人向角色拉动。当输入为false中,发送Event带有标签Ability.ShinraTensei.Push,表明此时要将敌人击飞。
Untitled 3.png

Montage Notify

自己选择一个动画创建Montage,然后在合适的位置新建Notify,分别命名为Pull Character和Push Character。
Untitled 4.png

打开角色动画蓝图。这里调用的就是刚才实现的custom Event,收到Pull Notify后,调用ShinraTensei(State=true)。收到Push Notify后,调用ShinraTensei(State=false)
Untitled 5.png

Shinra Tensei Ability

Gameplay Effect

创建需要的Gameplay Effect。效果是对敌人造成伤害。我直接用了最简单的方法,通过Scalable Float直接造成50点伤害。

Untitled 6.png

Gameplay Cue

创建Gameplay Cue,在这里我们通过GC播放台词。
Untitled 7.png

实现的功能是在角色的Root Component上生成一个sound,播放技能语音。注意别忘了设置Tag。
Untitled 8.png

BP_TargetData

创建在前面实现的TargetActor的蓝图派生类。
Untitled 9.png

Gameplay Ability

创建gameplay ability命名为GA_ShinraTensei。讲解下第一张图图里的流程。

  1. 通过Task PlayMontageAndWait播放montage
  2. 通过Add GameplayCue to Owner,调用播放声音的GC。
  3. 然后等待Character蓝图中发送的Event,即montage中的Pull Character Notify。
  4. 最后调用Task Wait Target Data,选择的class为我们刚才创建的BP_ShinraTensei_TargetActor,注意,在这里设置技能范围为1000。
    Untitled 10.png

第二张图:

  1. 接受到TargetActor发送的Valid Data后,取出其中的Actor。
  2. 拉动角色的方向计算通过将两个位置信息vector相减即可。
  3. 调用Push Character拉动角色。
    Untitled 11.png

第三张图:

  1. 等待Montage中的Push Character Notify。
  2. 同样计算角色的击飞方向,区别是将之前位置信息相减顺序互换,同时在方向上增加一个UpVector,负责让角色除了后退,也向天上飞。
  3. 应用Gameplay Effect造成伤害。
    Untitled 12.png

测试

GAS_Learn - Unreal Editor 2021-04-28 00-16-08 - converted with Clipchamp.gif
GAS入门合集

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值