CoopGame04-伤与挂#
本小节介绍#
- 实现的功能
- Actor对伤害做出反应,管理玩家的死亡
- 挑战:制作会爆炸的汽油桶
- 知识点:
- 自定义组件
- 自定义事件
- 死亡动画
- 使用材质
生命组件#
创建生命组件#
- 创建继承
ActorComponent
的C++类SHealthComponent
。目录为\CoopGame\Public\Component
生命组件的使用#
删除Tick函数相关
TickComponent
代码,声明和构造函数中的初始化,初始化组件用于处理伤害事件。在
SHealthComponent.h
声明当前生命值
,默认最大生命值
变量, 声明处理受伤的函数
1 2 3 4 5 6 7 8 9
//当前生命值 UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="HealthComponent") float Health; //默认最大生命值 UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category="HealthComponent") float DefaultHealth; //受任何伤害的函数,这个函数是自己声明的,用于受伤事件的回调函数,所以参数参考OnTakeAnyDamage.AddDynamic的委托 UFUNCTION() void HandleTakeAnyDamage(AActor* DamagedActor, float Damage, const class UDamageType* DamageType,class AController* InstigatedBy, AActor* DamageCauser);
用虚幻自带的委托绑定受伤的时候应该触发的函数,就是我们声明的
HandleTakeAnyDamage
回调函数,该函数处理受伤相关逻辑。在
SHealthComponent.cpp
中初始化默认最大生命值
变量, 绑定受伤的回调函数1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
USHealthComponent::USHealthComponent() { //初始化默认最大生命值 DefaultHealth =100; } void USHealthComponent::BeginPlay() { Super::BeginPlay(); AActor* MyOwner = GetOwner(); //用虚幻自带的委托OnTakeAnyDamage绑定HandleTakeAnyDamage函数 //当拥有者受到伤害时会自动调用HandleTakeAnyDamage函数 if (MyOwner) MyOwner->OnTakeAnyDamage.AddDynamic(this,&USHealthComponent::HandleTakeAnyDamage); //当前生命值等于默认最大生命值100 Health = DefaultHealth; } void USHealthComponent::HandleTakeAnyDamage(AActor* DamagedActor, float Damage, const UDamageType* DamageType, AController* InstigatedBy, AActor* DamageCauser) { if (Damage <= 0)return; //限定受伤后的生命值在0-默认最大生命值之间,包括这两个数 Health = FMath::Clamp(Health-Damage,0.0f,DefaultHealth); //打印受伤后的生命值 UE_LOG(LogTemp,Log,TEXT("被打的人说:我还剩:%s点血哦"),*FString::SanitizeFloat(Health)); }
将生命组件添加到角色身上,进行测试
- 在
BP_SCharacter
左上角添加组件,搜索SHealth
,添加。测试如图
- 在
动态多播委托#
- 定义六个参数的自定义事件宏,也就是动态多播委托,定义生命值改变的自定义事件。并在角色受伤后调用多播,意思是组件受伤后,告诉所有绑定了
OnHealthChanged
的地方,让他们执行相应的回调。注意这里OnHealthChanged
我们还没有绑定任何回调函数,后面会在蓝图绑定。在
SHealthComponent.h
声明动态多播委托,名为FOnHealthChangedSignature
,多播对象名为OnHealthChanged
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/* *DYNAMIC:可以在蓝图里被序列化后定义和绑定操作。 *MULTICAST:可实现一个事件类型多函数广播(事件类型必须声明为蓝图类型) *XXXParams:(使用DYNAMIC时)参数个数,宏定义参数里一个参数类型对应一个参数名字。 *动态多播委托,主要是可用于蓝图的委托绑定.可以作为变量给蓝图绑定调用,委托这块建议单独学习。 */ //声明一个动态多播委托类型,名字叫FOnHealthChangedSignature,有6个参数 DECLARE_DYNAMIC_MULTICAST_DELEGATE_SixParams(FOnHealthChangedSignature, USHealthComponent*, OwningHealthComp, float, Health, float, HealthDelta, const class UDamageType*, DamageType, class AController*, InstigatedBy, AActor*, DamageCauser); class COOPGAMEPLUS_API USHealthComponent : public UActorComponent { GENERATED_BODY() //... //声明动态多播对象,自定义事件——生命值改变事件(BlueprintAssignable仅能用于Multicast委托) UPROPERTY(BlueprintAssignable,Category="Events") FOnHealthChangedSignature OnHealthChanged; };
在
SHealthComponent.cpp
的HandleTakeAnyDamage
中进行广播1 2 3 4 5 6
void USHealthComponent::HandleTakeAnyDamage(AActor* DamagedActor, float Damage, const UDamageType* DamageType,AController* InstigatedBy, AActor* DamageCauser) { //... //执行多播调用 OnHealthChanged.Broadcast(this,Health,Damage,DamageType,InstigatedBy,DamageCauser); }
角色死亡动画#
给角色类
SCharacter
添加上生命值组件,将之前测试用的生命组件删除,我们需要改成在角色C++父类中添加组件在
SCharacter.h
声明生命组件
,角色是否死亡
变量,以及生命更新函数
1 2 3 4 5 6 7 8 9 10 11
//添加刚刚创建的生命组件 UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category="Components") class USHealthComponent* HealthComp; //生命值更新函数,为了和生命组件中的生命值更新委托对象OnHealthChanged区别开来,我想重命名为OnCharacterHealthChanged UFUNCTION() void OnCharacterHealthChanged(class USHealthComponent* OwningHealthComp,float Health,float HealthDelta, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser ); //角色是否死亡 UPROPERTY(BlueprintReadOnly, Category = "Player") bool bDied;
在
SCharacter.cpp
中初始化生命组件
,绑定之前的委托
到角色的生命值改变函数,定义角色的生命值改变函数中的逻辑1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
//导入生命组件头文件,Pawn的移动组件 #include "Component/SHealthComponent.h" #include "GameFramework/PawnMovementComponent.h" //在构造函数ASCharacter()中初始化生命组件 //创建生命值组件 HealthComp = CreateDefaultSubobject<USHealthComponent>(TEXT("HealthComp")); //在BeginPlay()函数中绑定委托OnHealthChanged的回调函数 //拿到生命组件中的委托对象OnHealthChanged,绑定回调函数为 HealthComp->OnHealthChanged.AddDynamic(this,&ASCharacter::OnCharacterHealthChanged); //定义受伤后生命改变的逻辑 void ASCharacter::OnCharacterHealthChanged(class USHealthComponent* OwningHealthComp, float Health, float HealthDelta, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser) { if (Health<=0 && !bDied){ //当生命值小于0,并且当前状态不是死亡时,设置为死亡状态 bDied = true; //运动组件停止运动 GetMovementComponent()->StopMovementImmediately(); //移除胶囊体所有碰撞 GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::NoCollision); //这后面就是播放死亡动画了 } }
设置角色的动画蓝图
UE4ASP_HeroTPP_AnimBlueprint
,在动画更新事件中拿到角色类中的bDied
并提升为变量,以便动画蓝图判断角色是否死亡。在动画图标中添加混合姿势,根据角色死亡的布尔值来混合死亡动画,死亡动画序列记得关闭循环
创建战争机器风格的生命指示材质和控件#
略
挑战:会爆炸的汽油桶#
略