文章目錄
- 使用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、添加約束(不然膠囊體之間會斷開)
對約束增加一些限制
使用鏡像創造對稱的膠囊體(可以偷懶),對稱的約束需要手動重新調制
給兩個小腿也添加膠囊