diff --git a/Config/DefaultEngine.ini b/Config/DefaultEngine.ini index a6fc21f..7fa7c44 100644 --- a/Config/DefaultEngine.ini +++ b/Config/DefaultEngine.ini @@ -1,9 +1,9 @@ [/Script/EngineSettings.GameMapsSettings] -GameDefaultMap=/Game/ThirdPerson/L_TestMap.L_TestMap +GameDefaultMap=/Game/ThirdPerson/L_Lobby.L_Lobby EditorStartupMap=/Game/ThirdPerson/L_TestMap.L_TestMap GlobalDefaultGameMode=/Game/ThirdPerson/Blueprints/BP_ThirdPersonGameMode.BP_ThirdPersonGameMode_C GameInstanceClass=/Game/ThirdPerson/Blueprints/BP_GameInstance.BP_GameInstance_C -ServerDefaultMap=/Game/ThirdPerson/L_TestMap.L_TestMap +ServerDefaultMap=/Game/ThirdPerson/L_Lobby.L_Lobby [/Script/Engine.RendererSettings] r.ReflectionMethod=1 diff --git a/Config/DefaultGame.ini b/Config/DefaultGame.ini index cb96856..c312692 100644 --- a/Config/DefaultGame.ini +++ b/Config/DefaultGame.ini @@ -1,3 +1,113 @@ [/Script/EngineSettings.GeneralProjectSettings] ProjectID=BAC1FC37410EC6AF53AC54BD0C2A91AC ProjectName=Third Person Game Template + +[/Script/UnrealEd.ProjectPackagingSettings] +Build=IfProjectHasCode +BuildConfiguration=PPBC_Development +BuildTarget=PvPDemo +FullRebuild=False +ForDistribution=False +IncludeDebugFiles=False +BlueprintNativizationMethod=Disabled +bIncludeNativizedAssetsInProjectGeneration=False +bExcludeMonolithicEngineHeadersInNativizedCode=False +UsePakFile=True +bUseIoStore=True +bUseZenStore=False +bMakeBinaryConfig=False +bGenerateChunks=False +bGenerateNoChunks=False +bChunkHardReferencesOnly=False +bForceOneChunkPerFile=False +MaxChunkSize=0 +bBuildHttpChunkInstallData=False +HttpChunkInstallDataDirectory=(Path="") +WriteBackMetadataToAssetRegistry=Disabled +bWritePluginSizeSummaryJsons=False +bCompressed=True +PackageCompressionFormat=Oodle +bForceUseProjectCompressionFormatIgnoreHardwareOverride=False +PackageAdditionalCompressionOptions= +PackageCompressionMethod=Kraken +PackageCompressionLevel_DebugDevelopment=4 +PackageCompressionLevel_TestShipping=4 +PackageCompressionLevel_Distribution=7 +PackageCompressionMinBytesSaved=1024 +PackageCompressionMinPercentSaved=5 +bPackageCompressionEnableDDC=False +PackageCompressionMinSizeToConsiderDDC=0 +HttpChunkInstallDataVersion= +IncludePrerequisites=True +IncludeAppLocalPrerequisites=False +bShareMaterialShaderCode=True +bDeterministicShaderCodeOrder=False +bSharedMaterialNativeLibraries=True +ApplocalPrerequisitesDirectory=(Path="") +IncludeCrashReporter=False +InternationalizationPreset=English +-CulturesToStage=en ++CulturesToStage=en +LocalizationTargetCatchAllChunkId=0 +bCookAll=False +bCookMapsOnly=False +bTreatWarningsAsErrorsOnCook=False +bSkipEditorContent=False +bSkipMovies=False +-IniKeyDenylist=KeyStorePassword +-IniKeyDenylist=KeyPassword +-IniKeyDenylist=DebugKeyStorePassword +-IniKeyDenylist=DebugKeyPassword +-IniKeyDenylist=rsa.privateexp +-IniKeyDenylist=rsa.modulus +-IniKeyDenylist=rsa.publicexp +-IniKeyDenylist=aes.key +-IniKeyDenylist=SigningPublicExponent +-IniKeyDenylist=SigningModulus +-IniKeyDenylist=SigningPrivateExponent +-IniKeyDenylist=EncryptionKey +-IniKeyDenylist=DevCenterUsername +-IniKeyDenylist=DevCenterPassword +-IniKeyDenylist=IOSTeamID +-IniKeyDenylist=SigningCertificate +-IniKeyDenylist=MobileProvision +-IniKeyDenylist=AppStoreConnectKeyPath +-IniKeyDenylist=AppStoreConnectIssuerID +-IniKeyDenylist=AppStoreConnectKeyID +-IniKeyDenylist=IniKeyDenylist +-IniKeyDenylist=IniSectionDenylist ++IniKeyDenylist=KeyStorePassword ++IniKeyDenylist=KeyPassword ++IniKeyDenylist=DebugKeyStorePassword ++IniKeyDenylist=DebugKeyPassword ++IniKeyDenylist=rsa.privateexp ++IniKeyDenylist=rsa.modulus ++IniKeyDenylist=rsa.publicexp ++IniKeyDenylist=aes.key ++IniKeyDenylist=SigningPublicExponent ++IniKeyDenylist=SigningModulus ++IniKeyDenylist=SigningPrivateExponent ++IniKeyDenylist=EncryptionKey ++IniKeyDenylist=DevCenterUsername ++IniKeyDenylist=DevCenterPassword ++IniKeyDenylist=IOSTeamID ++IniKeyDenylist=SigningCertificate ++IniKeyDenylist=MobileProvision ++IniKeyDenylist=AppStoreConnectKeyPath ++IniKeyDenylist=AppStoreConnectIssuerID ++IniKeyDenylist=AppStoreConnectKeyID ++IniKeyDenylist=IniKeyDenylist ++IniKeyDenylist=IniSectionDenylist +-IniSectionDenylist=HordeStorageServers +-IniSectionDenylist=StorageServers +-IniSectionDenylist=/Script/AndroidFileServerEditor.AndroidFileServerRuntimeSettings ++IniSectionDenylist=HordeStorageServers ++IniSectionDenylist=StorageServers ++IniSectionDenylist=/Script/AndroidFileServerEditor.AndroidFileServerRuntimeSettings ++MapsToCook=(FilePath="/Game/ThirdPerson/L_Lobby") ++MapsToCook=(FilePath="/Game/ThirdPerson/L_LoginMap") ++MapsToCook=(FilePath="/Game/PolygonApocalypse/Maps/Demonstration") ++DirectoriesToAlwaysCook=(Path="/NNEDenoiser") +bRetainStagedDirectory=False +CustomStageCopyHandler= + diff --git a/Config/DefaultGameplayTags.ini b/Config/DefaultGameplayTags.ini index 1dc4848..11395d1 100644 --- a/Config/DefaultGameplayTags.ini +++ b/Config/DefaultGameplayTags.ini @@ -15,3 +15,4 @@ NetIndexFirstBitSegment=16 +GameplayTagList=(Tag="Attributes.Vital.Health",DevComment="") +GameplayTagList=(Tag="Item.Held.Fireball",DevComment="") +GameplayTagList=(Tag="State.Dead",DevComment="") ++GameplayTagList=(Tag="State.Slowed",DevComment="") diff --git a/Content/Input/Actions/IA_Sprint.uasset b/Content/Input/Actions/IA_Sprint.uasset new file mode 100644 index 0000000..61eeb75 Binary files /dev/null and b/Content/Input/Actions/IA_Sprint.uasset differ diff --git a/Content/Input/IMC_Default.uasset b/Content/Input/IMC_Default.uasset index 85607e0..c1f09da 100644 Binary files a/Content/Input/IMC_Default.uasset and b/Content/Input/IMC_Default.uasset differ diff --git a/Content/PvPDemo/Blueprints/AI/BP_Bot.uasset b/Content/PvPDemo/Blueprints/AI/BP_Bot.uasset index 44ed3ce..fd2dd51 100644 Binary files a/Content/PvPDemo/Blueprints/AI/BP_Bot.uasset and b/Content/PvPDemo/Blueprints/AI/BP_Bot.uasset differ diff --git a/Content/PvPDemo/Blueprints/AI/BT_AI.uasset b/Content/PvPDemo/Blueprints/AI/BT_AI.uasset index 116b39f..814fa57 100644 Binary files a/Content/PvPDemo/Blueprints/AI/BT_AI.uasset and b/Content/PvPDemo/Blueprints/AI/BT_AI.uasset differ diff --git a/Content/PvPDemo/Blueprints/AI/Task/BTTask_AttackTarget.uasset b/Content/PvPDemo/Blueprints/AI/Task/BTTask_AttackTarget.uasset index 2778a91..8a6fa83 100644 Binary files a/Content/PvPDemo/Blueprints/AI/Task/BTTask_AttackTarget.uasset and b/Content/PvPDemo/Blueprints/AI/Task/BTTask_AttackTarget.uasset differ diff --git a/Content/PvPDemo/Blueprints/AI/Task/BTTask_FindNearestItem.uasset b/Content/PvPDemo/Blueprints/AI/Task/BTTask_FindNearestItem.uasset index 2d46078..4b2017d 100644 Binary files a/Content/PvPDemo/Blueprints/AI/Task/BTTask_FindNearestItem.uasset and b/Content/PvPDemo/Blueprints/AI/Task/BTTask_FindNearestItem.uasset differ diff --git a/Content/PvPDemo/Blueprints/AI/Task/BTTask_FindTargetPlayer.uasset b/Content/PvPDemo/Blueprints/AI/Task/BTTask_FindTargetPlayer.uasset index d4695c7..127b81e 100644 Binary files a/Content/PvPDemo/Blueprints/AI/Task/BTTask_FindTargetPlayer.uasset and b/Content/PvPDemo/Blueprints/AI/Task/BTTask_FindTargetPlayer.uasset differ diff --git a/Content/PvPDemo/Blueprints/AI/Task/BTTask_PickupItem.uasset b/Content/PvPDemo/Blueprints/AI/Task/BTTask_PickupItem.uasset index fa0e8c6..f5fd8ba 100644 Binary files a/Content/PvPDemo/Blueprints/AI/Task/BTTask_PickupItem.uasset and b/Content/PvPDemo/Blueprints/AI/Task/BTTask_PickupItem.uasset differ diff --git a/Content/PvPDemo/Blueprints/GAS/Effect/GE_Fireball.uasset b/Content/PvPDemo/Blueprints/GAS/Effect/GE_Fireball.uasset index 8178c8d..3a4cfd5 100644 Binary files a/Content/PvPDemo/Blueprints/GAS/Effect/GE_Fireball.uasset and b/Content/PvPDemo/Blueprints/GAS/Effect/GE_Fireball.uasset differ diff --git a/Content/PvPDemo/Blueprints/GAS/Effect/GE_Heal.uasset b/Content/PvPDemo/Blueprints/GAS/Effect/GE_Heal.uasset index cd98607..b4969f4 100644 Binary files a/Content/PvPDemo/Blueprints/GAS/Effect/GE_Heal.uasset and b/Content/PvPDemo/Blueprints/GAS/Effect/GE_Heal.uasset differ diff --git a/Content/PvPDemo/Blueprints/GAS/Effect/GE_Waterball.uasset b/Content/PvPDemo/Blueprints/GAS/Effect/GE_Waterball.uasset index d3fd39f..c31a824 100644 Binary files a/Content/PvPDemo/Blueprints/GAS/Effect/GE_Waterball.uasset and b/Content/PvPDemo/Blueprints/GAS/Effect/GE_Waterball.uasset differ diff --git a/Content/PvPDemo/Blueprints/GAS/Effect/GE_Waterball_Damage.uasset b/Content/PvPDemo/Blueprints/GAS/Effect/GE_Waterball_Damage.uasset new file mode 100644 index 0000000..fe6d8ee Binary files /dev/null and b/Content/PvPDemo/Blueprints/GAS/Effect/GE_Waterball_Damage.uasset differ diff --git a/Content/PvPDemo/Blueprints/GAS/GA_UseFirstItem.uasset b/Content/PvPDemo/Blueprints/GAS/GA_UseFirstItem.uasset index c654a28..1066c37 100644 Binary files a/Content/PvPDemo/Blueprints/GAS/GA_UseFirstItem.uasset and b/Content/PvPDemo/Blueprints/GAS/GA_UseFirstItem.uasset differ diff --git a/Content/PvPDemo/Blueprints/Item/BP_FakeShootItem.uasset b/Content/PvPDemo/Blueprints/Item/BP_FakeShootItem.uasset index 90591b5..16ee083 100644 Binary files a/Content/PvPDemo/Blueprints/Item/BP_FakeShootItem.uasset and b/Content/PvPDemo/Blueprints/Item/BP_FakeShootItem.uasset differ diff --git a/Content/PvPDemo/Blueprints/Item/BP_Item.uasset b/Content/PvPDemo/Blueprints/Item/BP_Item.uasset index ec3eb7c..1758040 100644 Binary files a/Content/PvPDemo/Blueprints/Item/BP_Item.uasset and b/Content/PvPDemo/Blueprints/Item/BP_Item.uasset differ diff --git a/Content/PvPDemo/Blueprints/Item/BP_ItemManager.uasset b/Content/PvPDemo/Blueprints/Item/BP_ItemManager.uasset index 0625508..4e6885b 100644 Binary files a/Content/PvPDemo/Blueprints/Item/BP_ItemManager.uasset and b/Content/PvPDemo/Blueprints/Item/BP_ItemManager.uasset differ diff --git a/Content/PvPDemo/Blueprints/Item/BP_ItemSpawner.uasset b/Content/PvPDemo/Blueprints/Item/BP_ItemSpawner.uasset index 8143b94..5ff9fba 100644 Binary files a/Content/PvPDemo/Blueprints/Item/BP_ItemSpawner.uasset and b/Content/PvPDemo/Blueprints/Item/BP_ItemSpawner.uasset differ diff --git a/Content/PvPDemo/Blueprints/Item/BP_ShootItem.uasset b/Content/PvPDemo/Blueprints/Item/BP_ShootItem.uasset index d5d3ff1..7195004 100644 Binary files a/Content/PvPDemo/Blueprints/Item/BP_ShootItem.uasset and b/Content/PvPDemo/Blueprints/Item/BP_ShootItem.uasset differ diff --git a/Content/PvPDemo/Blueprints/UMG/WBP_LoginUI.uasset b/Content/PvPDemo/Blueprints/UMG/WBP_LoginUI.uasset index 63aea09..11e1fd5 100644 Binary files a/Content/PvPDemo/Blueprints/UMG/WBP_LoginUI.uasset and b/Content/PvPDemo/Blueprints/UMG/WBP_LoginUI.uasset differ diff --git a/Content/PvPDemo/Blueprints/UMG/WBP_MainUI.uasset b/Content/PvPDemo/Blueprints/UMG/WBP_MainUI.uasset index 9aa7fc6..9ff9418 100644 Binary files a/Content/PvPDemo/Blueprints/UMG/WBP_MainUI.uasset and b/Content/PvPDemo/Blueprints/UMG/WBP_MainUI.uasset differ diff --git a/Content/PvPDemo/Blueprints/UMG/Widget/WBP_Countdown.uasset b/Content/PvPDemo/Blueprints/UMG/Widget/WBP_Countdown.uasset index 31b924b..789c629 100644 Binary files a/Content/PvPDemo/Blueprints/UMG/Widget/WBP_Countdown.uasset and b/Content/PvPDemo/Blueprints/UMG/Widget/WBP_Countdown.uasset differ diff --git a/Content/PvPDemo/Blueprints/UMG/Widget/Widget_Backpack.uasset b/Content/PvPDemo/Blueprints/UMG/Widget/Widget_Backpack.uasset index d40a36d..2c901eb 100644 Binary files a/Content/PvPDemo/Blueprints/UMG/Widget/Widget_Backpack.uasset and b/Content/PvPDemo/Blueprints/UMG/Widget/Widget_Backpack.uasset differ diff --git a/Content/PvPDemo/Blueprints/UMG/Widget/Widget_Lobby.uasset b/Content/PvPDemo/Blueprints/UMG/Widget/Widget_Lobby.uasset index 07943f4..58f6722 100644 Binary files a/Content/PvPDemo/Blueprints/UMG/Widget/Widget_Lobby.uasset and b/Content/PvPDemo/Blueprints/UMG/Widget/Widget_Lobby.uasset differ diff --git a/Content/PvPDemo/Blueprints/UMG/Widget/Widget_Lobby_DS.uasset b/Content/PvPDemo/Blueprints/UMG/Widget/Widget_Lobby_DS.uasset new file mode 100644 index 0000000..9955dca Binary files /dev/null and b/Content/PvPDemo/Blueprints/UMG/Widget/Widget_Lobby_DS.uasset differ diff --git a/Content/PvPDemo/Blueprints/UMG/Widget/Widget_RoomWidget.uasset b/Content/PvPDemo/Blueprints/UMG/Widget/Widget_RoomWidget.uasset index 049912b..01be3a6 100644 Binary files a/Content/PvPDemo/Blueprints/UMG/Widget/Widget_RoomWidget.uasset and b/Content/PvPDemo/Blueprints/UMG/Widget/Widget_RoomWidget.uasset differ diff --git a/Content/PvPDemo/Blueprints/UMG/Widget/Widget_SetDiffculty.uasset b/Content/PvPDemo/Blueprints/UMG/Widget/Widget_SetDiffculty.uasset new file mode 100644 index 0000000..e903ab6 Binary files /dev/null and b/Content/PvPDemo/Blueprints/UMG/Widget/Widget_SetDiffculty.uasset differ diff --git a/Content/ThirdPerson/Blueprints/BP_GameInstance.uasset b/Content/ThirdPerson/Blueprints/BP_GameInstance.uasset index 00a7b6e..35b0309 100644 Binary files a/Content/ThirdPerson/Blueprints/BP_GameInstance.uasset and b/Content/ThirdPerson/Blueprints/BP_GameInstance.uasset differ diff --git a/Content/ThirdPerson/Blueprints/BP_GameState.uasset b/Content/ThirdPerson/Blueprints/BP_GameState.uasset index 62b4ead..b7ad521 100644 Binary files a/Content/ThirdPerson/Blueprints/BP_GameState.uasset and b/Content/ThirdPerson/Blueprints/BP_GameState.uasset differ diff --git a/Content/ThirdPerson/Blueprints/BP_LobbyGameMode.uasset b/Content/ThirdPerson/Blueprints/BP_LobbyGameMode.uasset index da2ce40..e0b98ec 100644 Binary files a/Content/ThirdPerson/Blueprints/BP_LobbyGameMode.uasset and b/Content/ThirdPerson/Blueprints/BP_LobbyGameMode.uasset differ diff --git a/Content/ThirdPerson/Blueprints/BP_LobbyGameState.uasset b/Content/ThirdPerson/Blueprints/BP_LobbyGameState.uasset index ad15de1..8de2f0e 100644 Binary files a/Content/ThirdPerson/Blueprints/BP_LobbyGameState.uasset and b/Content/ThirdPerson/Blueprints/BP_LobbyGameState.uasset differ diff --git a/Content/ThirdPerson/Blueprints/BP_PlayerState.uasset b/Content/ThirdPerson/Blueprints/BP_PlayerState.uasset index f744a89..7720ca3 100644 Binary files a/Content/ThirdPerson/Blueprints/BP_PlayerState.uasset and b/Content/ThirdPerson/Blueprints/BP_PlayerState.uasset differ diff --git a/Content/ThirdPerson/Blueprints/BP_ThirdPersonCharacter.uasset b/Content/ThirdPerson/Blueprints/BP_ThirdPersonCharacter.uasset index 62f64dc..fc84adc 100644 Binary files a/Content/ThirdPerson/Blueprints/BP_ThirdPersonCharacter.uasset and b/Content/ThirdPerson/Blueprints/BP_ThirdPersonCharacter.uasset differ diff --git a/Content/ThirdPerson/Blueprints/BP_ThirdPersonGameMode.uasset b/Content/ThirdPerson/Blueprints/BP_ThirdPersonGameMode.uasset index 4ad8d41..333dd45 100644 Binary files a/Content/ThirdPerson/Blueprints/BP_ThirdPersonGameMode.uasset and b/Content/ThirdPerson/Blueprints/BP_ThirdPersonGameMode.uasset differ diff --git a/Content/ThirdPerson/Blueprints/BP_ThirdPersonPlayerController.uasset b/Content/ThirdPerson/Blueprints/BP_ThirdPersonPlayerController.uasset index 767e5df..c92c98e 100644 Binary files a/Content/ThirdPerson/Blueprints/BP_ThirdPersonPlayerController.uasset and b/Content/ThirdPerson/Blueprints/BP_ThirdPersonPlayerController.uasset differ diff --git a/DevLog.md b/DevLog.md new file mode 100644 index 0000000..a337cf6 --- /dev/null +++ b/DevLog.md @@ -0,0 +1,16 @@ +# PVPDemo开发日志 + +### Day1 2026.5.31 +#### 任务安排 +我认为这个对战方式是以道具驱动的,所以打算先开发道具刷新相关的逻辑 +#### 主要开发工作 +1. 市场寻找需要用到的美术资产,比如人物模型、特效、场景等 +2. 设计道具刷新相关的ItemSpawner以及ItemManager类 + + +### Day2 2026.6.1 +#### 任务安排 +我认为这个对战方式是以道具驱动的,所以打算先开发道具刷新相关的逻辑 +#### 主要开发工作 +1. 市场寻找需要用到的美术资产,比如人物模型、特效、场景等 +2. 设计道具刷新相关的ItemSpawner以及ItemManager类 diff --git a/NetTest.txt b/NetTest.txt new file mode 100644 index 0000000..712edde --- /dev/null +++ b/NetTest.txt @@ -0,0 +1,3 @@ +Net PktLag=200 +Net PktLagVariance=50N +et PktLoss=2 \ No newline at end of file diff --git a/Source/PvPDemo/Private/BotCharacter.cpp b/Source/PvPDemo/Private/BotCharacter.cpp index 8710442..1b7f0ae 100644 --- a/Source/PvPDemo/Private/BotCharacter.cpp +++ b/Source/PvPDemo/Private/BotCharacter.cpp @@ -16,10 +16,15 @@ namespace { - FGameplayTag GetDeadTag() + FGameplayTag GetBotDeadTag() { return FGameplayTag::RequestGameplayTag(FName(TEXT("State.Dead"))); } + + FGameplayTag GetBotSlowedTag() + { + return FGameplayTag::RequestGameplayTag(FName(TEXT("State.Slowed"))); + } } // Sets default values @@ -45,6 +50,7 @@ void ABotCharacter::BeginPlay() void ABotCharacter::EndPlay(const EEndPlayReason::Type EndPlayReason) { + UnbindSlowedTagChangedDelegate(); UnbindHealthChangedDelegate(); if (UWorld* World = GetWorld()) { @@ -87,9 +93,12 @@ void ABotCharacter::InitAbilityActorInfo() return; } + UnbindSlowedTagChangedDelegate(); UnbindHealthChangedDelegate(); AbilitySystemComponent->InitAbilityActorInfo(this, this); + CacheDefaultMovementState(); BindHealthChangedDelegate(); + BindSlowedTagChangedDelegate(); if (HasAuthority()) { @@ -123,6 +132,34 @@ void ABotCharacter::UnbindHealthChangedDelegate() HealthChangedHandle.Reset(); } +void ABotCharacter::BindSlowedTagChangedDelegate() +{ + if (!AbilitySystemComponent || SlowedTagChangedHandle.IsValid()) + { + return; + } + + const FGameplayTag SlowedTag = GetBotSlowedTag(); + SlowedTagChangedHandle = AbilitySystemComponent + ->RegisterGameplayTagEvent(SlowedTag, EGameplayTagEventType::NewOrRemoved) + .AddUObject(this, &ThisClass::OnSlowedTagChanged); + + ApplySlowedState(AbilitySystemComponent->GetTagCount(SlowedTag) > 0); +} + +void ABotCharacter::UnbindSlowedTagChangedDelegate() +{ + if (!AbilitySystemComponent || !SlowedTagChangedHandle.IsValid()) + { + return; + } + + AbilitySystemComponent + ->RegisterGameplayTagEvent(GetBotSlowedTag(), EGameplayTagEventType::NewOrRemoved) + .Remove(SlowedTagChangedHandle); + SlowedTagChangedHandle.Reset(); +} + void ABotCharacter::OnHealthChanged(const FOnAttributeChangeData& Data) { if (HasAuthority() && Data.NewValue <= 0.f) @@ -131,6 +168,31 @@ void ABotCharacter::OnHealthChanged(const FOnAttributeChangeData& Data) } } +void ABotCharacter::OnSlowedTagChanged(const FGameplayTag Tag, int32 NewCount) +{ + ApplySlowedState(NewCount > 0); +} + +void ABotCharacter::CacheDefaultMovementState() +{ + if (bHasCachedDefaultMovementState) + { + return; + } + + DefaultMaxWalkSpeed = GetCharacterMovement()->MaxWalkSpeed; + DefaultGlobalAnimRateScale = GetMesh()->GlobalAnimRateScale; + bHasCachedDefaultMovementState = true; +} + +void ABotCharacter::ApplySlowedState(bool bSlowed) +{ + CacheDefaultMovementState(); + + GetMesh()->GlobalAnimRateScale = bSlowed ? 0.5f : DefaultGlobalAnimRateScale; + GetCharacterMovement()->MaxWalkSpeed = bSlowed ? 300.f : DefaultMaxWalkSpeed; +} + void ABotCharacter::GiveDefaultAbilities() { if (bHasGivenDefaultAbilities || !AbilitySystemComponent) @@ -180,7 +242,7 @@ void ABotCharacter::HandleDeath() if (AbilitySystemComponent) { - AbilitySystemComponent->SetLooseGameplayTagCount(GetDeadTag(), 1, EGameplayTagReplicationState::TagOnly); + AbilitySystemComponent->SetLooseGameplayTagCount(GetBotDeadTag(), 1, EGameplayTagReplicationState::TagOnly); } MulticastHandleDeath(); @@ -223,7 +285,7 @@ void ABotCharacter::HandleRespawn() if (AbilitySystemComponent) { - AbilitySystemComponent->SetLooseGameplayTagCount(GetDeadTag(), 0, EGameplayTagReplicationState::TagOnly); + AbilitySystemComponent->SetLooseGameplayTagCount(GetBotDeadTag(), 0, EGameplayTagReplicationState::TagOnly); const float MaxHealth = AbilitySystemComponent->GetNumericAttribute(UMainAttributeSet::GetMaxHealthAttribute()); AbilitySystemComponent->SetNumericAttributeBase(UMainAttributeSet::GetHealthAttribute(), MaxHealth); diff --git a/Source/PvPDemo/Private/MainAttributeSet.cpp b/Source/PvPDemo/Private/MainAttributeSet.cpp index 2f72a48..0810d3f 100644 --- a/Source/PvPDemo/Private/MainAttributeSet.cpp +++ b/Source/PvPDemo/Private/MainAttributeSet.cpp @@ -8,7 +8,7 @@ namespace { - FGameplayTag GetDeadTag() + FGameplayTag GetAttributeSetDeadTag() { return FGameplayTag::RequestGameplayTag(FName(TEXT("State.Dead"))); } @@ -56,7 +56,7 @@ void UMainAttributeSet::PostGameplayEffectExecute(const FGameplayEffectModCallba AActor* OwningActor = ASC->GetOwnerActor(); if (OwningActor && OwningActor->HasAuthority()) { - ASC->SetLooseGameplayTagCount(GetDeadTag(), 1, EGameplayTagReplicationState::TagOnly); + ASC->SetLooseGameplayTagCount(GetAttributeSetDeadTag(), 1, EGameplayTagReplicationState::TagOnly); } } } diff --git a/Source/PvPDemo/Public/BotCharacter.h b/Source/PvPDemo/Public/BotCharacter.h index 737c1a9..9b87060 100644 --- a/Source/PvPDemo/Public/BotCharacter.h +++ b/Source/PvPDemo/Public/BotCharacter.h @@ -12,6 +12,7 @@ class UAbilitySystemComponent; class UAttributeSet; class UGameplayAbility; class UGameplayEffect; +struct FGameplayTag; struct FOnAttributeChangeData; UCLASS() @@ -62,7 +63,12 @@ private: void InitAbilityActorInfo(); void BindHealthChangedDelegate(); void UnbindHealthChangedDelegate(); + void BindSlowedTagChangedDelegate(); + void UnbindSlowedTagChangedDelegate(); void OnHealthChanged(const FOnAttributeChangeData& Data); + void OnSlowedTagChanged(const FGameplayTag Tag, int32 NewCount); + void CacheDefaultMovementState(); + void ApplySlowedState(bool bSlowed); void GiveDefaultAbilities(); void ApplyDefaultAttributeEffect(); void HandleDeath(); @@ -79,5 +85,9 @@ private: bool bHasHandledDeath = false; bool bHasNotifiedDeath = false; FDelegateHandle HealthChangedHandle; + FDelegateHandle SlowedTagChangedHandle; + float DefaultMaxWalkSpeed = 0.f; + float DefaultGlobalAnimRateScale = 1.f; + bool bHasCachedDefaultMovementState = false; FTimerHandle RespawnTimer; }; diff --git a/Source/PvPDemo/PvPDemoCharacter.cpp b/Source/PvPDemo/PvPDemoCharacter.cpp index 3ab7fa7..19704a6 100644 --- a/Source/PvPDemo/PvPDemoCharacter.cpp +++ b/Source/PvPDemo/PvPDemoCharacter.cpp @@ -22,10 +22,15 @@ namespace { - FGameplayTag GetDeadTag() + FGameplayTag GetPvPDemoCharacterDeadTag() { return FGameplayTag::RequestGameplayTag(FName(TEXT("State.Dead"))); } + + FGameplayTag GetPvPDemoCharacterSlowedTag() + { + return FGameplayTag::RequestGameplayTag(FName(TEXT("State.Slowed"))); + } } @@ -85,6 +90,7 @@ void APvPDemoCharacter::OnRep_PlayerState() void APvPDemoCharacter::EndPlay(const EEndPlayReason::Type EndPlayReason) { + UnbindSlowedTagChangedDelegate(); UnbindHealthChangedDelegate(); Super::EndPlay(EndPlayReason); @@ -188,18 +194,54 @@ UAbilitySystemComponent* APvPDemoCharacter::GetAbilitySystemComponent() const return AbilitySystemComponent; } +bool APvPDemoCharacter::AddHealth(float Amount) +{ + if (Amount <= 0.f) + { + UE_LOG(LogPvPDemo, Warning, TEXT("AddHealth failed: Amount must be greater than 0.")); + return false; + } + + if (!HasAuthority()) + { + ServerAddHealth(Amount); + return true; + } + + if (!AbilitySystemComponent) + { + UE_LOG(LogPvPDemo, Warning, TEXT("AddHealth failed: AbilitySystemComponent is null.")); + return false; + } + + const float CurrentHealth = AbilitySystemComponent->GetNumericAttribute(UMainAttributeSet::GetHealthAttribute()); + const float MaxHealth = AbilitySystemComponent->GetNumericAttribute(UMainAttributeSet::GetMaxHealthAttribute()); + const float NewHealth = FMath::Clamp(CurrentHealth + Amount, 0.f, MaxHealth); + + AbilitySystemComponent->SetNumericAttributeBase(UMainAttributeSet::GetHealthAttribute(), NewHealth); + return true; +} + +void APvPDemoCharacter::ServerAddHealth_Implementation(float Amount) +{ + AddHealth(Amount); +} + void APvPDemoCharacter::InitAbilityActorInfo() { AMainPlayerState* MainPlayerState = GetPlayerState(); check(MainPlayerState); + UnbindSlowedTagChangedDelegate(); UnbindHealthChangedDelegate(); // 设置ASC的所有者,OwnerActor是所有者,AvatarActor是游戏中的形象 MainPlayerState->GetAbilitySystemComponent()->InitAbilityActorInfo(MainPlayerState, this); AbilitySystemComponent = MainPlayerState->GetAbilitySystemComponent(); AttributeSet = MainPlayerState->GetAttributeSet(); + CacheDefaultMovementState(); BindHealthChangedDelegate(); + BindSlowedTagChangedDelegate(); if (HasAuthority() && AbilitySystemComponent && HeldItem) { @@ -234,6 +276,34 @@ void APvPDemoCharacter::UnbindHealthChangedDelegate() HealthChangedHandle.Reset(); } +void APvPDemoCharacter::BindSlowedTagChangedDelegate() +{ + if (!AbilitySystemComponent || SlowedTagChangedHandle.IsValid()) + { + return; + } + + const FGameplayTag SlowedTag = GetPvPDemoCharacterSlowedTag(); + SlowedTagChangedHandle = AbilitySystemComponent + ->RegisterGameplayTagEvent(SlowedTag, EGameplayTagEventType::NewOrRemoved) + .AddUObject(this, &ThisClass::OnSlowedTagChanged); + + ApplySlowedState(AbilitySystemComponent->GetTagCount(SlowedTag) > 0); +} + +void APvPDemoCharacter::UnbindSlowedTagChangedDelegate() +{ + if (!AbilitySystemComponent || !SlowedTagChangedHandle.IsValid()) + { + return; + } + + AbilitySystemComponent + ->RegisterGameplayTagEvent(GetPvPDemoCharacterSlowedTag(), EGameplayTagEventType::NewOrRemoved) + .Remove(SlowedTagChangedHandle); + SlowedTagChangedHandle.Reset(); +} + void APvPDemoCharacter::OnHealthChanged(const FOnAttributeChangeData& Data) { if (HasAuthority() && Data.NewValue <= 0.f) @@ -242,6 +312,31 @@ void APvPDemoCharacter::OnHealthChanged(const FOnAttributeChangeData& Data) } } +void APvPDemoCharacter::OnSlowedTagChanged(const FGameplayTag Tag, int32 NewCount) +{ + ApplySlowedState(NewCount > 0); +} + +void APvPDemoCharacter::CacheDefaultMovementState() +{ + if (bHasCachedDefaultMovementState) + { + return; + } + + DefaultMaxWalkSpeed = GetCharacterMovement()->MaxWalkSpeed; + DefaultGlobalAnimRateScale = GetMesh()->GlobalAnimRateScale; + bHasCachedDefaultMovementState = true; +} + +void APvPDemoCharacter::ApplySlowedState(bool bSlowed) +{ + CacheDefaultMovementState(); + + GetMesh()->GlobalAnimRateScale = bSlowed ? 0.5f : DefaultGlobalAnimRateScale; + GetCharacterMovement()->MaxWalkSpeed = bSlowed ? 300.f : DefaultMaxWalkSpeed; +} + void APvPDemoCharacter::HandleDeath() { if (bHasHandledDeath) @@ -253,7 +348,7 @@ void APvPDemoCharacter::HandleDeath() if (AbilitySystemComponent) { - AbilitySystemComponent->SetLooseGameplayTagCount(GetDeadTag(), 1, EGameplayTagReplicationState::TagOnly); + AbilitySystemComponent->SetLooseGameplayTagCount(GetPvPDemoCharacterDeadTag(), 1, EGameplayTagReplicationState::TagOnly); } if (UWorld* World = GetWorld()) @@ -333,5 +428,3 @@ bool APvPDemoCharacter::RemoveHeldItemTag(FGameplayTag Tag) ASC->RemoveLooseGameplayTag(Tag); return true; } - - diff --git a/Source/PvPDemo/PvPDemoCharacter.h b/Source/PvPDemo/PvPDemoCharacter.h index 1d5f208..90c7589 100644 --- a/Source/PvPDemo/PvPDemoCharacter.h +++ b/Source/PvPDemo/PvPDemoCharacter.h @@ -15,6 +15,7 @@ class UAbilitySystemComponent; class UAttributeSet; struct FInputActionValue; struct FOnAttributeChangeData; +struct FGameplayTag; class UGameplayAbility; DECLARE_LOG_CATEGORY_EXTERN(LogTemplateCharacter, Log, All); @@ -57,6 +58,9 @@ protected: UPROPERTY(EditAnywhere, Category="Input") UInputAction* AttackAction; + UPROPERTY(EditAnywhere, Category="Input") + UInputAction* SprintAction; + // ASC UPROPERTY(VisibleAnywhere, BlueprintReadOnly) TObjectPtr AbilitySystemComponent; @@ -72,6 +76,9 @@ public: UFUNCTION(BlueprintCallable) virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override; + + UFUNCTION(BlueprintCallable, Category="GAS|Health") + bool AddHealth(float Amount); virtual void PossessedBy(AController* NewController) override; virtual void OnRep_PlayerState() override; @@ -135,9 +142,17 @@ private: void InitAbilityActorInfo(); void BindHealthChangedDelegate(); void UnbindHealthChangedDelegate(); + void BindSlowedTagChangedDelegate(); + void UnbindSlowedTagChangedDelegate(); void OnHealthChanged(const FOnAttributeChangeData& Data); + void OnSlowedTagChanged(const FGameplayTag Tag, int32 NewCount); + void CacheDefaultMovementState(); + void ApplySlowedState(bool bSlowed); void HandleDeath(); + UFUNCTION(Server, Reliable) + void ServerAddHealth(float Amount); + UFUNCTION(NetMulticast, Reliable) void MulticastHandleDeath(); @@ -151,6 +166,10 @@ private: bool RemoveHeldItemTag(FGameplayTag Tag); FDelegateHandle HealthChangedHandle; + FDelegateHandle SlowedTagChangedHandle; + float DefaultMaxWalkSpeed = 0.f; + float DefaultGlobalAnimRateScale = 1.f; + bool bHasCachedDefaultMovementState = false; bool bHasHandledDeath = false; bool bHasNotifiedDeath = false; }; diff --git a/Source/PvPDemo/PvPDemoGameMode.cpp b/Source/PvPDemo/PvPDemoGameMode.cpp index ddbbe4a..eb600fd 100644 --- a/Source/PvPDemo/PvPDemoGameMode.cpp +++ b/Source/PvPDemo/PvPDemoGameMode.cpp @@ -12,7 +12,7 @@ namespace { - FGameplayTag GetDeadTag() + FGameplayTag GetGameModeDeadTag() { return FGameplayTag::RequestGameplayTag(FName(TEXT("State.Dead"))); } @@ -86,7 +86,7 @@ void APvPDemoGameMode::ResetRespawnAttributes(AController* Controller) const return; } - ASC->SetLooseGameplayTagCount(GetDeadTag(), 0, EGameplayTagReplicationState::TagOnly); + ASC->SetLooseGameplayTagCount(GetGameModeDeadTag(), 0, EGameplayTagReplicationState::TagOnly); const float MaxHealth = ASC->GetNumericAttribute(UMainAttributeSet::GetMaxHealthAttribute()); ASC->SetNumericAttributeBase(UMainAttributeSet::GetHealthAttribute(), MaxHealth); diff --git a/Source/PvPDemo/PvPDemoPlayerController.cpp b/Source/PvPDemo/PvPDemoPlayerController.cpp index 884a315..51b98f1 100644 --- a/Source/PvPDemo/PvPDemoPlayerController.cpp +++ b/Source/PvPDemo/PvPDemoPlayerController.cpp @@ -76,7 +76,8 @@ void APvPDemoPlayerController::SetupInputComponent() bool APvPDemoPlayerController::ShouldUseTouchControls() const { // are we on a mobile platform? Should we force touch? - return SVirtualJoystick::ShouldDisplayTouchInterface() || bForceTouchControls; + // return SVirtualJoystick::ShouldDisplayTouchInterface() || bForceTouchControls; + return false; } UAbilitySystemComponent* APvPDemoPlayerController::GetMainWidgetAbilitySystemComponent() const