前面文中讲述了如何创建一个血条,本文将讲述如何创造伤害,怎么收到伤害。这在游戏中是相当重要的,因为大部分游戏都是有伤害机制的,当然,我们不会对伤害的数值进行研究,只进行简单的处理。
首先在武器actor中,在构造玩collision时,设置为不碰撞,因为我们是只需要在挥剑的时候开启碰撞,其它时候应该是取消碰撞的。如下所示:
WeaponCollision->SetCollisionEnabled(ECollisionEnabled::NoCollision);
接着在我们的人物character中,在挥剑的时候,开启碰撞,并设置一个定时器,在播放完蒙太奇的时候,才允许碰撞,因此首先,我们创建一个bool变量,用来控制OnHit函数,如下所示:
bool bCanAttack;
void ActiveAttack();
void DeActiveAttack(); // 不激活武器
void AWeaponActor::ActiveAttack()
{
bCanAttack = true;
if (WeaponCollision != nullptr) // 激活碰撞
{
WeaponCollision->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
}
}
void AWeaponActor::DeActiveAttack() // 关闭碰撞
{
bCanAttack = false;
if (WeaponCollision != nullptr)
{
WeaponCollision->SetCollisionEnabled(ECollisionEnabled::NoCollision);
}
}
接着在我们的人物character中,当挥剑时激活武器。而在播放完蒙太奇后则不激活武器,如下所示:
void ABlogProjectCharacter::Attack()
{
UHeroAnimInstance* AnimInstance = Cast<UHeroAnimInstance>(GetMesh()->GetAnimInstance());
if (AnimInstance != nullptr)
{
if (!AnimInstance->Montage_IsPlaying(AttackMontage)) // 如果该蒙太奇动画未在播放,则进行播放
{
Weapon->ActiveAttack();
float fDt = AnimInstance->Montage_Play(AttackMontage);
FTimerHandle ActiveWeapon;
GetWorld()->GetTimerManager().SetTimer(ActiveWeapon, [=]() {
Weapon->DeActiveAttack();
}, fDt, false);
}
}
}
接着我们创建一个接口,该接口是为了在发生碰撞中,只有实现了该接口的actor,才是有效的碰撞,如下图所示:
在接口函数中,定义一个受到伤害的函数,如下所示:
class BLOGPROJECT_API IBeAttackInterface
{
GENERATED_BODY()
// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
virtual void BeAttacked(float fDamage) = 0;
};
显然,我们的AI需要继承这个接口,并实现这个纯虚函数。我们可以在这个函数中,对我们的生命值进行加减,从而更新我们的血量。但是,这里我介绍另一种方法。
首先在AI类中,重写一个叫TakeDamage的方法。为什么使用这种方法呢,因为这个函数中有个伤害类型的字段,我们可以根据不同的伤害类型,来使我们的AI做出不同的表现,但这里我只是简单的更新我们的血量,只是说一个思路。如下所示:
virtual float TakeDamage(float Damage, struct FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser) override;
float AAIBlogCharacter::TakeDamage(float Damage, struct FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
CurrentHealth -= Damage;
if (CurrentHealth <= 0) // 受到足够的伤害了,销毁actor
{
Destroy();
}
return 0.0f;
}
注意,我们这个函数是虚函数,那应该怎么调用这个函数呢?其实是不用调用的,引擎已经帮我们做好了这些,只要我们调用applydamage,便会调用该回调函数,从而造成伤害。因此,在我们的武器类中,实现OnHIt函数,如下所示:
void AWeaponActor::OnHit(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
UE_LOG(LogTemp, Warning, TEXT("OnHit"));
if (bCanAttack && OtherActor != this) // 在攻击有效时,造成伤害
{
IBeAttackInterface* AC = Cast<IBeAttackInterface>(OtherActor);
if (AC != nullptr)
{
UGameplayStatics::ApplyDamage(OtherActor, 10.0f, nullptr, this, UDamageType::StaticClass()); // 造成10点伤害
}
}
}
编译代码并测试成功,可以看到我们已经对AI造成了伤害。: