UE4学习监督——C++人物攻击(二)

UE4学习监督——C++人物攻击(二),第1张

UE4学习监督——C++人物攻击(二)

上一章我们初步完成了攻击功能的实现,但是会出现滑步现象,且攻击方式过于单一,这次我们来解决这个问题。

此时我们需要重写动画蓝图类。

创建一个类继承自AnimInstance,命名为HeroAnimInstance。

头文件如下

class DDEMO_API UHeroAnimInstance : public UAnimInstance
{
	GENERATED_BODY()

public:
		UPROPERTY(BlueprintReadOnly)
		float Speed;
	UPROPERTY(BlueprintReadOnly)
		float Direction;
	UPROPERTY(BlueprintReadOnly)
		bool bInAir;
	UPROPERTY(BlueprintReadOnly)
		bool isAttack;
	UPROPERTY(EditAnywhere,BlueprintReadOnly)
		class AHeroDemo* Hero;
    
	UFUNCTION(BlueprintCallable)
		void UpdateAnimInfo(float dt);
};

cpp文件如下

void UHeroAnimInstance::UpdateAnimInfo(float dt)
{
	APawn* Owner = TryGetPawnOwner();
	ACharacter* Player = Cast(Owner);
	if(Owner!=nullptr)
	{
		Speed = Owner->GetVelocity().Size();
		Direction = CalculateDirection(Owner->GetVelocity(), Owner->GetbaseAimRotation());
		bInAir = Player->GetMovementComponent()->IsFalling();
	}
}

完成后进行编译,并以此为父类创建动画蓝图。蓝图内的 *** 作基本与之前一致。

现在修改HeroDemo的代码。

在头文件增加如下代码:

	bool bAttacking;//为判断是否在攻击

	UFUNCTION(BlueprintCallable)//判定攻击动画结束,需要在动画蓝图中调用
		void AttackEnd();

将头文件中移动的函数做一些修改,使之在攻击时不能调用。如:

void AHeroDemo::MoveForward(float Axis)
{
	if((Controller!=NULL)&(Axis!=0.0f)
#if 1
		&&!bAttacking
#endif
       //以上代码用来作一个判断
		){
		const FRotator Rotation = Controller->GetControlRotation();
		const FRotator YawRotation(0, Rotation.Yaw, 0);

		const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
		AddMovementInput(Direction, Axis);
	}
}

Attack()更改如下:

void AHeroDemo::Attack()
{
	bAttacking = true;
	UAnimInstance* AnimInstance = Cast(GetMesh()->GetAnimInstance());
	if (AnimInstance != nullptr)
	{
		if (!AnimInstance->Montage_IsPlaying(AttackMontage))
		{
			AnimInstance->Montage_Play(AttackMontage);
			AnimInstance->Montage_JumpToSection(FName("Attack01"), AttackMontage);
		}
	}
}

AttackEnd()代码如下:

void AHeroDemo::AttackEnd()
{
	bAttacking = false;
}

但是我们的代码中却没有调用AttackEnd函数,我们需要到动画蓝图中调用,通过获得蒙太奇动画的结束时间来判断何时调用。

来到AttackM动画蒙太奇,添加两段攻击动画,并将三段动画在分段中命名为Attack01,Attack02,Attack03,并进行分段,效果如下:

再在下方通知中创建新通知,命名为AttackEnd,将位置调整到第一段攻击动画结束处。再分别复制两次到另外两段攻击动画。

这样,当蒙太奇动画播放完成时就会发出通知。

再来到动画蓝图的事件图表,调用并连接节点如下:

编译运行,发现在攻击时方向键已然失效。

现在我们来设置不同的攻击状态,期望的目标是连续点击左键有三种不同的攻击动画,如连续两次点击之间时间间隔超过5s则重新计算。

增加的代码如下。

.h

int AttackStatus = 1;
	//用于判断攻击状态

	FTimerHandle RestTimer;
	//声明定时器

	void ClearRestTime();
	//清除之前的攻击状态

.cpp

void AHeroDemo::ClearRestTime()
{
	AttackStatus = 1;
}

更改.cpp中Attack函数如下:

void AHeroDemo::Attack()
{
	bAttacking = true;
	UAnimInstance* AnimInstance = Cast(GetMesh()->GetAnimInstance());
	if (AnimInstance != nullptr)
	{
		if (!AnimInstance->Montage_IsPlaying(AttackMontage))
		{
			AnimInstance->Montage_Play(AttackMontage);
			switch (AttackStatus)
			{
				case 1:AnimInstance->Montage_JumpToSection(FName("Attack01"), AttackMontage);
					AttackStatus++;
					GetWorldTimerManager().SetTimer(RestTimer, this, &AHeroDemo::ClearRestTime, 0.1f, false, 3.0f);
				break;
				case 2:AnimInstance->Montage_JumpToSection(FName("Attack02"), AttackMontage);
					AttackStatus++;
                   	  GetWorldTimerManager().ClearTimer(RestTimer);
					GetWorldTimerManager().SetTimer(RestTimer, this, &AHeroDemo::ClearRestTime, 0.1f, false, 3.0f);
				break;
				case 3:AnimInstance->Montage_JumpToSection(FName("Attack03"), AttackMontage);
                   	  GetWorldTimerManager().ClearTimer(RestTimer);
					AttackStatus = 1;
				break;
			}
		}
	}
}

这里使用switch语句判断不同的攻击状态,分支中设置定时器运行时间,在下一个分支语句中清除之前设置的定时器,之后重新设置。

编译运行,已能完成既定目标。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5156222.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-18
下一篇 2022-11-18

发表评论

登录后才能评论

评论列表(0条)

保存