本功能可在蓝图中完成,也可以在C++中完成,本例选择部分在蓝图中完成。
首先我们新建一个蒙太奇动画,用于敌人角色死亡时候播放。
回到AttributeSetBase中对血量范围进行限制,下限到0即可。
PostGameplayEffectExecute方法修改为如下:
void UAttributeSetBase::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
if (Data.EvaluatedData.Attribute.GetUProperty() == FindFieldChecked<UProperty>(UAttributeSetBase::StaticClass(),GET_MEMBER_NAME_CHECKED(UAttributeSetBase,Health))) {
Health.SetCurrentValue(FMath::Clamp(Health.GetCurrentValue(),0.0f,MaxHealth.GetCurrentValue()));
Health.SetBaseValue(FMath::Clamp(Health.GetBaseValue(),0.0f,MaxHealth.GetBaseValue()));
onHealthChangeDelegate.Broadcast(Health.GetCurrentValue(),MaxHealth.GetCurrentValue());
UE_LOG(LogTemp, Warning, TEXT("Health : %f"), Health.GetBaseValue());
}
}
在主角头文件中增加以下代码:
UFUNCTION(BlueprintImplementableEvent)
void onDie();
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Shinbi | Status")
bool isDead;
一个是执行角色死亡时刻的事情,这一部分交给蓝图,所以宏定义用了BlueprintImplementableEvent
isDead用来判断角色是否死亡,这一部分在C++中完成。isDead在构造函数中初始化的值为false。
OnDamage方法中的代码增加为如下:
void AShinbi::onDamage(float Health, float MaxHealth) {
float temp = Health / MaxHealth;
UUserWidget* tobeCast = widget->GetUserWidgetObject();
UHealthWidget* bp123 = Cast<UHealthWidget>(tobeCast);
bp123->healthBar->SetPercent(temp);
if (Health <= 0) {
isDead = true;
onDie();
}
}
当血量小于等于0的时候,死亡状态改为真,且执行OnDie事件。
在敌人的蓝图中按照以下连接:
动画选择为我们创建的蒙太奇(角色死亡的)动画。
此时还不能实现播放功能,因为动作还没有进行融合,如果现在就播放实现效果会出现BUG,人物动作卡主,且无法收回。
笔者检查了所有可能的原因之后,锁定了动画蓝图的动作融合。
现在打开动画蓝图:
添加一个slot,并选择我们之前在蒙太奇中的分组,将状态机的cache与该slot链接,并创建新的cache。
将新建的cache——“DiePoses”,与之前的Layerd Blend per bone相连,在连接之前Add一个新的引脚。
点击Layerd Blend per bone,在Layer Setup属性中新建一个,此时编号为1,对应我们的Blend poses 1,因为死亡的动画与站立的动画相差还是很大的,这里选择的Bone Name为“root”,融合深度为1.
然后通过是否死亡状态判断该播放哪段动画,且进行融合。
当人物角色死亡的时候,播放true pose,没有死亡的时候,播放false pose。
那这个isDead变量的数据从哪来呢,从C++中来。
之前在C++中定义的isDead变量数据专递给这个蓝图中的isDead变量就可以了。
现在离成功就只有一步了。
现在进行攻击的话,自己角色的血量也会掉。
这是有问题的,难道是自己砍了自己一刀吗?
所以我们需要对攻击对象进行限制。
打开GA_Melee的GameplayAbility蓝图。
在waitGameplayEvent模块后增加一个Cast模块,Cast到敌人的蓝图类型即可。这样自己的角色就不会掉血了。
运行成功,没有BUG,效果如下: