RPG23.应用武器伤害(一):设置武器命中
1.打开PawnCombatComponent.h
新建一个枚举
UENUM(BlueprintType)
enum class EToggleDamageType : uint8
{CurrentEquippedWeapon,LeftHand,RightHand
};
创建一个新函数
public:
//攻击时设置武器碰撞UFUNCTION(BlueprintCallable, Category = "XMB|Combat")void ToggleWeaponCollision(bool bShouldEnable, EToggleDamageType ToggleDamageType = EToggleDamageType::CurrentEquippedWeapon);
void UPawnCombatComponent::ToggleWeaponCollision(bool bShouldEnable, EToggleDamageType ToggleDamageType)
{if (ToggleDamageType == EToggleDamageType::CurrentEquippedWeapon){AWeaponBase* WeaponToToggle = GetCharacterCurrentEquippedWeapon();check(WeaponToToggle);if (bShouldEnable){WeaponToToggle->GetWeaponCollisionBox()->SetCollisionEnabled(ECollisionEnabled::QueryOnly);Debug::Print(WeaponToToggle->GetName() + TEXT("collision enable"), FColor::Green);}else{WeaponToToggle->GetWeaponCollisionBox()->SetCollisionEnabled(ECollisionEnabled::NoCollision);Debug::Print(WeaponToToggle->GetName() + TEXT("collision disable"), FColor::Red);}}
}
3.打开项目,打开ANS_ToggleWeaponCollsiion
再去蒙太奇里将ANS调制到大约可以造成伤害的位置
4.打开weaponbase.h,添加两个函数用于碰撞结束前后
UFUNCTION()virtual void OnCollisionBoxBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);UFUNCTION()virtual void OnCollisionEndOverlap( UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
void AWeaponBase::OnCollisionBoxBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{//APawn* WeaponOwningPawn = GetInstigator<APawn>();checkf(WeaponOwningPawn,TEXT("forgot to assign an instagtor as the owning pawn of the weapon : %s"),* GetName());if (APawn* HitPawn = Cast<APawn>(OtherActor)){if (WeaponOwningPawn != HitPawn)//命中的对象与武器装备者本身不相同{Debug::Print(FString::Printf(TEXT("begin overlap with: %s"),* HitPawn->GetName()),FColor::Green);}//TODO:Implement hit check for enemy characters}}void AWeaponBase::OnCollisionEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{//APawn* WeaponOwningPawn = GetInstigator<APawn>();checkf(WeaponOwningPawn,TEXT("forgot to assign an instagtor as the owning pawn of the weapon : %s"),* GetName());if (APawn* HitPawn = Cast<APawn>(OtherActor)){if (WeaponOwningPawn != HitPawn)//命中的对象与武器装备者本身不相同{Debug::Print(FString::Printf(TEXT("end overlap with: %s"),* HitPawn->GetName()),FColor::Red);}}
}
在构造函数内绑定这两个函数
AWeaponBase::AWeaponBase()
{PrimaryActorTick.bCanEverTick = true;WeaponMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("WeaponMesh"));SetRootComponent(WeaponMesh);WeaponCollisionBox = CreateDefaultSubobject<UBoxComponent>(TEXT("WeaponCollisionBox"));WeaponCollisionBox->SetupAttachment(GetRootComponent());WeaponCollisionBox->SetBoxExtent(FVector(20.f));WeaponCollisionBox->SetCollisionEnabled(ECollisionEnabled::NoCollision);//绑定WeaponCollisionBox->OnComponentBeginOverlap.AddUniqueDynamic(this, &ThisClass::OnCollisionBoxBeginOverlap);WeaponCollisionBox->OnComponentEndOverlap.AddUniqueDynamic(this,&ThisClass::OnCollisionEndOverlap);
}
5.在weapoinbase内创建委托用于传递命中的对象
DECLARE_DELEGATE_OneParam(FOnTargetInteractedDelegate, AActor*)
public:FOnTargetInteractedDelegate OnWeaponHitTarget;FOnTargetInteractedDelegate OnWeaponPulledFromTarget;
然后在OnCollisionBoxBeginOverlap与OnCollisionEndOverlap内分别改为
void AWeaponBase::OnCollisionBoxBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{//APawn* WeaponOwningPawn = GetInstigator<APawn>();checkf(WeaponOwningPawn,TEXT("forgot to assign an instagtor as the owning pawn of the weapon : %s"),* GetName());if (APawn* HitPawn = Cast<APawn>(OtherActor)){if (WeaponOwningPawn != HitPawn)//命中的对象与武器装备者本身不相同{OnWeaponHitTarget.ExecuteIfBound(OtherActor);}//TODO:Implement hit check for enemy characters}}void AWeaponBase::OnCollisionEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{//APawn* WeaponOwningPawn = GetInstigator<APawn>();checkf(WeaponOwningPawn,TEXT("forgot to assign an instagtor as the owning pawn of the weapon : %s"),* GetName());if (APawn* HitPawn = Cast<APawn>(OtherActor)){if (WeaponOwningPawn != HitPawn)//命中的对象与武器装备者本身不相同{OnWeaponPulledFromTarget.ExecuteIfBound(OtherActor);}}
}
创建数组用于存储命中对象
protected:TArray<AActor*> OverlappedActors;
6.要在战斗组件中绑定这两个函数
首先,在PawnCombatCompnent内创建两个函数
virtual void OnHitTargetActor(AActor* HitActor);virtual void OnWeaponPulledFromTargetActor(AActor* InteractedActor);
其次,在将武器添加到映射内后,绑定这两个函数
//简单的回调函数不需要ufunction(动态多播需要)InWeaponToRegister->OnWeaponHitTarget.BindUObject(this,&ThisClass::OnHitTargetActor);InWeaponToRegister->OnWeaponPulledFromTarget.BindUObject(this,&ThisClass::OnWeaponPulledFromTargetActor);
7.创建新标签,用于攻击时记录命中
/* Shared tags */ARPG_GRIVITY_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Shared_Event_MeleeHit);
/* Enemy tags */UE_DEFINE_GAMEPLAY_TAG(Shared_Event_MeleeHit, "Shared.Event.MeleeHit");
8.进入XMBCombatComponent.h
对6创建的两个函数进行覆写
virtual void OnHitTargetActor(AActor* HitActor) override;virtual void OnWeaponPulledFromTargetActor(AActor* InteractedActor) override;
然后实现他们
void UXMBCombatComponent::OnHitTargetActor(AActor* HitActor)
{if (OverlappedActors.Contains(HitActor)){return;}//确保每次每个目标只收一次伤害OverlappedActors.AddUnique(HitActor);FGameplayEventData Data;Data.Instigator = GetOwningPawn();Data.Target = HitActor;UAbilitySystemBlueprintLibrary::SendGameplayEventToActor(GetOwningPawn(),XMBGameplayTags::Shared_Event_MeleeHit,Data);
}void UXMBCombatComponent::OnWeaponPulledFromTargetActor(AActor* InteractedActor)
{}
9.启动项目,打开lightattackmaster
打开HeavyAttackMaster
10.接下来对每一个montage进行anim通知
例如这样,对每一个LightAttack或者HeavyAttack的Montage进行设置就好
测试成功