From 8c0623b397a9f8eb99a24264f2a201f486dd816e Mon Sep 17 00:00:00 2001 From: wyatt Date: Sun, 26 Oct 2025 15:46:04 +0800 Subject: [PATCH] =?UTF-8?q?Lua=E5=90=91C#=E9=80=BB=E8=BE=91=E8=BF=81?= =?UTF-8?q?=E7=A7=BB=20=E4=B8=80=E6=9C=9F=20#13?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 狐狸移动,技能迁移和完善 --- Config/DefaultGameplayTags.ini | 11 + .../Blueprint/Level/Actor/Role/BP_Fox.uasset | Bin 31604 -> 48723 bytes .../BP_BusyLevelPlayerController.uasset | Bin 22353 -> 22759 bytes .../Data/Ability/FoxUltimateDataAsset.uasset | Bin 2328 -> 3196 bytes Content/Data/Level/LevelRoleBaseConfig.uasset | Bin 2962 -> 2902 bytes .../Ability/Role/Common/GA_MoveAbility.uasset | Bin 0 -> 16917 bytes .../Ability/Role/Fox/GA_FoxUltimate.uasset | Bin 22438 -> 20618 bytes .../Effects/Role/Fox/GE_UltimateRecast.uasset | Bin 7622 -> 7544 bytes Script/BusyRabbit-CSharp.code-workspace | 44 ++ Script/BusyRabbit.Glue/AssetTypes.cs | 7 + .../Ability/Common/MoveAbility.cs | 27 +- .../Ability/Role/Fox/FoxUltimate.cs | 469 ++++++++++++------ .../Level/Role/BusyFoxRole.cs | 118 +++-- .../ManagedBusyRabbit.csproj | 4 +- .../BlueprintLibrary/BusyAscLibrary.cpp | 10 + .../Private/Gas/BusyGameAbility.cpp | 28 +- .../Gas/BusyGameplayEffectSubSystem.cpp | 38 ++ .../Private/Level/Actor/BusyPawnBase.cpp | 3 - .../Actor/Components/BusyPawnMovement.cpp | 4 +- .../Private/Level/LevelPlayerController.cpp | 36 +- .../Public/BlueprintLibrary/BusyAscLibrary.h | 5 + .../Data/Ability/Role/FoxAbilityDataAsset.h | 41 +- .../BusyRabbit/Public/Gas/BusyGameAbility.h | 6 +- .../Public/Gas/BusyGameplayEffectSubSystem.h | 21 + .../Public/Level/Actor/BusyPawnBase.h | 10 +- .../Public/Level/Actor/BusyPlayerRole.h | 4 +- .../Level/Actor/Components/BusyPawnMovement.h | 8 + .../Public/Level/LevelPlayerController.h | 34 -- 28 files changed, 605 insertions(+), 323 deletions(-) create mode 100644 Content/Gas/Ability/Role/Common/GA_MoveAbility.uasset create mode 100644 Script/BusyRabbit-CSharp.code-workspace create mode 100644 Script/BusyRabbit.Glue/AssetTypes.cs create mode 100644 Source/BusyRabbit/Private/Gas/BusyGameplayEffectSubSystem.cpp create mode 100644 Source/BusyRabbit/Public/Gas/BusyGameplayEffectSubSystem.h diff --git a/Config/DefaultGameplayTags.ini b/Config/DefaultGameplayTags.ini index 4444572..a77ea33 100644 --- a/Config/DefaultGameplayTags.ini +++ b/Config/DefaultGameplayTags.ini @@ -5,13 +5,24 @@ ClearInvalidTags=False AllowEditorTagUnloading=True AllowGameTagUnloading=False FastReplication=False +bDynamicReplication=False InvalidTagCharacters="\"\'," NumBitsForContainerSize=6 NetIndexFirstBitSegment=16 +GameplayTagList=(Tag="Ability.Block.UltimatePlaying",DevComment="大招正在释放中") ++GameplayTagList=(Tag="Ability.Common",DevComment="通用技能") ++GameplayTagList=(Tag="Ability.Common.Move",DevComment="移动技能") +GameplayTagList=(Tag="Ability.Flags.Cooldown",DevComment="技能冷却") +GameplayTagList=(Tag="Ability.Flags.Recast",DevComment="可以再次释放技能的标记") +GameplayTagList=(Tag="Ability.Fox",DevComment="狐狸技能标签") ++GameplayTagList=(Tag="Ability.Fox.CastTag",DevComment="可以释放技能的标签") ++GameplayTagList=(Tag="Ability.Fox.CastTag.Ultimate1",DevComment="可以使用大招第一阶段") ++GameplayTagList=(Tag="Ability.Fox.CastTag.Ultimate2",DevComment="可以使用二阶大招") ++GameplayTagList=(Tag="Ability.Fox.CastTag.Ultimate3",DevComment="可以使用第三阶段大招") ++GameplayTagList=(Tag="Ability.Fox.StateTag",DevComment="状态标签") ++GameplayTagList=(Tag="Ability.Fox.StateTag.Ultimate1",DevComment="正在使用第一阶段大招") ++GameplayTagList=(Tag="Ability.Fox.StateTag.Ultimate2",DevComment="正在使用第二阶段大招") ++GameplayTagList=(Tag="Ability.Fox.StateTag.Ultimate3",DevComment="正在使用第三阶段大招") +GameplayTagList=(Tag="Ability.Fox.UltimateStage1",DevComment="一阶大招") +GameplayTagList=(Tag="Ability.Fox.UltimateStage2",DevComment="二阶大招就绪标签") +GameplayTagList=(Tag="Ability.Fox.UltimateStage3",DevComment="三阶大招就绪") diff --git a/Content/Blueprint/Level/Actor/Role/BP_Fox.uasset b/Content/Blueprint/Level/Actor/Role/BP_Fox.uasset index 80d15ee2221ea47a0daca433e3fbcad238033afe..e267e6d54935b8963af7515b4a51bf1653a48464 100644 GIT binary patch literal 48723 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 literal 31604 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 delta 5390 zcmc&&Yiv|S6rQ^+g)S}Kw!3|>+uiMhw)C+;X{k^UT4;fmJ{D+;pvVGCTPY7qc@&|` zOHA~KHYf3yk{C1?Py|;nhD0TbCZa|HXu=OsKu|;!0eMB%bLP%0x9o1a5RHf2ow?`x z=A1KU&di;1VZU;0uab0lYu=8VKA&$v1Y>#~W7n`{tjCczd=R$VQ_>b}t6%)q_s5fV zfBX5x*zKs>d~##kp7Q$hmz>qRa}U1%;o6?f^~&g;V>wZ=h<24jjjke|u}DVb5;RE` z$3v}B;5iV-7?F0F7)!_2V_>Y=%$S1xo!IWd=R153-CRH7z?TKp&kutymd&s5UO#;D z$Jw>u%r>wdJe9O;otSrf&>27zsR=EpH9K{?*FU2>N zgsDLZsN_E$kblK#Z5I71(Ncqp#$}mke?ne|==aB4ADZW3T7%DoCi;2j z(D8;acxREfv0t8tF(P*NOJwW}@}3Hlw=_&%JNoC+R|?7T(_!+qgvr|`c%J?o&kka+ zP3THRdl3Wd41@Oz@>ciesq??z;Lk{0)0@cO?&n=V-r7ERT>?9gymdi%3KRL41x3ZR zA_!4dzg#Y&(8ebTmO(9VkxC2B(-If=MHCn{?l5^v!r*cLEnyIe(i$d@&SH}OGJ{!F z=ieVu9#Z}BB2~Y=9LuqCXI#Q1e%8;MBYN1#HQp*zKO(WnPrS#wf%jgK1r&^BD7y5w51Z^Y#5T3Rwy*r zH3mtwN*JQA)&bE^naW4)uw-T5Pk&NF-!J-Ksq`Uf#YuE-lU1_TB&N|lja%y$FeQ!P zB_j1FYB+ouVLHs^=pGU8xCRc-w`OJE)`X5swuydF$YPYRcGQV!%m#n?(}yZ+;n?IzY z!pTfC!^kt9Yb^8@!g?W(8Hx#v~-7(!WWLp9Itg;#z_QQ4$8cdK42uR!F)nc2C5DD z^Ymg;z40i>-Uz|cu!EBaAaQ6Aa=Fk^!}lZwC=VL3s2QwGu(WREg^&`G1taT{ttY8V zWj9RFwUkB}Rhw+3nE3>pK`1VySW*SxZ)S>~1Dw;0X)?5aTu>zcnF}bG9&LI^>$Btp zMvG|$6ag&&-JnV2o>kxQmnwuro7oad8{D35$d|S`g?1-NfCI8o1try4gY?_jEiBei z;HpmSbrs^LT^%1D!~hQQJrWB14Z%sFz&{X72@XzS47agQevtyA{vE-3F*H;enqX3M zvUMx5r~sk_U7M^TXs@w&9ur8pXsO|4N!x@(X0lX$4NT%?3`dfl2t}elI2wY03H&G^ zlpd0JxZ+GvZv(SbO`yxW=(19P+6-t@#S4cjh~`ctJ}YbkDybNiB%0*t7?o1NL^&^x zKX^FsN^OecLHu&J7Pwn$$mr!dp9jz@MD{42G#1YUfoP}Bb4q`>j~8IT;?59&bV7d~ zliZ&hL$<2tUs>u>LUV+U3Jc2WVrC}`1vPxOxk5o#8j=9BdQ~3?R0yC6cFb%wO%`vO zl@S^GwBDdp!O8kEWg5gcq(-L;W)-|TrcDOVf*%TFnrP{@MduXdrF3ifIv KR>7NdCjJ9svYrY6 diff --git a/Content/Data/Ability/FoxUltimateDataAsset.uasset b/Content/Data/Ability/FoxUltimateDataAsset.uasset index 1dabde171ad7a6963bec0a9ec717243d06029bc2..820e37dbb58d5e86e55faf11b7cd75a3599267af 100644 GIT binary patch literal 3196 zcmb_fU2GIp6h5@2LTmkj))uKqMXcDcyWMWLEeh^m7pqMvY%3`Q%XFFGz_z>D9k7cr zsg#V2wYT`>nOwcsOKxiK%CTa+Y5P1+^On@3vN)_sQzL~l0Ox?Pg`Xw`W z?)lC=_uPBWId}I=?^8p!Q>oP6Y@)m@qTjg%ddfbnc=632nhQ%#weS3DRo+Cwz_rn3 zL`#^v{_@B#zxv*v%)eB5(mNWoJ;^dW_N`KqH34UBpvL8_arlH3=qi)Et!8q4vF@w4mXtD7&_|EM1vcb*<Q^B@hC+hUjSk>dHDyH}TqH}7)_oA@XT8ckdg z_wAu@T#2dL9>yY4vPIgTpxdqIJJ&F2Y^RO4)8>~FDw8&`uaz{>dvhw2mXqAWrEQtC zs_6AEl3U=OdB%{+$7h}L=*5y-8P%M$`?slG8P%%j+VvBg^X4XP2vF%eE$?E33^$rM zu;}B8A6MgSf=WE0vQPVEV=HLyhiz{ZTbO{<$$U@>tI;@(ANa`jkcAG#WO<*#W*xlP zd!L2nrP8sL4aJ%?5|z~Ecr+%*)g;~dl?;4|FDWV*aR3+MlL5Y|YmT85W>|e=B zAvqlF+GknXg{Ja7C05F^xRM)vg*YVBP_x&4FUgnhx6<%?dQIPqCRXEz!gB}VpbzeH zA`z=-vGGiI?g*CGB6rUzo!g|I{x5YYe`fm-7AI2CcPNqEA$4>pD&6qBHBo4y{L#4F zx~=1Y99C(%VdEAQA%8?lBuIUwdjR=t3X!?WH-7xqRk&^JF(tP47r|{k_e0tm>4l$y;bh&Y6th~sezUL zWjRJs5w&F2Q=2*QF!OxCL7XN4k22P7C;^Y@4gJZBTW5SDBLsxr<3hmgTH`yDo*0r& zZ@odz@Vp2pz^upOlrGiZ!nb_xzHMBJsND-;2@`mL`L=Ya{yuKlLJ#_PSsBqI#_}Dk zL8#%51CXZxbms$O7mT?Di7)wv`pj6-KU&ao$he;7aw2WqXv;t~Y~sRkSk_a*&wY_o zro^#nY`I`EST5IYdvS8w4&cfFkU;{*cJ(~F%8;ZX$%EPqq#->XoH&q%TWEd1}zy~TdfYTMw&QfTL*hWbP7H?TZrm*~g zZuoz&EMi?)MgRee_gQ3*u#Bq{SiEJCkHRu;2Vn7*MTQH@oTeK7cGUQN0*I=FUv~oS z;)B-l*X~T^d5>1aGhQp!8%a2bsm}2Kh{37h9^2FBzDJ;lZ2$)xzEZnA=bNuLIP|Wj F{}+`~Z}k8G literal 2328 zcmb_eU2GIp6h6=`AQkzuLIRi&BNZ#V+hw=gA`*9Ycd%GX|A{pQXO|mX*>*QOx7gK} z28^jc2@oJnj5ekLB5!>lA;t#+K_2iyO?@MSQ~MWNF^uap{K{6T)2v7wY6RGP;I+N3&Rv! zLf)WdC)yL7S}?brU$RiQJ39{HD6c=U#MY@_=Cc5zmb2oP%T~>EUq>>R%1VpBY}&|o z8v9N9yX%|Yb!>E~^fHxR#bt*y_KN_0-u(L)^SW%MHEk!qU0RIN6r=S=I*&eD)U!5R$i!P1rJq8_$>Lf+SuU8DMW?i#kN-KwUkz|qcrT5QHdX}*X@mh14tjNhc z9r|O*F0K=`Wcmajqpz23;7O~IJizHUXOc!b^^PG^nLfN^W{sqvRWd&WN;*U`)3>i= zjsA}hg}`5j%=IVb%qo8R^e!0XG_2ihA6PVoR64~#(dqIwdH%l~(yHmU5o}e}M(a28 z?M5PzlJx6~AN}^Y%M{JzMAz=bTOuiGs%gs(u0BQ6hG~*~d*B#$NL)5$?Kd|s|p-z z7FIelv=A`Od4ga7G$@q%-DN+p4b0^SeigtLP|i=SQO?hfHg~)=juCvL;($9Is|&W) z{#ARe;%SdnDf{Mh`?zJeIBrxL%k9_gINd8*?+M2Vmz?Ivqppj`9p4=f@_g&L_XuCa zxx+7D9hEQSQo#1WUU;Bk7gM{PuT5ay2v%=9_h_+K=RBrXAY5%NeEA#{cB@8tu6o_o z&|b@0qby}2*I1vV5RwH@Y5;2i*nm1JiYm*%Kbs+-s{vP;Y*~3L@*PJ0hsdf_Dzfvf zzdr@s;{bneEj;Fo81~M{PqFk`xexj44|g5SzR6UA)>5-3tN}mx%mEwuDVG6V7=u diff --git a/Content/Data/Level/LevelRoleBaseConfig.uasset b/Content/Data/Level/LevelRoleBaseConfig.uasset index 8c0ee63e1d48ec3c80d4659b1dace13f966d9521..dc4eb13047e446bd858eb68ebb726448cd5f86a2 100644 GIT binary patch delta 623 zcmbOveoaj8V6)b|@Bjb*Phe(X;9_E6_z9#z!2R>B=VIGlHXok#!hLpkdXVWR+pR?$ z6UFo<_c3b11FHSWCe*bFf_6wXcnLt zjNb_q2jQ7OtfTguqfnmLuRrAN)s4|doI$38%mP`(%D~3J$nYg|DHF(cZS7E3Q|+MC zoYchPR9#a&GmyL=P~yGABpeEWl3*}7jPDhQaU5u&5;sH)Mgjxke-Q@*gCtNuZF4cB z2NR?2sf2Ery?`B>kDF{@LDi`m}5Vdr} zuF0`1GO9oW83GcMvlG)(8H(LIM0tVy;N+srf|B5pqSE9N25-@pj>($brh+m+84!?# zPz=8(v5JeL3;qH+QepBP7HLMg$qKCMoN`dbKPKN`k!Mt%T)?UhBwv8Zk8Hw|SF?)n zDnr$PC>fC6$^2{_j6Ww!uvs$|aZGMxmz!M7W+SEqRR#){IiQdSf;NcsV>X@19qhuB y*jXpfX4hiv1%_VI=_{oUUDe zoP~h_q(GmIfq@e&%D_<14w7eJ=mydtJR68VH+|WpH~)iwOT^CO=8fONb<}=y6w34Z z^@qH@x-t5QGssYoIjTU+%D@7Is<-5rgn&G4?NC=!?V!}0)WqUcT~j?1usj1pxXBMj zAvdfFfP!E!IgIZWh;b6=fH-c57>oq^@P7dZ1A`<`AZc?qqX*Mu4wgkMB0%oMLJ?b4 z?>ex5d{avjT@p(Y8J;w3nG96U5RjOhotU1=Q0(3zDuCd_)y>sek~;Z4i>RnHP!a@W zAQZ!IpoQ|2=dnuj%0fkc0!0)-B8;+=C$Xx-#X+Gj2Ue*BRSBY`z$%p{C$bAqUdk%M zi!8?omE&Sl=Tw2}`8BzV%^DbIKn)U;@3T3HDL^Ga0Wkv@u^`X_k@jadGW`d%6(R^B zm7yGvN+&2=1}P9hF~$fqTzqmYy9^^I*qQ=%PM}q6ljpLlvGxN4J!SF<_IXS@88_!} g%wO09j^=7ytkO diff --git a/Content/Gas/Ability/Role/Common/GA_MoveAbility.uasset b/Content/Gas/Ability/Role/Common/GA_MoveAbility.uasset new file mode 100644 index 0000000000000000000000000000000000000000..8545260d42f79f2a04a4e67d95bb2c5d4dc65246 GIT binary patch literal 16917 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 WG_`87+~oJNhO+5vXppC(>;DIu$QcFz delta 2251 zcmbVNU2IfU5T3hq>D_jB%i{jr{b>snwrgG1cH0!&Qt8h^31JZ=XzGKwAsb5Yr4gBZO)1oxktS znVBvg;(QV&#zwzrI8`d0)oj!B! zlYJj_gqq25ci_bBJ3Ze_R^Dhj+Wq~iM2u|dz?iMsLjtU(=Qj<2{=tSet+9VDNh6g2 zRm2xM0D^AQ+eEyLo-947yTfPaUOcw;ho2u`-LYIdd-K}f10&Iqb^EstjMjD@Uck{f z4o9~`8T~D}QG;J;K4**20p4zz((r4|+uTABlh%**TxRJCEihIsjgnE>g>(R*mGu4i zr*<+wZVPJp={Y;J{9gNY4L>d4=%Hlct?ZWEM?=XJY-)Vpk^iy0Qq#P6%kMQd_d@i_ z>3YVbv$;$vlgq&E-KP*I^jc#cS=VQ_Y|m`X&NvUmzs=&b-nUDoLOp?%!`TmWeM6bS z0nstCKpVe^9#M*&rU>P=bnZ zT)#D-%DM>n6t2vSS2Dp>(s!RK?ka)%o9xmIK^Cktcv+T|#&gcz#JJR^>66En&${LJ zJn$Q&> zrG#@+A4z#4jOU#-*yYl3lWVayh3~lQY(GV?$rZwzP92Z9Q#j}-b8+;06py)`5~xK_ zRZL4`d(|>~KOGI7`QfUa`g}f~CPrsx0~#=57_Hm_{-H80F`0Oa-QaZiNMtHEnV78@ zrVV3FR9dW_qy_boMOM?orbGPVY`rWHCD9WO;3dQ7h?@qo95?E4Fl6WR>j_#aHL=T5 zmXovlyc)4uDlL-Won&&EZ1!CtMQgGPu|E{S!@+sgDu@7C6>b%E-?voX1OJdr$EzT@ zy+wGDRwH*gN$3Jk3R6)!3xt{4AUVh5bmEJwtHXThHYDek`mj12NYEzFkXXepRdHjH zY>gb^PeSjKRex2&tnLK4BdzL^DbeK%T`DWZ>r@y_hXNQ2JKdkNg$Ir)iNBEfOxWkK zn+9>yJ>hv%c~r<6i7c0#TN0BpGf^cQ`O@Ueh{;+;n5&F4Lbs`)0%TRVgX(z&e|L0+ toC3plFhFkTkIV3ELbxi8v#?nR#ec!QC;k8c diff --git a/Script/BusyRabbit-CSharp.code-workspace b/Script/BusyRabbit-CSharp.code-workspace new file mode 100644 index 0000000..551957e --- /dev/null +++ b/Script/BusyRabbit-CSharp.code-workspace @@ -0,0 +1,44 @@ +{ + "folders": [ + { + "name": "BusyRabbit-CSharp", + "path": "./ManagedBusyRabbit" + }, + { + "name": "ProjectGlue (Generated)", + "path": "./BusyRabbit.Glue" + } + ], + "settings": { + "files.exclude": { + "**/bin": true, + "**/obj": true, + "**/.vs": true, + }, + "search.exclude": { + "**/bin": true, + "**/obj": true + }, + "dotnet.defaultSolution": "Script/${workspaceFolderBasename}.sln", + "omnisharp.enableRoslynAnalyzers": true, + "omnisharp.enableEditorConfigSupport": true, + "csharp.suppressDotnetRestoreNotification": false + }, + "extensions": { + "recommendations": [ + "ms-dotnettools.csharp", + "ms-dotnettools.csdevkit" + ] + }, + "launch": { + "version": "0.2.0", + "configurations": [ + { + "name": "Attach to Unreal Editor", + "type": "coreclr", + "request": "attach", + "processName": "UnrealEditor.exe" + } + ] + } +} \ No newline at end of file diff --git a/Script/BusyRabbit.Glue/AssetTypes.cs b/Script/BusyRabbit.Glue/AssetTypes.cs new file mode 100644 index 0000000..0cba6c2 --- /dev/null +++ b/Script/BusyRabbit.Glue/AssetTypes.cs @@ -0,0 +1,7 @@ +using UnrealSharp.CoreUObject; + +public static class AssetTypes +{ + public static readonly FPrimaryAssetType Map = new("Map"); + public static readonly FPrimaryAssetType PrimaryAssetLabel = new("PrimaryAssetLabel"); +} \ No newline at end of file diff --git a/Script/ManagedBusyRabbit/GameAbilitySystem/Ability/Common/MoveAbility.cs b/Script/ManagedBusyRabbit/GameAbilitySystem/Ability/Common/MoveAbility.cs index 8ca4a50..19387d6 100644 --- a/Script/ManagedBusyRabbit/GameAbilitySystem/Ability/Common/MoveAbility.cs +++ b/Script/ManagedBusyRabbit/GameAbilitySystem/Ability/Common/MoveAbility.cs @@ -1 +1,26 @@ -// 角色移动 \ No newline at end of file +using UnrealSharp.Engine; +using UnrealSharp.Attributes; +using UnrealSharp.BusyRabbit; +using UnrealSharp.GameplayAbilities; +using UnrealSharp.CoreUObject; + +namespace GameAbilitySystem.Ability.Common; +// 角色移动 + +[UClass] +public class UMoveAbility : UBusyGameAbility +{ + protected override void ActivateAbilityFromEvent(FGameplayEventData eventData) + { + base.ActivateAbilityFromEvent(eventData); + if (UGameplayStatics.GetPlayerController(0) is ALevelPlayerController pc) + { + pc.GetCursorPosition(out FVector2D position); + if (eventData.Instigator is ABusyPawnBase pawn) + { + pawn.MovementComponent.MoveTo(position); + } + } + EndAbility(); + } +} \ No newline at end of file diff --git a/Script/ManagedBusyRabbit/GameAbilitySystem/Ability/Role/Fox/FoxUltimate.cs b/Script/ManagedBusyRabbit/GameAbilitySystem/Ability/Role/Fox/FoxUltimate.cs index af9949f..ec8c37c 100644 --- a/Script/ManagedBusyRabbit/GameAbilitySystem/Ability/Role/Fox/FoxUltimate.cs +++ b/Script/ManagedBusyRabbit/GameAbilitySystem/Ability/Role/Fox/FoxUltimate.cs @@ -1,12 +1,314 @@ -// local GameplayStatics = import("GameplayStatics") -// local AbilitySystemBlueprintLibrary = import("AbilitySystemBlueprintLibrary") -// local BusyGameplayLibrary = import("BusyGameplayLibrary") +using Level.Role; +using UnrealSharp; +using UnrealSharp.Attributes; +using UnrealSharp.BusyRabbit; +using UnrealSharp.CoreUObject; +using UnrealSharp.Engine; +using UnrealSharp.GameplayAbilities; +using UnrealSharp.GameplayTags; +using UnrealSharp.SpinePlugin; -// --- @class FoxUltimate -// --- @field RecastWindow number -// local FoxUltimate = {} +namespace GameAbilitySystem.Ability.Role.Fox; +[UClass] +public class UFoxUltimate : UBusyGameAbility +{ + protected bool bIsEventBinded = false; + protected ABusyFoxRole? Owner = null; + protected UFoxUltimateDataAsset? FoxData = null; + protected UBusyAbilitySystemComponent? ASC = null; + protected FActiveGameplayEffectHandle CastStateHandle; + protected FActiveGameplayEffectHandle SkillStateHandle; + + protected FActiveGameplayEffectHandle AccelerateHandle; // 大招移动速度增加的Effect + protected FActiveGameplayEffectHandle SprintHandle; // 大招三阶移速再次增加的Effect + + [UFunction()] + protected void OnGamePlayTagAddOrRemove(FGameplayTag tag, int isAdd) + { + if (isAdd == 0 && !IsActive) + { + CommitAbilityCooldown(); + } + } + + /// + /// 初始化技能依赖的属性 + /// + /// false->初始化失败 + protected bool InitAbilityOnce() + { + Owner = OwningActorFromActorInfo as ABusyFoxRole; + if (Owner == null) return false; + + FoxData = Data as UFoxUltimateDataAsset; + + ASC = AbilitySystemLibrary.GetAbilitySystemComponent(Owner) as UBusyAbilitySystemComponent; + if (FoxData == null || ASC == null) return false; + + PrintString("asdafdasdf"); + + + if (bIsEventBinded) return true; + TDelegate Delegate = new TDelegate(); + Delegate.BindUFunction(this, "OnGamePlayTagAddOrRemove"); + Owner.BindGameplayTagAddOrRemove(FoxData.SecondStageCastTag, Delegate); + Owner.BindGameplayTagAddOrRemove(FoxData.LastStageCastTag, Delegate); + bIsEventBinded = true; + return true; + } + + /// + /// 获取当前大招的阶段 + /// + /// + protected int GetCurrentAbilityStage() + { + if (ASC == null || FoxData == null) return 0; + if (ASC.HasMatchingGameplayTag(FoxData.LastStageCastTag)) + { + return 3; + } + if (ASC.HasMatchingGameplayTag(FoxData.SecondStageCastTag)) + { + return 2; + } + else if (ASC.HasMatchingGameplayTag(FoxData.FirstStageCastTag)) + { + return 1; + } + return 0; + } + + protected override void ActivateAbilityFromEvent(FGameplayEventData eventData) + { + base.ActivateAbilityFromEvent(eventData); + if (!InitAbilityOnce()) + { + EndAbility(); + return; + } + + if (Owner == null || !CommitAbilityCost(Owner)) + { + EndAbility(); + return; + } + + int stage = GetCurrentAbilityStage(); + if (stage != 0) + { + TriggerAbility(stage); + } + else + { + EndAbility(); + return; + } + } + + /// + /// 当被授予技能时,立刻获得可释放第一段大招的常驻Tag + /// + /// + /// + public override void OnGiveAbility(FGameplayAbilityActorInfo actorInfo, FGameplayAbilitySpec spec) + { + base.OnGiveAbility(actorInfo, spec); + InitAbilityOnce(); + + if (FoxData == null || ASC == null) return; + + UBusyGameplayEffectSubSystem EffectSubSystem = GetGameInstanceSubsystem(); + if (EffectSubSystem == null) return; + + + UGameplayEffect effect = EffectSubSystem.GetTagGrantEffectWithDuration( + new FGameplayTagContainer(FoxData.FirstStageCastTag), + new FGameplayTagContainer(), 0 + ); + + FGameplayEffectSpecHandle handle = UBusyAscLibrary.MakeGameplayEffectSpecHandle(ASC, effect, 1); + ASC.ApplyGameplayEffectSpecToSelf(handle); + } + + + protected bool ApplayCastEffect(FGameplayTag CastTag) + { + UBusyGameplayEffectSubSystem EffectSubSystem = GetGameInstanceSubsystem(); + if (ASC == null || EffectSubSystem == null || FoxData == null) return false; + + ASC.RemoveActiveGameplayEffect(CastStateHandle); + + if (CastTag.IsValid) + { + UGameplayEffect cast_effect = EffectSubSystem.GetTagGrantEffectWithDuration( + new FGameplayTagContainer(CastTag), + new FGameplayTagContainer(), FoxData.RecastWindow + ); + FGameplayEffectSpecHandle CastSpecHandle = UBusyAscLibrary.MakeGameplayEffectSpecHandle(ASC, cast_effect, 1); + CastStateHandle = ASC.ApplyGameplayEffectSpecToSelf(CastSpecHandle); + } + return true; + } + protected bool ApplyEffect(FGameplayTag stateTag, FGameplayTag CastTag) + { + UBusyGameplayEffectSubSystem EffectSubSystem = GetGameInstanceSubsystem(); + if (ASC == null || EffectSubSystem == null || FoxData == null) return false; + + ApplayCastEffect(CastTag); + + ASC.RemoveActiveGameplayEffect(SkillStateHandle); + UGameplayEffect state_effect = EffectSubSystem.GetTagGrantEffectWithDuration( + new FGameplayTagContainer(stateTag), + new FGameplayTagContainer(), 0 + ); + FGameplayEffectSpecHandle stateSpecHandle = UBusyAscLibrary.MakeGameplayEffectSpecHandle(ASC, state_effect, 1); + SkillStateHandle = ASC.ApplyGameplayEffectSpecToSelf(stateSpecHandle); + return true; + } + protected bool TriggerAbility(int stage) + { + if (FoxData == null) return false; + if (stage == 1) + { + if (!ApplyEffect(FoxData.FirstStageTag, FoxData.SecondStageCastTag)) return false; + } + else if (stage == 2) + { + if (!ApplyEffect(FoxData.SecondStageTag, new FGameplayTag())) return false; + } + else if(stage == 3) + { + if (!ApplyEffect(FoxData.LastStageTag, new FGameplayTag())) return false; + } + + PlayAnimation(stage); + return true; + } + + + protected string GetAnimationName(FVector2D direction, int stage) + { + string animation_name_prefix = ""; + if (direction.X >= 0) + { + animation_name_prefix = "Ultimate/Right/"; + } + else + { + animation_name_prefix = "Ultimate/Left/"; + } + + if (stage == 1) + { + return animation_name_prefix + "UltimateStage1"; + } + else if (stage == 2) + { + return animation_name_prefix + "UltimateStage2"; + } + else if (stage == 3) + { + return animation_name_prefix + "UltimateStage3"; + } + return ""; + } + + [UFunction()] + protected void OnAnimationComplete(UTrackEntry Entry) + { + Entry.AnimationComplete.Remove(OnAnimationComplete); + if (ASC != null) + { + if (ASC.HasMatchingGameplayTag(FoxData.LastStageTag)) + { + CommitAbilityCooldown(); + } + ASC.RemoveActiveGameplayEffect(SkillStateHandle); + } + EndAbility(); + } + + [UFunction()] + protected void OnTailBeginOverlay(UPrimitiveComponent OverlappedComponent, AActor OtherActor, + UPrimitiveComponent OtherComp, int OtherBodyIndex, bool bFromSweep, FHitResult SweepResult) + { + if (ASC == null || FoxData == null) return; + + bool bIsStage2 = ASC.HasMatchingGameplayTag(FoxData.SecondStageTag); + + if (bIsStage2 && !ASC.HasMatchingGameplayTag(FoxData.LastStageCastTag)) + { + ApplayCastEffect(FoxData.LastStageCastTag); + } + } + + [UFunction()] + protected void OnAnimationEvent(UTrackEntry Entry, FSpineEvent Event) + { + if (ASC == null || FoxData == null || Owner == null) return; + if (Event.Name == "OnSpeedChange") + { + AccelerateHandle = MakeAccelerate(FoxData.LastStageSprintSpeedFactor, 1); + } + else if (Event.Name == "OnSpeedReset") + { + ASC.RemoveActiveGameplayEffect(AccelerateHandle); + } + else if (Event.Name == "OnDamageBegin") + { + Owner.SetTailCollisionEnabled(true); + Owner.FoxTailCollision.OnComponentBeginOverlap.Add(OnTailBeginOverlay); + } + + else if (Event.Name == "OnDamageEnd") + { + Owner.SetTailCollisionEnabled(false); + Owner.FoxTailCollision.OnComponentBeginOverlap.Remove(OnTailBeginOverlay); + } + + } + + protected FActiveGameplayEffectHandle MakeAccelerate(float SpeedFactor, float TotalTime) + { + GetAbilityEffectSpecHandle("Accelerate", ASC, 1, out FGameplayEffectSpecHandle handle); + AbilitySystemLibrary.AssignTagSetByCallerMagnitude( + handle, UBusyGameplayLibrary.RequestGameplayTag("Effect.Factor"), SpeedFactor + ); + AbilitySystemLibrary.AssignTagSetByCallerMagnitude( + handle, UBusyGameplayLibrary.RequestGameplayTag("Effect.Duration"), TotalTime + ); + return ApplyGameplayEffectSpecToOwner(handle); + } + + + protected bool PlayAnimation(int stage) + { + FVector2D AbilityDirection = new FVector2D(0, 1); + if (UGameplayStatics.GetPlayerController(0) is ALevelPlayerController PC) + { + PC.GetCursorDirection(out AbilityDirection); + } + string AnimationName = GetAnimationName(AbilityDirection, stage); + if (AnimationName == "") return false; + + USpineSkeletonAnimationComponent Animation = Owner.SpineAnimationComponent; + UTrackEntry AnimEntry = Animation.SetAnimation(0, AnimationName, false); + AnimEntry.AnimationEvent.Add(OnAnimationEvent); + AnimEntry.AnimationComplete.Add(OnAnimationComplete); + + float TotalTime = AnimEntry.GetAnimationEnd(); + + if (stage == 1) MakeAccelerate(FoxData.FirstStageSpeedFactor, TotalTime); + else if (stage == 2) MakeAccelerate(FoxData.SecondStageSpeedFactor, TotalTime); + else if (stage == 3) MakeAccelerate(FoxData.LastStageNormalSpeedFactor, TotalTime); + Owner.MovementComponent.ActivateSprint(AbilityDirection, TotalTime); + return true; + } +} + // function FoxUltimate:ctor() // self.ultimate_phase = 1 -- 大招阶段 // self.active_recast_handle = nil @@ -17,136 +319,6 @@ // end -// function FoxUltimate:K2_ActivateAbilityFromEvent(EventData) -// print("FoxUltimate:K2_ActivateAbilityFromEvent", self.ultimate_phase) - -// if not self:K2_CommitAbilityCost(false) then -// return self:K2_EndAbility() -// end - -// local owner = self:GetOwningActorFromActorInfo() -// self.movement = owner.MovementComponent -// self.animation = owner.SpineAnimationComponent -// self.asc = AbilitySystemBlueprintLibrary.GetAbilitySystemComponent(owner) -// self.recast_tag = BusyGameplayLibrary.RequestGameplayTag("Ability.Flags.Recast") -// self.owner = owner - - -// local asc = self.asc - -// if self.tag_add_or_remove_delegate == nil then -// self.tag_add_or_remove_delegate = slua.createDelegate(function(tag, is_add) -// if is_add == 0 and not self.bIsActive then -// self.ultimate_phase = 1 -// self:K2_CommitAbilityCooldown(false, false) -// end -// end) -// owner:BindGameplayTagAddOrRemove(self.recast_tag, self.tag_add_or_remove_delegate) -// end - -// if self.ultimate_phase == 1 or asc:HasMatchingGameplayTag(self.recast_tag) then -// self:TriggerUltimate(asc) -// else -// self:K2_EndAbility() -// end - - -// end - -// function FoxUltimate:TriggerUltimate(asc) -// if self.ultimate_phase == 1 then -// -- 第一次释放大招,添加一个可以再次释放的Tag -// local _, recast_effect = self:GetAbilityEffectSpecHandle("Recast", asc, 1, nil) -// self.active_recast_handle = asc:BP_ApplyGameplayEffectSpecToSelf(recast_effect) -// elseif self.ultimate_phase == 2 then -// -- 第二次激活,移除可重复释放的tag -// self.asc:RemoveActiveGameplayEffect(self.active_recast_handle, -1) -// elseif self.ultimate_phase == 3 then -// self.asc:RemoveActiveGameplayEffect(self.active_recast_handle, -1) -// end - -// -- 播放动画,并监听动画完成的事件 -// self:PlayAnimation() -// end - - -// function FoxUltimate:GetAnimationName(direction) -// local animation_name_prefix -// if direction.X >= 0 then -// animation_name_prefix = "Ultimate/Right/" -// else -// animation_name_prefix = "Ultimate/Left/" -// end - -// if self.ultimate_phase == 1 then -// return animation_name_prefix .. "UltimateStage1" -// elseif self.ultimate_phase == 2 then -// return animation_name_prefix .. "UltimateStage2" -// elseif self.ultimate_phase == 3 then -// return animation_name_prefix .. "UltimateStage3" -// end -// return nil -// end - - -// function FoxUltimate:K2_OnEndAbility(bWasCancelled) -// print("FoxUltimate:K2_OnEndAbility") -// end - - -// function FoxUltimate:GetSprintSpeedFactor() -// if self.ultimate_phase == 1 then -// return 2.5 -// elseif self.ultimate_phase == 2 then -// return 2.8 -// elseif self.ultimate_phase == 3 then -// return 3.0 -// end -// end - -// function FoxUltimate:PlayAnimation() - -// local animation = self.animation -// local PC = GameplayStatics.GetPlayerController(self, 0) - -// local result, ability_direction = PC:GetCursorDirection(nil) -- 获取技能的朝向 -// if not result then -// print("FoxUltimate:TriggerPrimaryPhase can't find direction") -// return -// end -// local anim_name = self:GetAnimationName(ability_direction) -- 获取技能动画名称 -// if not anim_name then -// print("FoxUltimate:TriggerPrimaryPhase can't get animation", self.ultimate_phase) -// return -// end - -// local anim_entry = animation:SetAnimation(0, anim_name, false) -// anim_entry.AnimationComplete:Add(function(entry) self:OnAnimationComplete(entry) end) -// anim_entry.AnimationEvent:Add(function(entry, event) self:OnAnimationEvent(entry, event) end) - -// local anim_total_time = anim_entry:GetAnimationEnd() -- 获取技能动画时长 - -// -- 附加加速buff -// self:MakeAccelerate(self:GetSprintSpeedFactor(), anim_total_time) -// self.movement:ActivateSprint(ability_direction, anim_total_time) -// end - - -// function FoxUltimate:MakeAccelerate(speed_factor, total_time) -// local _, accelerate_effect = self:GetAbilityEffectSpecHandle("Accelerate", self.asc, 1, nil) -// AbilitySystemBlueprintLibrary.AssignTagSetByCallerMagnitude( -// accelerate_effect, -// BusyGameplayLibrary.RequestGameplayTag("Effect.Factor"), -// speed_factor -// ) - -// AbilitySystemBlueprintLibrary.AssignTagSetByCallerMagnitude( -// accelerate_effect, -// BusyGameplayLibrary.RequestGameplayTag("Effect.Duration"), -// total_time -// ) -// return self.asc:BP_ApplyGameplayEffectSpecToSelf(accelerate_effect) -// end // function FoxUltimate:OnAnimationComplete(entry) @@ -168,29 +340,4 @@ // self:K2_EndAbility() // end -// function FoxUltimate:OnAnimationEvent(entry, event) -// if event.Name == "OnSpeedChange" then -// self.active_accelerate_handle = self:MakeAccelerate(8.0, 0.5) -// elseif event.Name == "OnSpeedReset" then -// self.asc:RemoveActiveGameplayEffect(self.active_accelerate_handle, -1) -// elseif event.Name == "OnDamageBegin" then -// local collision = self.owner["TailCollision"] -// collision:SetCollisionEnabled(1) -// self.overlap_delegate_handle = collision.OnComponentBeginOverlap:Add(function() -// if not self.asc:HasMatchingGameplayTag(self.recast_tag) then -// local _, recast_effect = self:GetAbilityEffectSpecHandle("Recast", self.asc, 1, nil) -// self.active_recast_handle = self.asc:BP_ApplyGameplayEffectSpecToSelf(recast_effect) -// end -// end) -// elseif event.Name == "OnDamageEnd" then -// self.owner["TailCollision"]:SetCollisionEnabled(0) -// if self.overlap_delegate_handle ~= nil then -// self.owner["TailCollision"].OnComponentBeginOverlap:Remove(self.overlap_delegate_handle) -// self.overlap_delegate_handle = nil -// end -// end -// end - - -// return Class(nil, nil, FoxUltimate) \ No newline at end of file diff --git a/Script/ManagedBusyRabbit/Level/Role/BusyFoxRole.cs b/Script/ManagedBusyRabbit/Level/Role/BusyFoxRole.cs index 5c43850..392a749 100644 --- a/Script/ManagedBusyRabbit/Level/Role/BusyFoxRole.cs +++ b/Script/ManagedBusyRabbit/Level/Role/BusyFoxRole.cs @@ -1,54 +1,82 @@ -// local LevelFoxRole = {} -// local Vector2D = require("Utils.Vector2D") +using UnrealSharp.Engine; +using UnrealSharp.Attributes; +using UnrealSharp.BusyRabbit; +using UnrealSharp.CoreUObject; +using System.Numerics; +using UnrealSharp.SpinePlugin; -// function LevelFoxRole:ctor() +namespace Level.Role; -// end +[UClass] +public class ABusyFoxRole : ABusyPlayerRole +{ + private string lastAnimation = ""; -// function LevelFoxRole:ReceiveBeginPlay() -// self["SpineAnimationComponent"]:SetAnimation(0, "Idle/Front", true) -// self.last_animation = "Idle/Front" + [UProperty(DefaultComponent = true, AttachmentComponent = "SpineRoot")] + protected USpineBoneFollowerComponent SpineBoneFollower { set; get; } // 用于跟踪尾巴的运动 -// self["SpineBoneFollower"].Target = self -// self["SpineBoneFollower"].BoneName = "tail" -// self["SpineBoneFollower"].UseComponentTransform = true -// self["SpineBoneFollower"].UseScale = true - -// self["TailCollision"]:SetCollisionEnabled(0) -// end + [UProperty(DefaultComponent = true, AttachmentComponent = "SpineBoneFollower")] + public UBoxComponent FoxTailCollision { set; get; } // 尾巴碰撞体组件 -// function LevelFoxRole:OnMoveDirectionChanged(InDirection) -// -- 运动组件更新方向响应函数 -// local cur_animation -// if Vector2D.Equals(InDirection, Vector2D.Zero) then -- Idle的情况 -// local forward_direction = self["MovementComponent"]:GetForwardDirection() -// if(forward_direction.Y >= 0) then -// cur_animation = "Idle/Front" -// else -// cur_animation = "Idle/Back" -// end -// else -// if(InDirection.Y >= 0) then -// cur_animation = "Move/Front" -// else -// cur_animation = "Move/Back" -// end -// end -// if cur_animation ~= self.last_animation then -// self["SpineAnimationComponent"]:SetAnimation(0, cur_animation, true) -// self.last_animation = cur_animation -// end + [UFunction(FunctionFlags.BlueprintEvent)] + public void SetTailCollisionEnabled(bool bIsEnable){} + protected override void BeginPlay() + { + base.BeginPlay(); + lastAnimation = "Idle/Front"; + SpineAnimationComponent.SetAnimation(0, lastAnimation, true); + MovementComponent.MoveDirectionChangedDelegate.Add(OnRoleMoveDirectionChanged); -// self["SpineAnimationComponent"]:SetTimeScale(1.0) -// end + SpineBoneFollower.Target = this; + SpineBoneFollower.BoneName = "tail"; + SpineBoneFollower.UseComponentTransform = true; + SpineBoneFollower.UseScale = true; + SetTailCollisionEnabled(false); + } + + protected override void EndPlay(EEndPlayReason endPlayReason) + { + base.EndPlay(endPlayReason); + PrintString("haha1"); + MovementComponent.MoveDirectionChangedDelegate.Remove(OnRoleMoveDirectionChanged); + PrintString("haha2"); + + } + + [UFunction()] + protected void OnRoleMoveDirectionChanged(FVector2D direction) + { + string currAnimation = ""; + + if (direction.Equals(Vector2.Zero)) // Idle的情况 + { + var forwardDirection = MovementComponent.ForwardDirection; + if (forwardDirection.Y > 0) + { + currAnimation = "Idle/Front"; + } + else + { + currAnimation = "Idle/Back"; + } + } + else + { + if (direction.Y >= 0) + { + currAnimation = "Move/Front"; + } + else + currAnimation = "Move/Back"; + } + if (currAnimation != lastAnimation) + { + lastAnimation = currAnimation; + SpineAnimationComponent.SetAnimation(0, currAnimation, true); + } + } + +} -// function LevelFoxRole:OnMove(location) -// -- 控制器移动相应函数 -// self["MovementComponent"]:MoveTo(location) -// end - - - -// return Class(nil, nil, LevelFoxRole) \ No newline at end of file diff --git a/Script/ManagedBusyRabbit/ManagedBusyRabbit.csproj b/Script/ManagedBusyRabbit/ManagedBusyRabbit.csproj index 21447d9..10b91fe 100644 --- a/Script/ManagedBusyRabbit/ManagedBusyRabbit.csproj +++ b/Script/ManagedBusyRabbit/ManagedBusyRabbit.csproj @@ -15,7 +15,9 @@ ..\..\Plugins\UnrealSharp\Binaries\Managed\net9.0\UnrealSharp.Core.dll - + + Analyzer + \ No newline at end of file diff --git a/Source/BusyRabbit/Private/BlueprintLibrary/BusyAscLibrary.cpp b/Source/BusyRabbit/Private/BlueprintLibrary/BusyAscLibrary.cpp index 3360e98..08d155a 100644 --- a/Source/BusyRabbit/Private/BlueprintLibrary/BusyAscLibrary.cpp +++ b/Source/BusyRabbit/Private/BlueprintLibrary/BusyAscLibrary.cpp @@ -1,5 +1,7 @@ #include "BlueprintLibrary/BusyAscLibrary.h" +#include "AbilitySystemComponent.h" +#include "AbilitySystemGlobals.h" #include "GameplayEffectTypes.h" #include "Gas/BusyGameAbility.h" @@ -18,3 +20,11 @@ AActor* UBusyAscLibrary::GetEffectInstigator(const FGameplayEffectSpec& Spec) return Spec.GetEffectContext().GetInstigator(); } + +FGameplayEffectSpecHandle UBusyAscLibrary::MakeGameplayEffectSpecHandle(const UAbilitySystemComponent* Asc, const UGameplayEffect* Effect, const float Level) +{ + const FGameplayEffectContextHandle ContextHandle = Asc->MakeEffectContext(); + FGameplayEffectSpec && Spec = FGameplayEffectSpec(Effect, ContextHandle, Level); + FGameplayEffectSpec* NewSpec = new FGameplayEffectSpec(Effect, ContextHandle, Level); + return FGameplayEffectSpecHandle(NewSpec); +} diff --git a/Source/BusyRabbit/Private/Gas/BusyGameAbility.cpp b/Source/BusyRabbit/Private/Gas/BusyGameAbility.cpp index 699f792..09e784d 100644 --- a/Source/BusyRabbit/Private/Gas/BusyGameAbility.cpp +++ b/Source/BusyRabbit/Private/Gas/BusyGameAbility.cpp @@ -2,12 +2,26 @@ #include "AbilitySystemBlueprintLibrary.h" #include "AbilitySystemComponent.h" -UBusyGameAbility::UBusyGameAbility() +#pragma optimize("", off) +void UBusyGameAbility::OnGiveAbility(const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilitySpec& Spec) { + Super::OnGiveAbility(ActorInfo, Spec); + Data = SoftDataAsset.LoadSynchronous(); + if (Data) + { + Data->TargetAbility = this; + } + K2_OnGiveAbility(*ActorInfo, Spec); } +void UBusyGameAbility::K2_OnGiveAbility_Implementation(const FGameplayAbilityActorInfo& ActorInfo, const FGameplayAbilitySpec& Spec) +{ + +} + + bool UBusyGameAbility::GetAbilityEffectSpecHandle(const FName& EffectName, const UAbilitySystemComponent* Asc, const int32 Level, - FGameplayEffectSpecHandle& Handle) const + FGameplayEffectSpecHandle& Handle) const { // 1. 查找对应的GameplayEffectClass const TSubclassOf *EffectClass = AbilityEffects.Find(EffectName); @@ -25,13 +39,3 @@ bool UBusyGameAbility::GetAbilityEffectSpecHandle(const FName& EffectName, const return Handle.IsValid(); } -void UBusyGameAbility::PostInitProperties() -{ - Super::PostInitProperties(); - if (SoftDataAsset) - { - Data = SoftDataAsset.LoadSynchronous(); - Data->TargetAbility = this; - } -} - diff --git a/Source/BusyRabbit/Private/Gas/BusyGameplayEffectSubSystem.cpp b/Source/BusyRabbit/Private/Gas/BusyGameplayEffectSubSystem.cpp new file mode 100644 index 0000000..a82d478 --- /dev/null +++ b/Source/BusyRabbit/Private/Gas/BusyGameplayEffectSubSystem.cpp @@ -0,0 +1,38 @@ +#include "Gas/BusyGameplayEffectSubSystem.h" + +#include "GameplayEffect.h" +#include "GameplayEffectComponents/TargetTagsGameplayEffectComponent.h" + +UGameplayEffect* UBusyGameplayEffectSubSystem::GetTagGrantEffectWithDuration(const FGameplayTagContainer& TagsAdd, + const FGameplayTagContainer& TagsRemove, const float Duration, const float Period) +{ + UGameplayEffect* Effect = nullptr; + if (EffectsPool.IsEmpty()) + { + Effect = NewObject(this); + Effect->Period = Period; + if (Duration > 0) + { + Effect->DurationPolicy = EGameplayEffectDurationType::HasDuration; + Effect->DurationMagnitude = FGameplayEffectModifierMagnitude(Duration); + } + else + { + Effect->DurationPolicy = EGameplayEffectDurationType::Infinite; + } + } + else + { + Effect = EffectsPool.Pop(); + } + + FInheritedTagContainer Container; + UTargetTagsGameplayEffectComponent& Component = Effect->FindOrAddComponent(); + + Container.Added = TagsAdd; + Container.CombinedTags = TagsAdd; + Container.Removed = TagsRemove; + Component.SetAndApplyTargetTagChanges(Container); + return Effect; +} + diff --git a/Source/BusyRabbit/Private/Level/Actor/BusyPawnBase.cpp b/Source/BusyRabbit/Private/Level/Actor/BusyPawnBase.cpp index aba82c7..f3c6add 100644 --- a/Source/BusyRabbit/Private/Level/Actor/BusyPawnBase.cpp +++ b/Source/BusyRabbit/Private/Level/Actor/BusyPawnBase.cpp @@ -85,8 +85,5 @@ void ABusyPawnBase::BindGameplayTagAddOrRemove(const FGameplayTag& Tag, FGamepla ); } -void ABusyPawnBase::InitCollision() -{ -} diff --git a/Source/BusyRabbit/Private/Level/Actor/Components/BusyPawnMovement.cpp b/Source/BusyRabbit/Private/Level/Actor/Components/BusyPawnMovement.cpp index 2cdcd2d..b4bd5df 100644 --- a/Source/BusyRabbit/Private/Level/Actor/Components/BusyPawnMovement.cpp +++ b/Source/BusyRabbit/Private/Level/Actor/Components/BusyPawnMovement.cpp @@ -84,6 +84,7 @@ void UBusyPawnMovement::TickComponent(float DeltaTime, ELevelTick TickType, } +#pragma optimize("", off) void UBusyPawnMovement::MoveTick(const float DeltaTime) { @@ -121,9 +122,10 @@ void UBusyPawnMovement::MoveTick(const float DeltaTime) } if (!NewDirection.Equals(LastMoveDirection)) { - Movable->Execute_OnMoveDirectionChanged(Owner, NewDirection); + MoveDirectionChangedDelegate.Broadcast(NewDirection); LastMoveDirection = NewDirection; } + } void UBusyPawnMovement::SprintTick(const float DeltaTime) diff --git a/Source/BusyRabbit/Private/Level/LevelPlayerController.cpp b/Source/BusyRabbit/Private/Level/LevelPlayerController.cpp index 3dca737..c19ff9a 100644 --- a/Source/BusyRabbit/Private/Level/LevelPlayerController.cpp +++ b/Source/BusyRabbit/Private/Level/LevelPlayerController.cpp @@ -148,41 +148,6 @@ void ALevelPlayerController::SwitchControlledRole(ABusyPlayerRole* Target) this->Possess(Target); } -void ALevelPlayerController::OnMove(const FInputActionValue& Value) const -{ - AActor* ControlledRole = GetControlledRole(); - if (!ControlledRole) return; - - IBusyControllable *Controllable = Cast(ControlledRole); - if (!Controllable) return; - - if (FVector2D Position; GetCursorPosition(Position)) - { - Controllable->Execute_OnMove(ControlledRole, Position); - } -} - -void ALevelPlayerController::OnPrimarySkill(const FInputActionValue& Value) const -{ - AActor* ControlledRole = GetControlledRole(); - if (!ControlledRole) return; - - if (IBusyControllable *Controllable = Cast(ControlledRole)) - { - Controllable->Execute_OnPrimarySkill(ControlledRole); - } -} - -void ALevelPlayerController::OnUltimateSkill(const FInputActionValue& Value) const -{ - AActor* ControlledRole = GetControlledRole(); - if (!ControlledRole) return; - if (IBusyControllable *Controllable = Cast(ControlledRole)) - { - Controllable->Execute_OnUltimateSkill(ControlledRole); - } -} - void ALevelPlayerController::OnCameraDetach(const FInputActionValue& Value) { if (!RoamingCameraActor) return; @@ -223,6 +188,7 @@ void ALevelPlayerController::OnRoleSkillTriggered(FGameplayTag GameplayTag) if (UAbilitySystemComponent* Asc = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(ControlledRole)) { FGameplayEventData EventData = FGameplayEventData(); + EventData.Instigator = ControlledRole; Asc->HandleGameplayEvent(GameplayTag, &EventData); } } diff --git a/Source/BusyRabbit/Public/BlueprintLibrary/BusyAscLibrary.h b/Source/BusyRabbit/Public/BlueprintLibrary/BusyAscLibrary.h index 113d211..8e912ed 100644 --- a/Source/BusyRabbit/Public/BlueprintLibrary/BusyAscLibrary.h +++ b/Source/BusyRabbit/Public/BlueprintLibrary/BusyAscLibrary.h @@ -1,7 +1,9 @@ #pragma once +#include "GameplayEffectTypes.h" #include "Kismet/BlueprintFunctionLibrary.h" #include "BusyAscLibrary.generated.h" +class UGameplayEffect; struct FGameplayEffectSpec; class UBusyAbilityDataAssetBase; @@ -15,4 +17,7 @@ public: UFUNCTION(BlueprintCallable) static AActor* GetEffectInstigator(const FGameplayEffectSpec& Spec); + + UFUNCTION(BlueprintCallable) + static FGameplayEffectSpecHandle MakeGameplayEffectSpecHandle(const UAbilitySystemComponent* Asc, const UGameplayEffect* Effect, const float Level); }; diff --git a/Source/BusyRabbit/Public/Data/Ability/Role/FoxAbilityDataAsset.h b/Source/BusyRabbit/Public/Data/Ability/Role/FoxAbilityDataAsset.h index d165ec8..fecbf1b 100644 --- a/Source/BusyRabbit/Public/Data/Ability/Role/FoxAbilityDataAsset.h +++ b/Source/BusyRabbit/Public/Data/Ability/Role/FoxAbilityDataAsset.h @@ -12,61 +12,64 @@ class UFoxUltimateDataAsset : public UBusyAbilityDataAssetBase { GENERATED_BODY() public: - UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="一阶消耗", Category="技能消耗") + UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="一阶消耗", Category="技能消耗", meta=(ScriptName="FirstStageCost")) float FirstStageCost = 5.f; - UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="二阶消耗", Category="技能消耗") + UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="二阶消耗", Category="技能消耗", meta=(ScriptName="SecondStageCost")) float SecondStageCost = 8.f; - UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="三阶消耗", Category="技能消耗") + UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="三阶消耗", Category="技能消耗", meta=(ScriptName="LastStageCost")) float LastStageCost = 12.f; - UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="一阶伤害系数", Category="伤害系数") + UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="一阶伤害系数", Category="伤害系数", meta=(ScriptName="FirstStageDamageFactor")) float FirstStageDamageFactor = 5.f; - UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="二阶伤害系数", Category="伤害系数") + UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="二阶伤害系数", Category="伤害系数", meta=(ScriptName="SecondStageDamageFactor")) float SecondStageDamageFactor = 8.f; - UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="三阶伤害系数", Category="伤害系数") + UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="三阶伤害系数", Category="伤害系数", meta=(ScriptName="LastStageDamageFactor")) float LastStageDamageFactor = 12.f; - UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="一阶速度系数", Category="速度系数") + UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="一阶速度系数", Category="速度系数", meta=(ScriptName="FirstStageSpeedFactor")) float FirstStageSpeedFactor = 5.f; - UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="二阶速度系数", Category="速度系数") + UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="二阶速度系数", Category="速度系数", meta=(ScriptName="SecondStageSpeedFactor")) float SecondStageSpeedFactor = 8.f; - UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="三阶一段速度系数", Category="速度系数") + UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="三阶一段速度系数", Category="速度系数", meta=(ScriptName="LastStageNormalSpeedFactor")) float LastStageNormalSpeedFactor = 12.f; - UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="三阶二段速度系数", Category="速度系数") + UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="三阶二段速度系数", Category="速度系数", meta=(ScriptName="LastStageSprintSpeedFactor")) float LastStageSprintSpeedFactor = 12.f; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="可释放一阶标签", Category="技能标签", meta=(ScriptName="FirstStageCastTag")) + FGameplayTag FirstStageCastTag; - UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="可释放二阶标签", Category="技能标签") - FGameplayTag SecondStageRecastTag; + UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="可释放二阶标签", Category="技能标签", meta=(ScriptName="SecondStageCastTag")) + FGameplayTag SecondStageCastTag; - UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="可释放三阶标签", Category="技能标签") - FGameplayTag LastStageRecastTag; + UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="可释放三阶标签", Category="技能标签", meta=(ScriptName="LastStageCastTag")) + FGameplayTag LastStageCastTag; - UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="一阶标签", Category="技能标签") + UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="一阶标签", Category="技能标签", meta=(ScriptName="FirstStageTag")) FGameplayTag FirstStageTag; - UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="二阶标签", Category="技能标签") + UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="二阶标签", Category="技能标签", meta=(ScriptName="SecondStageTag")) FGameplayTag SecondStageTag; - UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="三阶标签", Category="技能标签") + UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="三阶标签", Category="技能标签", meta=(ScriptName="LastStageTag")) FGameplayTag LastStageTag; - UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="可重新释放时长") + UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="可重新释放时长", meta=(ScriptName="RecastWindow")) float RecastWindow = 6.f; - UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="冷却时间") + UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="冷却时间", meta=(ScriptName="CooldownTime")) float CooldownTime = 15.f; }; \ No newline at end of file diff --git a/Source/BusyRabbit/Public/Gas/BusyGameAbility.h b/Source/BusyRabbit/Public/Gas/BusyGameAbility.h index 9541c57..9ca62ae 100644 --- a/Source/BusyRabbit/Public/Gas/BusyGameAbility.h +++ b/Source/BusyRabbit/Public/Gas/BusyGameAbility.h @@ -10,16 +10,16 @@ class UBusyGameAbility : public UGameplayAbility { GENERATED_BODY() public: - - UBusyGameAbility(); + virtual void OnGiveAbility(const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilitySpec& Spec) override; public: UFUNCTION(BlueprintCallable) bool GetAbilityEffectSpecHandle(const FName& EffectName, const UAbilitySystemComponent* Asc, const int32 Level, FGameplayEffectSpecHandle& Handle)const; + UFUNCTION(BlueprintNativeEvent) + void K2_OnGiveAbility(const FGameplayAbilityActorInfo& ActorInfo, const FGameplayAbilitySpec& Spec); public: - virtual void PostInitProperties()override; UBusyAbilityDataAssetBase* GetData()const { return Data; } public: diff --git a/Source/BusyRabbit/Public/Gas/BusyGameplayEffectSubSystem.h b/Source/BusyRabbit/Public/Gas/BusyGameplayEffectSubSystem.h new file mode 100644 index 0000000..498ab68 --- /dev/null +++ b/Source/BusyRabbit/Public/Gas/BusyGameplayEffectSubSystem.h @@ -0,0 +1,21 @@ +#pragma once +#include "GameplayTagContainer.h" +#include "BusyGameplayEffectSubSystem.generated.h" + +class UGameplayEffect; + +UCLASS(blueprinttype) +class UBusyGameplayEffectSubSystem : public UGameInstanceSubsystem +{ + GENERATED_BODY() + +public: + + UFUNCTION(BlueprintCallable, Category = "GameplayEffectSubSystem") + UGameplayEffect* GetTagGrantEffectWithDuration(const FGameplayTagContainer& TagsAdd, + const FGameplayTagContainer& TagsRemove, const float Duration, const float Period=0); + +private: + UPROPERTY() + TArray EffectsPool; +}; diff --git a/Source/BusyRabbit/Public/Level/Actor/BusyPawnBase.h b/Source/BusyRabbit/Public/Level/Actor/BusyPawnBase.h index 7091a54..e296956 100644 --- a/Source/BusyRabbit/Public/Level/Actor/BusyPawnBase.h +++ b/Source/BusyRabbit/Public/Level/Actor/BusyPawnBase.h @@ -70,10 +70,6 @@ public: UFUNCTION(BlueprintCallable) void BindGameplayTagAddOrRemove(const FGameplayTag& Tag, FGameplayTagAddOrRemoveDelegate Delegate)const; - -protected: - void InitCollision(); - protected: UPROPERTY(EditDefaultsOnly) TObjectPtr RootScene; //场景根组件 @@ -85,8 +81,7 @@ protected: UPROPERTY(EditDefaultsOnly) TObjectPtr SpineRenderComponent; - UPROPERTY(EditAnywhere, BlueprintReadOnly) - TObjectPtr SpineAnimationComponent; + /*-------------------------------------------------------------------*/ /*-----------------------------GAS相关--------------------------------*/ @@ -96,6 +91,9 @@ protected: /*-------------------------------------------------------------------*/ public: + UPROPERTY(EditAnywhere, BlueprintReadOnly) + TObjectPtr SpineAnimationComponent; + /*-------------------------------移动组件------------------------------*/ UPROPERTY(EditAnywhere, BlueprintReadOnly) TObjectPtr MovementComponent; diff --git a/Source/BusyRabbit/Public/Level/Actor/BusyPlayerRole.h b/Source/BusyRabbit/Public/Level/Actor/BusyPlayerRole.h index 0cbed04..1e2495b 100644 --- a/Source/BusyRabbit/Public/Level/Actor/BusyPlayerRole.h +++ b/Source/BusyRabbit/Public/Level/Actor/BusyPlayerRole.h @@ -36,7 +36,7 @@ public: UCLASS() -class ABusyPlayerRole : public ABusyPawnBase, public IBusyControllable +class ABusyPlayerRole : public ABusyPawnBase { GENERATED_BODY() public: @@ -48,7 +48,7 @@ public: virtual void InitPawnAttributes(const struct FBusyPawnBaseConfig& Config)override; - + virtual void OnMoveDirectionChanged_Implementation(const FVector2D& InDirection) override {} protected: /*--------------------相机相关--------------------------*/ diff --git a/Source/BusyRabbit/Public/Level/Actor/Components/BusyPawnMovement.h b/Source/BusyRabbit/Public/Level/Actor/Components/BusyPawnMovement.h index 41d0a43..779e2b2 100644 --- a/Source/BusyRabbit/Public/Level/Actor/Components/BusyPawnMovement.h +++ b/Source/BusyRabbit/Public/Level/Actor/Components/BusyPawnMovement.h @@ -34,6 +34,9 @@ enum class EBusyMoveState: uint8 }; +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FBusyMoveDirectionChanged, FVector2D, Direction); + + UCLASS() class UBusyPawnMovement : public UActorComponent { @@ -99,6 +102,11 @@ public: */ void SprintTick(const float DeltaTime); + +public: + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement") + FBusyMoveDirectionChanged MoveDirectionChangedDelegate; + protected: UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Movement") EBusyMoveState BusyMoveState = EBusyMoveState::None; diff --git a/Source/BusyRabbit/Public/Level/LevelPlayerController.h b/Source/BusyRabbit/Public/Level/LevelPlayerController.h index 0c9e44f..da43fe0 100644 --- a/Source/BusyRabbit/Public/Level/LevelPlayerController.h +++ b/Source/BusyRabbit/Public/Level/LevelPlayerController.h @@ -5,31 +5,6 @@ #include "LevelPlayerController.generated.h" - -UINTERFACE(MinimalAPI, Blueprintable) -class UBusyControllable: public UInterface -{ - GENERATED_BODY() -}; - -class IBusyControllable -{ - GENERATED_BODY() -public: - // 角色移动 - UFUNCTION(BlueprintNativeEvent, BlueprintCallable) - void OnMove(const FVector2D& Location); - - // 角色普通技能 - UFUNCTION(BlueprintNativeEvent, BlueprintCallable) - void OnPrimarySkill(); - - // 角色大招 - UFUNCTION(BlueprintNativeEvent, BlueprintCallable) - void OnUltimateSkill(); -}; - - class ABusyPlayerRole; struct FInputActionValue; @@ -116,15 +91,6 @@ public: // 输入相关 TArray RoleSkillActions; public: - UFUNCTION() - void OnMove(const FInputActionValue& Value)const; - - UFUNCTION() - void OnPrimarySkill(const FInputActionValue& Value)const; - - UFUNCTION() - void OnUltimateSkill(const FInputActionValue& Value)const; - UFUNCTION() void OnCameraDetach(const FInputActionValue& Value);