【UE4 C++】设置攻击间隔、面向敌人攻击

该博客介绍了如何使用C++在游戏环境中实现角色与敌人的交互攻击系统。通过球形碰撞组件检测敌人,角色能感知并转向攻击敌人。同时,敌人在冷却时间结束后才会进行攻击。博客详细讲解了代码实现,包括重叠开始和结束的处理,以及攻击状态的管理。此外,还涉及了攻击动画的播放和冷却时间的管理。
摘要由CSDN通过智能技术生成

效果展示

当人物背对着敌人的时候,他会回头攻击敌人。
在这里插入图片描述在这里插入图片描述
敌人会等待一段时间之后再攻击,这个图片无法展示就不展示啦。

C++ 代码实现

Role 第三人称角色类

.h

// 设置当前要攻击的目标
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
	class AEnemy* TargetEnemy;

// 球形碰撞组件,主要作用就是检测敌人于它重叠与否。
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
	class USphereComponent* DetectSphere; 

// 球形组件绑定的函数
UFUNCTION()
	void OnDetectSphereOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, 
		UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);

UFUNCTION()
	void OnDetectSphereOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
		UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);

.cpp

  • 构造函数
// 初始化球形组件,附加在根组件上
DetectSphere = CreateDefaultSubobject<USphereComponent>(TEXT("DetectSphere"));
DetectSphere->SetupAttachment(RootComponent);
  • BeginPlay
// 绑定重叠发生反应的函数
DetectSphere->OnComponentBeginOverlap.AddDynamic(this, &ARole::OnDetectSphereOverlapBegin);
DetectSphere->OnComponentEndOverlap.AddDynamic(this, &ARole::OnDetectSphereOverlapEnd);

// 先把所有反应通道忽略,然后再打开对Pawn类的通道。
DetectSphere->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
DetectSphere->SetCollisionResponseToChannel(ECollisionChannel::ECC_Pawn, ECollisionResponse::ECR_Overlap);
  • OnDetectSphereOverlapBegin
// 重叠开始函数的作用就是将目标保存一下
if (!TargetEnemy) {
	if (OtherActor) {
		AEnemy* Enemy = Cast<AEnemy>(OtherActor);
		if (Enemy) {
			TargetEnemy = Enemy;
		}
	}
}
  • OnDetectSphereOverlapEnd
// 离开的时候就将攻击目标设置为空。
if (OtherActor) {
	AEnemy* Enemy = Cast<AEnemy>(OtherActor);
	if (Enemy == TargetEnemy) {
		TargetEnemy = nullptr;
	}
}
  • AttackBegin
// 如果有攻击目标
if (TargetEnemy) {
	FRotator CurrentRotation = GetActorRotation();
	// 通过FindLookAtRotation函数或得当前目标到攻击目标的Z轴
	FRotator TargetRotation = UKismetMathLibrary::FindLookAtRotation(GetActorLocation(), TargetEnemy->GetActorLocation());
	// 将人物的Z轴修改一下就可以了
	TargetRotation = FRotator(CurrentRotation.Pitch, TargetRotation.Yaw, CurrentRotation.Roll);
	SetActorRotation(TargetRotation);
}

Z轴是这个蓝色的,所以只需要修改Z轴即可。
在这里插入图片描述
这个情况是对应于有重力的情况,如果是其他的状态就要经过一番计算了。

在这里插入图片描述
修改一下这个检测球的范围,面向敌人功能完成。

Enemy

.h

// 冷却时间,记得在编辑器中赋值,默认为 0s
UPROPERTY(EditAnywhere, BlueprintReadWrite)
	float AttackInterval;

// 是否在冷却时间内
bool bInColdTime;

// 储存时间的变量
FTimerHandle AttackTimer;

// 攻击时间截止
void OnAttackTimeOut();

// 更新状态。
void UpdateStatus();

.cpp

  • UpdateStatus
// 更新状态
if (HittingRole) {
	// 有攻击角色移动到攻击角色
	MoveToTarget();
	// 只有不在冷却时间之内才可以进行攻击
	if (!bInColdTime) {
		AttackBegin();
	}
}
else if (TargetRole) {
	// 非攻击状态,才可以进行移动
	if (!Attacking) {
		MoveStatus = EMoveStatus::MS_MoveToTarget;
	}
	MoveToTarget();
}
else {
	MoveStatus = EMoveStatus::MS_Idle;
}
  • OnAttackSphereOverlapBegin
if (!HittingRole) {
	if (OtherActor) {
		ARole* _Role = Cast<ARole>(OtherActor);
		if (_Role) {
			HittingRole = _Role;
			MoveStatus = EMoveStatus::MS_Attacking;

			// 只有不在冷却时间才可以进行攻击
			if (!bInColdTime) {
				AttackBegin();
			}

			if (_AIController) {
				_AIController->StopMovement();
			}
		}
	}
}
  • OnAttackSphereOverlapEnd
if (OtherActor) {
	ARole* _Role = Cast<ARole>(OtherActor);
	if (_Role && _Role == HittingRole) {
		TargetRole = HittingRole;
		HittingRole = nullptr;
		// 离开攻击范围之后,要对状态进行更新
		UpdateStatus();
	}
}
  • AttackBegin
void AEnemy::AttackBegin()
{
	if (!HittingRole) return;

	UAnimInstance* Instance = GetMesh()->GetAnimInstance();
	if (_AnimMontage && Instance && !Instance->Montage_IsPlaying(_AnimMontage)) {

		// 和角色一样,面向敌人
		if (HittingRole && !Attacking) {
			FRotator CurrentRotation = GetActorRotation();
			FRotator TargetRotation = UKismetMathLibrary::FindLookAtRotation(GetActorLocation(), HittingRole->GetActorLocation());
			TargetRotation = FRotator(CurrentRotation.Pitch, TargetRotation.Yaw, CurrentRotation.Roll);
			SetActorRotation(TargetRotation);
		}

		Attacking = true;

		// 攻击开始的时候,要设置为冷却时间,清空之前的时间,重新计时。
		bInColdTime = true;
		GetWorldTimerManager().ClearTimer(AttackTimer);
		GetWorldTimerManager().SetTimer(AttackTimer, this, &AEnemy::OnAttackTimeOut, AttackInterval);

		Instance->Montage_Play(_AnimMontage);
		Instance->Montage_JumpToSection(FName("Attack01"), _AnimMontage);
		
		if (AttackSound) {
			UGameplayStatics::PlaySound2D(this, AttackSound);
		}
	}
}
  • AttackEnd
void AEnemy::AttackEnd()
{
	Attacking = false;
	// 攻击结束之后也要更新状态
	UpdateStatus();
}

其实就是攻击前加个时间判断,其他都差不多,时间的管理就交给FTimerHandle。到点就更新CD状态。

结束!编译试试吧!

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值