效果展示
处在他的发现范围之外敌人是不会发现。 当走进他的发现范围之内的时候,他就会跑过来, 进行攻击。 现在还没有伤害。
C++ 文件
打开Built.cs文件, 找到:PublicDependencyModuleNames.AddRange 在之中添加"AIModule" ,增加AI相关的模块,这样系统才能识别我们调用的函数。
Enemy
创建继承Character 类的Enemy 类,因为不是玩家控制敌人的状态,而是计算机控制状态,所以需要在文件中声明敌人的状态:
UENUM(BlueprintType)
enum class EMoveStatus : uint8 {
MS_Idle UMETA(DisplayName = "Idle"),
MS_MoveToTarget UMETA(DisplayName = "MoveToTarget"),
MS_Attacking UMETA(DisplayName = "Attacking"),
};
.h
- 添加球形组件,一个是表示检测角色的范围,一个是攻击敌人的范围
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
class USphereComponent* DetectSphere;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
class USphereComponent* AttackSphere;
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);
UFUNCTION()
void OnAttackSphereOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
UFUNCTION()
void OnAttackSphereOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
class AAIController* _AIController;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
EMoveStatus MoveStatus;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
class ARole* TargetRole;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
class ARole* HittingRole;
UFUNCTION(BlueprintCallable)
void MoveToTarget();
.cpp文件
添加头文件:
#include "Components/SphereComponent.h"
#include "AIController.h"
#include "Kismet/KismetSystemLibrary.h"
#include "Role.h"
加载球形组件和设置范围,初始化操作。
DetectSphere = CreateDefaultSubobject<USphereComponent>(TEXT("DetectSphere"));
DetectSphere->SetupAttachment(RootComponent);
DetectSphere->SetSphereRadius(300);
AttackSphere = CreateDefaultSubobject<USphereComponent>(TEXT("AttackSphere"));
AttackSphere->SetupAttachment(RootComponent);
AttackSphere->SetSphereRadius(100);
绑定重叠函数,这个算是重叠的基本操作了。
DetectSphere->OnComponentBeginOverlap.AddDynamic(this, &AEnemy::OnDetectSphereOverlapBegin);
DetectSphere->OnComponentEndOverlap.AddDynamic(this, &AEnemy::OnDetectSphereOverlapEnd);
AttackSphere->OnComponentBeginOverlap.AddDynamic(this, &AEnemy::OnAttackSphereOverlapBegin);
AttackSphere->OnComponentEndOverlap.AddDynamic(this, &AEnemy::OnAttackSphereOverlapEnd);
获得AI控制器:
_AIController = Cast<AAIController>(GetController());
- OnDetectSphereOverlapBegin
触碰到检测球形组件的时候,设置我们的追击目标,然后移动到目标角色的位置。
检测球形组件重叠结束的时候,敌人不在进行追逐,目标角色置为空,AI控制器控制敌人停止移动,人物处于呆滞状态。
if (OtherActor) {
ARole* _Role = Cast<ARole>(OtherActor);
if (_Role == TargetRole) {
TargetRole = nullptr;
if (MoveStatus != EMoveStatus::MS_Attacking) {
MoveStatus = EMoveStatus::MS_Idle;
}
if (_AIController) {
_AIController->StopMovement();
}
}
}
- OnAttackSphereOverlapBegin
在攻击范围之内的时候,敌人要进行攻击,设置攻击目标,敌人设置为攻击状态,如果敌人在移动状态就要停止移动。
if (!HittingRole) {
if (OtherActor) {
ARole* _Role = Cast<ARole>(OtherActor);
if (_Role) {
HittingRole = _Role;
MoveStatus = EMoveStatus::MS_Attacking;
if (_AIController) {
_AIController->StopMovement();
}
}
}
}
在攻击范围之外的时候,敌人就变成了追击状态,设置追击目标,攻击目标置为空。
if (OtherActor) {
ARole* _Role = Cast<ARole>(OtherActor);
if (_Role == HittingRole) {
TargetRole = HittingRole;
HittingRole = nullptr;
}
}
让AI控制器控制敌人移动到角色的位置。
if (TargetRole) {
if (_AIController) {
FAIMoveRequest _MoveRequest;
_MoveRequest.SetGoalActor(TargetRole);
_MoveRequest.SetAcceptanceRadius(2);
FNavPathSharedPtr NavPath;
_AIController->MoveTo(_MoveRequest, &NavPath);
}
}
else {
MoveStatus = EMoveStatus::MS_Idle;
}
EnemyAnimInstance
创建继承AnimInstance 的EnemyAnimInstance ,这个就和之前的是一样的。
.h文件
初始化函数,更新函数,移动速度(便于我们区分人物状态)、敌人类、Pawn类。
virtual void NativeInitializeAnimation() override;
UFUNCTION(BlueprintCallable, Category = AnimationProperty)
void UpdateAnimationProperties();
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Movement)
float MovementSpeed;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Movement)
class AEnemy* _Enemy;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Movement)
class APawn* _Pawn;
.cpp文件
添加头文件:
#include "Enemy.h"
void UEnemyAnimInstance::NativeInitializeAnimation()
{
if (!_Pawn) {
_Pawn = TryGetPawnOwner();
}
_Enemy = Cast<AEnemy>(_Pawn);
}
void UEnemyAnimInstance::UpdateAnimationProperties()
{
if (!_Pawn) {
_Pawn = TryGetPawnOwner();
}
if (_Pawn) {
FVector Speed = _Pawn->GetVelocity();
FVector LateralSpeed = FVector(Speed.X, Speed.Y, 0);
MovementSpeed = LateralSpeed.Size();
}
}
蓝图操作
创建动画蓝图, 设置角色状态机:
攻击动画中要添加一个注意:
蓝图中要更新状态: 和人物是差不多的。
根据动作传来的提醒,我们要对敌人的状态进行设置:
|