近战机制(盒体碰撞检测)

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*

posted @ 2022-05-11 18:56  ChioHiro  阅读(279)  评论(0)    收藏  举报