血量属性
为了方便开发和维护我们通常将角色的血量蓝条或者其它属性放在Actor Component中然后绑定。
创建AttributeComponent(继承自ActorComponent)
protected:
UPROPERTY(EditDefaultsOnly,BlueprintReadOnly,Category="Attributes")
float Health;
public:
UFUNCTION(BlueprintCallable)
bool ApplyHealthChange(float Delta);
bool UAttributeComponent::ApplyHealthChange(float Delta)
{
if (Health<=0)
{
return false;
}
else
{
Health+=Delta;
return true;
}
}
然后在PlayerCharacter中实现它
//PlayerCharacter.h
protected:
UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category="Components")
UAttributeComponent* AttributeComp;
//PlayerCharacter.cpp
AttributeComp = CreateDefaultSubobject<UAttributeComponent>("AttributeComp");
然后需要在子弹中创建重叠事件,当事件触发时修改血量
//MagicProjectile.cpp
SphereComp->OnComponentBeginOverlap.AddDynamic(this,&AMagicProjectile::OnActorOverlap);
然后选中OnComponentBeginOverlap按f12找到定义,在定义的对象类型再按f12找到定义可以找到一个多播委托声明
DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_SixParams( FComponentBeginOverlapSignature,
UPrimitiveComponent, OnComponentBeginOverlap,
UPrimitiveComponent*, OverlappedComponent,
AActor*, OtherActor,
UPrimitiveComponent*, OtherComp,
int32, OtherBodyIndex,
bool, bFromSweep,
const FHitResult &, SweepResult);
FComponentBeginOverlapSignature是签名,后面一个是事件的名称,然后复制后面的所有参数粘贴到我们要绑定的OnactorOverlap函数的参数中,并且把逗号去掉
//MagicProjectile.h
protected:
UFUNCTION()
void OnActorOverlap(UPrimitiveComponent* OverlappedComponent,
AActor* OtherActor,
UPrimitiveComponent* OtherComp,
int32 OtherBodyIndex,
bool bFromSweep,
const FHitResult & SweepResult);
然后需要判断我们获取的OtherActor是有效的,获取它的AttributeComponent再调用ApplyHealthChange
//MagicProjectile.cpp
void AMagicProjectile::OnActorOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
if (OtherActor&&OtherActor!=GetInstigator())
{
//GetComponentByClass是一个迭代器,寻找第一个出现符合条件的我们指定的类
UAttributeComponent* AttributeComp = Cast<UAttributeComponent>(OtherActor->GetComponentByClass(UAttributeComponent::StaticClass()));
//确保AttributeComp不为空,比如立方体没有AttributeComp
if (AttributeComp)
{
AttributeComp->ApplyHealthChange(-20.0f);
Destroy();
}
}
}
事件
事件的好处是游戏不用每一帧都要检查这个值是否改变,只有当事件被触发的时候才会执行。
//AttributeComponent.h
//创建事件
//第一个参数是委托的名字,后面的参数自己设置
DECLARE_DYNAMIC_MULTICAST_DELEGATE_FourParams(FOnHealthChanged, AActor*, InstigatorActor, UAttributeComponent*, OwningComp, float, NewHeawlth, float, Delta);
//然后在类中创建委托的声明
//AttributeComponent.h
public:
UPROPERTY(BlueprintAssignable)
FOnHealthChanged OnHealthChanged;
//AttributeComponent.cpp
bool UAttributeComponent::ApplyHealthChange(float Delta)
{
if (Health<=0)
{
return false;
}
else
{
Health+=Delta;
//当Health发生改变的时候,所有绑定了这一个委托的函数都会被执行
OnHealthChanged.Broadcast(nullptr,this,Health,Delta);
//UE_LOG(LogTemp,Log,TEXT("Applying"));
return true;
}
}
然后可以在PlayerCharacter的AttributeComponent里的细节面板内找到我们刚刚创建的事件
并且调试一下
启动游戏之后可以看到只有当血量发生改变才会而不是每一帧都去检查血量是否改变