RPG39.创建玩家格挡攻击的能力

发布于:2025-07-04 ⋅ 阅读:(18) ⋅ 点赞:(0)

1.创建标签

ARPG_GRIVITY_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(InputTag_MustBeHeld);
	ARPG_GRIVITY_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(InputTag_MustBeHeld_Block);
ARPG_GRIVITY_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Player_Ability_Block);
	ARPG_GRIVITY_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Player_Status_Blocking);
	UE_DEFINE_GAMEPLAY_TAG(InputTag_MustBeHeld, "InputTag.MustBeHeld");
	UE_DEFINE_GAMEPLAY_TAG(InputTag_MustBeHeld_Block, "InputTag.MustBeHeld.Block");
	UE_DEFINE_GAMEPLAY_TAG(Player_Ability_Block, "Player.Ability.Block");
	UE_DEFINE_GAMEPLAY_TAG(Player_Status_Blocking, "Player.Status.Blocking");

2。进入资产,创建block的蒙太奇

确保根运动未开启

需要创建循环动画

在ga内设置

然后创建一个gameplaycue

3.打开XMbWarriorFunctionLibrary

//计算player在格挡时的夹角是否有效
	UFUNCTION(BlueprintPure, Category = "XMBWorrior|FunctionLibrary")
	static bool IsValidBlock(AActor* InAttacker, AActor* InDefender);
bool UXMBWarriorFunctionLibrary::IsValidBlock(AActor* InAttacker, AActor* InDefender)
{
	check(InAttacker && InDefender);

	//计算夹角
	const float DotResult = FVector::DotProduct(InAttacker->GetActorForwardVector(), InDefender->GetActorForwardVector());

	const FString DebugString = FString::Printf(TEXT("dot result: %f %s"),DotResult, DotResult < -0.1f ? TEXT("valid") : TEXT("invalid"));

	Debug::Print(DebugString,DotResult < -0.1f ? FColor::Green : FColor::Red);
	return DotResult < -0.1f;
}

打开EnemyCombatComponent


void UEnemyCombatComponent::OnHitTargetActor(AActor* HitActor)
{
	if (OverlappedActors.Contains(HitActor))
	{
		return;
	}

	OverlappedActors.AddUnique(HitActor);

	//TODO: Implement block check
	bool bIsValidBlock = false;

	const bool bIsPlayerBlocking = UXMBWarriorFunctionLibrary::NativeDoesActorHaveTag(HitActor, XMBGameplayTags::Player_Status_Blocking);
	const bool bIsMyAttackUnblockble = false;

	if (bIsPlayerBlocking && !bIsMyAttackUnblockble)
	{
		//TODO:check if the block is valid
		//通过被攻击的角度和角色当前的朝向计算夹角
		bIsValidBlock = UXMBWarriorFunctionLibrary::IsValidBlock(GetOwningPawn(),HitActor);
	}

	FGameplayEventData EventData;
	EventData.Instigator = GetOwningPawn();
	EventData.Target = HitActor;

	if (bIsValidBlock)
	{
		//TODO:Handle successful block
		
	}
	else
	{
		UAbilitySystemBlueprintLibrary::SendGameplayEventToActor(
			GetOwningPawn(),
			XMBGameplayTags::Shared_Event_MeleeHit,
			EventData
			);
	}
}

添加一个tag

ARPG_GRIVITY_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Player_Event_SuccessfulBlock);
UE_DEFINE_GAMEPLAY_TAG(Player_Event_SuccessfulBlock, "Player.Event.SuccessfulBlock");

然后打开EnemyCombatComponent,将成功被阻挡的tag发送出去

if (bIsValidBlock)
	{
		//阻挡成功将事件发送
		UAbilitySystemBlueprintLibrary::SendGameplayEventToActor(
			HitActor,
			XMBGameplayTags::Player_Event_SuccessfulBlock,
			EventData
		);
		
	}

4。启动项目

当玩家成功阻挡后,转向enemy的方向

然后进行击退和阻挡成功的粒子

接下来制作完美格挡.我们需要在被攻击前的一定时间内进行一个时间的计算,来判断玩家是否在开启格挡技能的一定时间内受到了攻击。

首先,先获取当前玩家开启技能时游戏的时间

再新建一个gameplaycue

 

下一步需要制作完美格挡后,玩家再进行攻击时能直接进入轻攻击或者重攻击的最后一段。则需要再完美格挡后将一个标签发送出去,在进行攻击的时候进行检测即可

打开GA_Block

在完美格挡后进行调用

再打开lightattackmaster与heavyattackmaster

通过检查是否拥有tag来判断刚刚是否完美格挡