文章目录
- 使用GE为角色添加定时的Tag控制死亡时间
- 1、添加死亡Tag
- 2、创建死亡GE,并完成相关配置
- 3、在AbilitySystemComponent中监听属性的变化,调用GE来添加Tag到角色上
- 4、在角色中监听ASC传入的Tag以及Tag的层数,来响应不同的函数
- 添加死亡、复活的逻辑
- 1、在`CAbilitySystemComponent`中,添加回血回蓝函数
- 2、在`CCharacter`中添加动画蒙太奇,添加一些逻辑
- 3、到子类`CPlayerCharacter`中覆盖`OnDead`和`OnRespawn`
- 添加布娃娃
- 对物理资产的修改调整
- 1、添加胶囊体
- 2、添加约束(不然胶囊体之间会断开)
使用GE为角色添加定时的Tag控制死亡时间
1、添加死亡Tag
去Tag中添加新的标签
CRUNCH_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Stats_Dead)
UE_DEFINE_GAMEPLAY_TAG_COMMENT(Stats_Dead, "Stats.Dead", "死亡")
2、创建死亡GE,并完成相关配置
添加新的GEGE_Death
使用拥有持续时间
策略,后面幅度计算类型会采用属性基础
,用等级来计算死亡时间,添加死亡标签到角色上
3、在AbilitySystemComponent中监听属性的变化,调用GE来添加Tag到角色上
到能力组件CAbilitySystemComponent
中监听生命的变化,对生命值为0的时候添加死亡的GE
public:UCAbilitySystemComponent();// 添加GEvoid AuthApplyGameplayEffect(TSubclassOf<UGameplayEffect> GameplayEffect, int Level = 1);private:void HealthUpdated(const FOnAttributeChangeData& ChangeData);// 死亡效果UPROPERTY(EditDefaultsOnly, Category = "Gameplay Effects")TSubclassOf<UGameplayEffect> DeathEffect;
UCAbilitySystemComponent::UCAbilitySystemComponent()
{GetGameplayAttributeValueChangeDelegate(UCAttributeSet::GetHealthAttribute()).AddUObject(this, &UCAbilitySystemComponent::HealthUpdated);
}void UCAbilitySystemComponent::AuthApplyGameplayEffect(TSubclassOf<UGameplayEffect> GameplayEffect, int Level)
{if (GetOwner() && GetOwner()->HasAuthority()){FGameplayEffectSpecHandle EffectSpecHandle = MakeOutgoingSpec(GameplayEffect, Level, MakeEffectContext());ApplyGameplayEffectSpecToSelf(*EffectSpecHandle.Data.Get());}
}void UCAbilitySystemComponent::HealthUpdated(const FOnAttributeChangeData& ChangeData)
{if (!GetOwner() || !GetOwner()->HasAuthority()) return;if (ChangeData.NewValue <= 0.0f){// 角色死亡if (DeathEffect){AuthApplyGameplayEffect(DeathEffect);}}
}
4、在角色中监听ASC传入的Tag以及Tag的层数,来响应不同的函数
在能力系统中使用了GE
来获取Tag
,然后来到角色中监听ASC
获取到的Tag
做出相应的响应,到CCharacter
中:
#pragma region GAS组件相关
private:// 绑定GAS属性改变委托void BindGASChangeDelegates();// 死亡标签更新void DeathTagUpdated(const FGameplayTag Tag, int32 NewCount);#pragma endregion#pragma region 死亡和复活 (Death and Respawn)
private:void StartDeathSequence();void Respawn();
#pragma endregion
在角色构造函数中添加,绑定要在实现能力组件和属性初始化的下面。
ACCharacter::ACCharacter()
{PrimaryActorTick.bCanEverTick = true;// 禁用网格的碰撞功能GetMesh()->SetCollisionEnabled(ECollisionEnabled::NoCollision);CAbilitySystemComponent = CreateDefaultSubobject<UCAbilitySystemComponent>(TEXT("CAbilitySystemComponent"));CAttributeSet = CreateDefaultSubobject<UCAttributeSet>(TEXT("CAttributeSet"));OverHeadWidgetComponent = CreateDefaultSubobject<UWidgetComponent>(TEXT("OverHeadWidgetComponent"));OverHeadWidgetComponent->SetupAttachment(GetRootComponent());// 绑定GAS属性改变委托BindGASChangeDelegates();
}void ACCharacter::BindGASChangeDelegates()
{if (CAbilitySystemComponent){CAbilitySystemComponent->RegisterGameplayTagEvent(TGameplayTags::Stats_Dead).AddUObject(this, &ACCharacter::DeathTagUpdated);}
}void ACCharacter::DeathTagUpdated(const FGameplayTag Tag, int32 NewCount)
{// 标签数量不为0时,死亡。为0则复活。if (NewCount != 0){StartDeathSequence();}else{Respawn();}
}void ACCharacter::StartDeathSequence()
{UE_LOG(LogTemp, Warning, TEXT("%s:狗带"),*GetName())
}void ACCharacter::Respawn()
{UE_LOG(LogTemp, Warning, TEXT("%s:复活"),*GetName())
}
在角色蓝图中给角色添加死亡GE
添加死亡、复活的逻辑
1、在CAbilitySystemComponent
中,添加回血回蓝函数
// 回满血、满蓝效果void ApplyFullStatEffect();// 满血、满蓝效果UPROPERTY(EditDefaultsOnly, Category = "Gameplay Effects")TSubclassOf<UGameplayEffect> FullStatEffect;
void UCAbilitySystemComponent::ApplyFullStatEffect()
{AuthApplyGameplayEffect(FullStatEffect);
}
2、在CCharacter
中添加动画蒙太奇,添加一些逻辑
#pragma region UI/*** @brief 设置头顶状态条的启用状态\n* 启用或禁用头顶UI组件的显示。\n* @param bIsEnabled 是否启用头顶UI*/void SetStatusGaugeEnabled(bool bIsEnabled);
#pragma endregion
#pragma region 死亡和复活 (Death and Respawn)
private:// 死亡蒙太奇UPROPERTY(EditDefaultsOnly, Category = "Death")TObjectPtr<UAnimMontage> DeathMontage;// 播放死亡动画void PlayDeathAnimation();// 死亡void StartDeathSequence();// 复活void Respawn();// 子类中实现virtual void OnDead();virtual void OnRespawn();
#pragma endregion
void ACCharacter::SetStatusGaugeEnabled(bool bIsEnabled)
{// 清除定时器GetWorldTimerManager().ClearTimer(HeadStatGaugeVisibilityUpdateTimerHandle);if (bIsEnabled){// 启动头顶血条ConfigureOverHeadStatusWidget();}else{// 关闭头顶血条OverHeadWidgetComponent->SetHiddenInGame(true);}
}void ACCharacter::PlayDeathAnimation()
{if (DeathMontage){PlayAnimMontage(DeathMontage);}
}void ACCharacter::StartDeathSequence()
{OnDead();// 播放死亡动画PlayDeathAnimation();// 关闭头顶血条SetStatusGaugeEnabled(false);// 禁用移动GetCharacterMovement()->SetMovementMode(EMovementMode::MOVE_None);// 禁用碰撞GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::NoCollision);UE_LOG(LogTemp, Warning, TEXT("%s:狗带"),*GetName())
}void ACCharacter::Respawn()
{OnRespawn();SetStatusGaugeEnabled(true);// 开启移动GetCharacterMovement()->SetMovementMode(EMovementMode::MOVE_Walking);// 开启碰撞GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);GetMesh()->GetAnimInstance()->StopAllMontages(0.f);if (CAbilitySystemComponent){CAbilitySystemComponent->ApplyFullStatEffect();}UE_LOG(LogTemp, Warning, TEXT("%s:复活"),*GetName())
}void ACCharacter::OnDead()
{
}void ACCharacter::OnRespawn()
{
}
3、到子类CPlayerCharacter
中覆盖OnDead
和OnRespawn
#pragma region Input// 输入开关void SetInputEnabledFromPlayerController(bool bEnabled);
#pragma endregion
#pragma region 死亡和复活 (Death and Respawn)virtual void OnDead() override;virtual void OnRespawn() override;
#pragma endregion
void ACPlayerCharacter::SetInputEnabledFromPlayerController(bool bEnabled)
{// 获取玩家控制器APlayerController* PlayerController = GetController<APlayerController>();// 如果玩家控制器为空,则返回if (!PlayerController){return;}if (bEnabled){// 启用玩家控制器输入EnableInput(PlayerController);}else{// 禁用玩家控制器输入DisableInput(PlayerController);}
}void ACPlayerCharacter::OnDead()
{// 死亡,禁用玩家控制器输入SetInputEnabledFromPlayerController(false);
}void ACPlayerCharacter::OnRespawn()
{// 复活,启用玩家控制器输入SetInputEnabledFromPlayerController(true);
}
创建一个死亡蒙太奇,设置新的插槽,关闭自动混出
在动画蓝图中添加这个新的插槽
到角色中添加死亡蒙太奇
添加补状态的GE
,这个GE
在初始化属性的时候创建了
打死后又会复活:
添加布娃娃
#pragma region 死亡和复活 (Death and Respawn)
private:// 相对于网格的变换FTransform MeshRelativeTransform;// 死亡蒙太奇完成时间偏移UPROPERTY(EditDefaultsOnly, Category = "Death")float DeathMontageFinishTimeShift = -0.8f;// 死亡蒙太奇UPROPERTY(EditDefaultsOnly, Category = "Death")TObjectPtr<UAnimMontage> DeathMontage;// 死亡蒙太奇计时器句柄FTimerHandle DeathMontageTimerHandle;// 死亡蒙太奇完成处理void DeathMontageFinished();// 启用/禁用 布娃娃系统void SetRagdollEnabled(bool bIsEnabled);// 播放死亡动画void PlayDeathAnimation();// 死亡void StartDeathSequence();// 复活void Respawn();virtual void OnDead();virtual void OnRespawn();
#pragma endregion
void ACCharacter::BeginPlay()
{Super::BeginPlay();ConfigureOverHeadStatusWidget();MeshRelativeTransform = GetMesh()->GetRelativeTransform();//UE_LOG(LogTemp, Warning, TEXT("ACCharacter::BeginPlay,%hhd"),GetIsReplicated());//UE_LOG(LogTemp, Warning, TEXT("True是:,%hhd"),true);
}void ACCharacter::DeathMontageFinished()
{SetRagdollEnabled(true);
}void ACCharacter::SetRagdollEnabled(bool bIsEnabled)
{if (bIsEnabled){GetMesh()->DetachFromComponent(FDetachmentTransformRules::KeepWorldTransform); // 从父组件分离网格,但保持世界变换不变GetMesh()->SetSimulatePhysics(true); // 启用物理模拟GetMesh()->SetCollisionEnabled(ECollisionEnabled::PhysicsOnly); // 仅启用物理碰撞}else{GetMesh()->SetSimulatePhysics(false); // 禁用物理模拟GetMesh()->SetCollisionEnabled(ECollisionEnabled::NoCollision); // 禁用碰撞GetMesh()->AttachToComponent(GetRootComponent(), FAttachmentTransformRules::KeepRelativeTransform); // 将网格重新附加到根组件,保持相对变换GetMesh()->SetRelativeTransform(MeshRelativeTransform); // 设置网格的相对变换}
}void ACCharacter::PlayDeathAnimation()
{if (DeathMontage){// 获取死亡蒙太奇的持续时间float MontageDuration = PlayAnimMontage(DeathMontage);GetWorldTimerManager().SetTimer(DeathMontageTimerHandle, this, &ACCharacter::DeathMontageFinished, MontageDuration + DeathMontageFinishTimeShift);}
}void ACCharacter::StartDeathSequence()
{OnDead();// 播放死亡动画PlayDeathAnimation();// 关闭头顶血条SetStatusGaugeEnabled(false);// 禁用移动GetCharacterMovement()->SetMovementMode(EMovementMode::MOVE_None);// 禁用碰撞GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::NoCollision);UE_LOG(LogTemp, Warning, TEXT("%s:狗带"),*GetName())
}void ACCharacter::Respawn()
{OnRespawn();// 关闭布娃娃SetRagdollEnabled(false);// 开启血条SetStatusGaugeEnabled(true);// 开启移动GetCharacterMovement()->SetMovementMode(EMovementMode::MOVE_Walking);// 开启碰撞GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);// 停止所有蒙太奇GetMesh()->GetAnimInstance()->StopAllMontages(0.f);// 应用全属性if (CAbilitySystemComponent){CAbilitySystemComponent->ApplyFullStatEffect();}UE_LOG(LogTemp, Warning, TEXT("%s:复活"),*GetName())
}
用上了布娃娃系统后
对物理资产的修改调整
删除手上两个胶囊体
可以显示所有骨骼
1、添加胶囊体
2、添加约束(不然胶囊体之间会断开)
对约束增加一些限制
使用镜像创造对称的胶囊体(可以偷懒),对称的约束需要手动重新调制
给两个小腿也添加胶囊