在上一文中,我们讲述了如何创建一个武器,并将武器装备到人物的手上,接下来我们要讲述的就是如何为武器actor添加碰撞事件,使我们在挥刀的时候,能够产生伤害。
首先在weaponactor类里添加成员,如下所示:
UPROPERTY(EditAnywhere, Category = Collision)
class UBoxComponent* WeaponCollision;
FORCEINLINE class UBoxComponent* GetWeaponCollision() { return WeaponCollision; }
使用UPROPERTY,并置为EditAnywhere的原因,就是让我们能在编辑器中以可视化的方式调整碰撞体的大小,使之能刚好与我们的剑适配。接下来我们在构造函数中,使用CreateSubObject创建该碰撞体,并将其设置为NOCollision,关闭碰撞的原因是,我们想让我们的人物做出挥刀的动作时,再开启碰撞。如下所示:
WeaponCollision = CreateDefaultSubobject<UBoxComponent>(TEXT("WeaponCollision"));
if (WeaponCollision != nullptr)
{
WeaponCollision->SetCollisionEnabled(ECollisionEnabled::NoCollision);
}
接下来就要为我们的碰撞体绑定函数,使我们的碰撞体在碰撞到物体,比如敌人时,产生回调,通知我们砍到了敌人,然后再产生伤害。首先定义类成员函数,如下所示:
UFUNCTION()
void OnHit(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
现在暂时不实现该函数,只是打印下日志,如下所示:
void AWeaponActor::OnHit(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
UE_LOG(LogTemp, Warning, TEXT("OnHit"));
}
在beginplay函数中,绑定碰撞体的回调函数,如下所示:
void AWeaponActor::BeginPlay()
{
Super::BeginPlay();
if (WeaponCollision != nullptr)
{
WeaponCollision->OnComponentBeginOverlap.AddDynamic(this, &AWeaponActor::OnHit);
}
}
接着编译我们的代码,然后在编辑器中,调整碰撞体的大小及长款之类的,在weaponactor中,右键,选择创建蓝图,如下图所示:
然后打开我们创建的武器蓝图,调整我们的boxcollison的大小,如下图所示:
既然我们有了武器蓝图类,那我们在spawn武器的actor时,便可以使用这个蓝图类作为我们的模板来创建武器,当然,我们也可以查看boxcollision的transform,然后在代码中设置,这里我采用第一种方案,就是使用蓝图类模板来创建武器,因此需要修改我们的character类,首先在character类中添加成员TSubclassOf<AWeaponActor> WeaponM,如下:
TSubclassOf<class AWeaponActor> WeaponM;
接着在character构造函数中,使用constructhelpers找到该类,如下:
static ConstructorHelpers::FClassFinder<AWeaponActor> WeaponBP(TEXT("/Game/ThirdPersonCPP/Blueprints/WeaponActorBP"));
if (WeaponBP.Succeeded())
{
WeaponM = WeaponBP.Class;
}
接着在beginplay中,修改我们的创建方式,如下所示:
void ABlogProjectCharacter::BeginPlay()
{
Super::BeginPlay(); // 记得一定先调父类的函数
//武器的添加
//Weapon = GetWorld()->SpawnActor<AWeaponActor>(AWeaponActor::StaticClass()); // 之前的创建方式
Weapon = GetWorld()->SpawnActor<AWeaponActor>(WeaponM->StaticClass());
if (Weapon != nullptr)
{
// 附加武器,保持位置
Weapon->GetWeaponMesh()->AttachToComponent(GetMesh(), FAttachmentTransformRules::KeepRelativeTransform, TEXT("weapon"));
}
}
测试如下:
但是,我发现OnHit函数不是每次都触发,经谷歌,才知道,人物在跑动的时候,碰撞检测只会检测rootcomponnet,因此,attach是不行的。所以修改如下:
void ABlogProjectCharacter::BeginPlay()
{
Super::BeginPlay(); // 记得一定先调父类的函数
//武器的添加
//Weapon = GetWorld()->SpawnActor<AWeaponActor>(AWeaponActor::StaticClass()); // 之前的创建方式
Weapon = GetWorld()->SpawnActor<AWeaponActor>(WeaponM);
//if (Weapon != nullptr)
//{
// // 附加武器,保持位置
// Weapon->GetWeaponMesh()->AttachToComponent(GetMesh(), FAttachmentTransformRules::KeepRelativeTransform, TEXT("weapon"));
//}
}
void ABlogProjectCharacter::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
if (Weapon != nullptr)
{
FVector Location;
FQuat Rotation;
GetMesh()->GetSocketWorldLocationAndRotation(TEXT("weapon"), Location, Rotation);
Weapon->SetActorLocation(Location);
Weapon->SetActorRotation(Rotation);
Weapon->GetWeaponMesh()->SetWorldLocationAndRotation(Location, Rotation);
}
}