近战机制(盒体碰撞检测)
1.Mycharacter
1.1Mycharacter.h中
UFUNCTION(BlueprintCallable) void PlayAttackSound(); //人物攻击声音 UPROPERTY(EditAnywhere, BlueprintReadOnly) class UParticleSystem* InteractParticle; //受伤粒子特效 UPROPERTY(EditAnywhere, BlueprintReadWrite) class USoundCue* ReactSound; //受伤声音
1.2Mycharacter.cpp
添加头文件
#include "Kismet/GameplayStatics.h" #include "Sound/SoundCue.h"
PlayAttackSound()函数中
void AMyCharacter::PlayAttackSound() { if (EquiqedWeapon && EquiqedWeapon->AttackSound) { UGameplayStatics::PlaySound2D(this, EquiqedWeapon->AttackSound); } }
在人物蒙太奇添加

2.攻击方
2.1Weapon.h中添加
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
class UBoxComponent* CombatBox; // 攻击检测盒体
// 盒体检测重叠函数 UFUNCTION() void OnCombatBoxOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult); UFUNCTION() void OnCombatBoxOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex); UPROPERTY(EditAnywhere, BlueprintReadWrite) class USoundCue* AttackSound; // 攻击声音 UFUNCTION(BlueprintCallable) void EnableCollision(); // 启用碰撞 UFUNCTION(BlueprintCallable) void DisableCollision(); // 关闭碰撞 virtual void BeginPlay() override;
2.2weapon.cpp中
头文件添加
#include "Components/BoxComponent.h"
#include "Enemy.h"
#include "Sound/SoundCue.h"
构造函数添加
创建盒子的实例,绑定到骨骼网格下
CombatBox = CreateDefaultSubobject<UBoxComponent>(TEXT("CombatBox")); CombatBox->SetupAttachment(Mesh);
OnAttackSphereOverlapBegin函数中添加AttackBegin();
void AEnemy::OnAttackSphereOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult) { if (!HittingMan) { if (OtherActor) { AMyCharacter* Man = Cast<AMyCharacter>(OtherActor); if (Man) { HittingMan = Man; MoveStatus = EMoveStatus::MS_Attacking; //之前是使用敌人枚举状态控制敌人移动,现在改为C++内部实现 AttackBegin(); //即在蓝图中设置蒙太奇可使用,否则特效、声音蒙太奇攻击动画等会因为没有调用而失效。 if (AIController) { AIController->StopMovement(); } } } } }
OnCombatBoxOverlapBegin函数中
void AWeapon::OnCombatBoxOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult) { if (OtherActor) { //检测重叠是什么东西 AEnemy* Enemy = Cast<AEnemy>(OtherActor); if (Enemy) { if (Enemy->InteractParticle) { //播放特效的位置就是武器插槽的位置 UGameplayStatics::SpawnEmitterAtLocation(this, Enemy->InteractParticle, Mesh->GetSocketLocation("WeaponSocket")); } if (Enemy->ReactSound) { UGameplayStatics::PlaySound2D(this, Enemy->ReactSound); } } } }
OnCombatBoxOverlapEnd函数中
void AWeapon::OnCombatBoxOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex) { }
EnableCollision函数中
void AWeapon::EnableCollision() { //开启碰撞 QueryOnly只问重叠事件,不会阻挡 CombatBox->SetCollisionEnabled(ECollisionEnabled::QueryOnly); }
DisableCollision函数中
void AWeapon::DisableCollision() { //关闭碰撞 CombatBox->SetCollisionEnabled(ECollisionEnabled::NoCollision); }
begin函数中
void AWeapon::BeginPlay() { Super::BeginPlay(); //盒子重叠函数的绑定 CombatBox->OnComponentBeginOverlap.AddDynamic(this, &AWeapon::OnCombatBoxOverlapBegin); CombatBox->OnComponentEndOverlap.AddDynamic(this, &AWeapon::OnCombatBoxOverlapEnd); CombatBox->SetCollisionEnabled(ECollisionEnabled::NoCollision); //关掉碰撞 ////设置碰撞通道类型 ECollisionChannel碰撞检测通道 WorldDynamic用于受到动画或代码的影响而移动的Actor类型 CombatBox->SetCollisionObjectType(ECollisionChannel::ECC_WorldDynamic); //自己设置为动态的物体 CombatBox->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore); //对所有通道响应设置为忽略 CombatBox->SetCollisionResponseToChannel(ECollisionChannel::ECC_Pawn, ECollisionResponse::ECR_Overlap);//对Pawn进行检测重叠 }
3.挨打方
3.1Enemy.h
UPROPERTY(EditAnywhere, BlueprintReadOnly) class UAnimMontage* _AnimMontage; // 声明动画蒙太奇 UPROPERTY(EditAnywhere, BlueprintReadOnly) class UParticleSystem* InteractParticle; // 敌人受伤粒子特效 UPROPERTY(EditAnywhere, BlueprintReadWrite) class USoundCue* ReactSound; // 受伤声音 UPROPERTY(VisibleAnywhere, BlueprintReadOnly) class UBoxComponent* CombatBox; // 攻击检测盒体 // 盒体检测重叠函数,老套路了。 UFUNCTION() void OnCombatBoxOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult); UFUNCTION() void OnCombatBoxOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex); UPROPERTY(EditAnywhere, BlueprintReadWrite) class USoundCue* AttackSound; // 攻击声音 UFUNCTION(BlueprintCallable) void EnableCollision(); // 启用碰撞 UFUNCTION(BlueprintCallable) void DisableCollision(); // 关闭碰撞 bool Attacking; // 是否处于攻击状态 UFUNCTION(BlueprintCallable) void AttackBegin(); // 攻击开始状态 UFUNCTION(BlueprintCallable) void AttackEnd(); // 攻击结束状态
3.2 在Enemy.cpp中
添加头文件
#include "Components/BoxComponent.h" #include "Components/SkeleTalMeshComponent.h" #include "Kismet/GameplayStatics.h" //UGameplayStatics是一个很实用的静态类,我们不需要拥有指向此类的任何实例的指针,并且可以直接从任何地方调用函数。 #include "Animation/AnimInstance.h"
#include "Sound/SoundCue.h"
AttachToComponent有四种依附形式:
KeepRelativeTransform(保持两个物体之间的相对位置不变)
KeepWorldTransform(保持连个物体在世界的位置不变)
SnapToTargetNotIncludingScale(保持物体的缩放对齐到目标上)
SnapToTargetIncludingScale(随目标的缩放)
在构造函数中添加
//初始化操作,盒体是附加在武器上的,所以就放到插槽里面。 CombatBox = CreateDefaultSubobject<UBoxComponent>(TEXT("CombatBox")); CombatBox->AttachToComponent(GetMesh(), FAttachmentTransformRules::SnapToTargetNotIncludingScale, "WeaponSocket");
OnCombatBoxOverlapBegin函数中
void AEnemy::OnCombatBoxOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult) { if (OtherActor) { AMyCharacter* Character = Cast<AMyCharacter>(OtherActor); if (Character) { if (Character->InteractParticle){ //播放特效 UGameplayStatics::SpawnEmitterAtLocation(this, Character->InteractParticle, GetMesh()->GetSocketLocation("WeaponSocket")); } if (Character->ReactSound){ //播放声音 UGameplayStatics::PlaySound2D(this, Character->ReactSound); //挨打的声音 } } } }
OnCombatBoxOverlapEnd中
void AEnemy::OnCombatBoxOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{}
碰撞通道函数设置
void AEnemy::EnableCollision() { CombatBox->SetCollisionEnabled(ECollisionEnabled::QueryOnly); } void AEnemy::DisableCollision() { CombatBox->SetCollisionEnabled(ECollisionEnabled::NoCollision); }
Attackbegin函数
void AEnemy::AttackBegin() { UAnimInstance* Instance = GetMesh()->GetAnimInstance(); if (AnimMontage && Instance && !Instance->Montage_IsPlaying(AnimMontage)) { Attacking = true; Instance->Montage_Play(AnimMontage);//播放攻击动作 switch (FMath::RandRange((int32)1, 2)) { //随机调用其中一个攻击动画 case 1: Instance->Montage_JumpToSection(FName("Attack1"), AnimMontage); break; case 2: Instance->Montage_JumpToSection(FName("Attack2"), AnimMontage); break; break; } if (AttackSound) { UGameplayStatics::PlaySound2D(this, AttackSound); //播放打人声音 注意添加头文件 } } }
attackend函数中
void AEnemy::AttackEnd() { Attacking = false; if (HittingMan) { MoveToTarget(); AttackBegin(); } else if (TargetMan) { MoveStatus = EMoveStatus::MS_MoveToTarget; MoveToTarget(); } else { MoveStatus = EMoveStatus::MS_Idle; } }
在begin函数中
CombatBox->OnComponentBeginOverlap.AddDynamic(this, &AEnemy::OnCombatBoxOverlapBegin); CombatBox->OnComponentEndOverlap.AddDynamic(this, &AEnemy::OnCombatBoxOverlapEnd); CombatBox->SetCollisionEnabled(ECollisionEnabled::NoCollision); //无碰撞
4.主角动画蓝图

5.敌人动画蓝图中

学习至b站视频阿棍儿和CSDNTanzq*

浙公网安备 33010602011771号