Compare commits
2 Commits
846e4d6f44
...
c111170bb0
| Author | SHA1 | Date |
|---|---|---|
|
|
c111170bb0 | |
|
|
cc8982b131 |
|
|
@ -7,8 +7,8 @@
|
|||
<AssetBundleCompression>1</AssetBundleCompression>
|
||||
<CompressionHelperTypeName>UnityGameFramework.Runtime.DefaultCompressionHelper</CompressionHelperTypeName>
|
||||
<AdditionalCompressionSelected>False</AdditionalCompressionSelected>
|
||||
<ForceRebuildAssetBundleSelected>True</ForceRebuildAssetBundleSelected>
|
||||
<BuildEventHandlerTypeName>VampireLike.Editor.VampireLikeBuildEventHandler</BuildEventHandlerTypeName>
|
||||
<ForceRebuildAssetBundleSelected>False</ForceRebuildAssetBundleSelected>
|
||||
<BuildEventHandlerTypeName>SepCore.Editor.DefaultBuildEventHandler</BuildEventHandlerTypeName>
|
||||
<OutputDirectory>D:/Learn/GameLearn/UnityProjects/VampireLike/bin/AssetBundles</OutputDirectory>
|
||||
<OutputPackageSelected>True</OutputPackageSelected>
|
||||
<OutputFullSelected>True</OutputFullSelected>
|
||||
|
|
|
|||
|
|
@ -31,20 +31,27 @@
|
|||
<Assets>
|
||||
<Asset Guid="0080b46050fc460cb6d6c7fc8d4e8c27" ResourceName="DataTables" />
|
||||
<Asset Guid="0179316b5fc7c2946a67c5877c02fc30" ResourceName="UI/UISprites/Common" />
|
||||
<Asset Guid="04d7dde7615d71b4db1a0c8d67a62e95" ResourceName="UI/UIForms" />
|
||||
<Asset Guid="037baa35a19f9e64ea778ab74b0d48eb" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="03a4e96650b651d49b7cb120872f7d61" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="04dbc0581071c254ea6564b2ff06ff9b" ResourceName="Textures" />
|
||||
<Asset Guid="04e1c2b9cc1f8484cbf5533473f55a2c" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="0722cd253d6bf014eb4134a2151ec7e3" ResourceName="UI/UIItems" />
|
||||
<Asset Guid="08c97a5a0cf01ff469525a635a4a1eb1" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="093f8873cfe371d41b854ed9fb6bff69" ResourceName="Music/About" />
|
||||
<Asset Guid="0963e6c65b2b1f74d9f455e21901e2dc" ResourceName="Textures" />
|
||||
<Asset Guid="0a65a68c01a76ea4b8b574827a6467aa" ResourceName="UI/UISprites/Common" />
|
||||
<Asset Guid="0b6c5dfe0bd1cc34497e98040ca981e1" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="0e45b8557b1831845a6e03fce7b5aa2b" ResourceName="SceneSettings" />
|
||||
<Asset Guid="0ed73dc47f4cb38489020d05e9f02c99" ResourceName="Materials" />
|
||||
<Asset Guid="0f995b3145e0e7247a42da6cef1dbf23" ResourceName="Materials" />
|
||||
<Asset Guid="1046dcb12e547564d8b54bd15419a787" ResourceName="Entities" />
|
||||
<Asset Guid="1053b0070685be347ab58587156842dc" ResourceName="Localization/Dictionaries" ResourceVariant="zh-tw" />
|
||||
<Asset Guid="11143001bcbdc864b8d8fe2083142e5a" ResourceName="Entities" />
|
||||
<Asset Guid="1125080c72a9ace40b258e8df7695362" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="121c37ab385fb0248bdf75e663ac8e8e" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="1478894bc9a1ed241b05b0862a7b8bce" ResourceName="Textures" />
|
||||
<Asset Guid="14869ac0d4433f04db1704e39d03412e" ResourceName="Localization/Dictionaries" ResourceVariant="en-us" />
|
||||
<Asset Guid="14fe2dc326b7c78458bc404b6a9c791c" ResourceName="UI/UIForms" />
|
||||
<Asset Guid="156d241f796508c4da4fc354a7fbf5a8" ResourceName="UI/UISprites/Common" />
|
||||
<Asset Guid="185f97f18bd603a478461ce9c08bd039" ResourceName="Materials" />
|
||||
<Asset Guid="18dc0cd2c080841dea60987a38ce93fa" ResourceName="URPAssets" />
|
||||
|
|
@ -57,24 +64,30 @@
|
|||
<Asset Guid="1d46a17a95a444c08830612bc1146d1d" ResourceName="Materials" />
|
||||
<Asset Guid="1e0350b97c61bfb4a91c62d756d01727" ResourceName="Materials" />
|
||||
<Asset Guid="1eb120084e9602c4da979658e08c63e4" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="1f84d60b84fd40b49bc5033530a7e24a" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="20e5dc75d1c3fe74bb841127a036d69d" ResourceName="UI/UIForms" />
|
||||
<Asset Guid="20ebdccacd18e7c45a8c10c46cddb3d7" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="2257393dd6ed51a49a6c3fd178382b59" ResourceName="Materials" />
|
||||
<Asset Guid="236433a27ce40a7429b87d14d8fa3035" ResourceName="UI/UISprites/Common" />
|
||||
<Asset Guid="24ca310f92a6796408f1db7647ec4e55" ResourceName="UI/UISprites/Common" />
|
||||
<Asset Guid="25229adaac96caa42a737b60465f3229" ResourceName="Fonts" />
|
||||
<Asset Guid="261cde3315e1f0e41a28d6477fa3d434" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="2768a9a4c8d289840918dcb879705893" ResourceName="Meshes" />
|
||||
<Asset Guid="28988b1366cba3e4b947bb60d6b118f9" ResourceName="DataTables" />
|
||||
<Asset Guid="28c42f88cfe56e84e95c0d7545db8c1b" ResourceName="Materials" />
|
||||
<Asset Guid="2cb5eef4d7d7bf6459dd13a3f8d90246" ResourceName="Textures" />
|
||||
<Asset Guid="2d1b2cc11a8e99f42b34265765fc6d86" ResourceName="Entities" />
|
||||
<Asset Guid="2ed59bf0745586248aaa89cf7d3305a7" ResourceName="Entities" />
|
||||
<Asset Guid="2fbbf1c667136af4b9dd4f823f897378" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="308577c72eb4cd14ca676aeee62b0ea5" ResourceName="UI/UIItems" />
|
||||
<Asset Guid="312264fc6c05ca04499685cc989e533d" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="315e8ed2db27c254cb3366ff0793cd90" ResourceName="DataTables" />
|
||||
<Asset Guid="352da872791696c48af3b21132e3e3c3" ResourceName="DataTables" />
|
||||
<Asset Guid="372a8b1e52bedc64b9207b12d167afaa" ResourceName="DataTables" />
|
||||
<Asset Guid="39e7c07f139dbb3438fc8b55662778d5" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="3aa539b1e46111d4299a83c73ebe762c" ResourceName="UI/UIForms" />
|
||||
<Asset Guid="3be3fac3611f4584695662c4889f722d" ResourceName="UI/UISprites/Common" />
|
||||
<Asset Guid="3cda1857d670c6340adb393eda40cd3e" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="3dc7455402dfa462b89a4bbd513955e9" ResourceName="Sounds" />
|
||||
<Asset Guid="3e504a46a8fcec34db3c4776530c6eb2" ResourceName="Textures" />
|
||||
<Asset Guid="3f54fcfdac53aec42ae18a6a1c6d8cb1" ResourceName="UI/UISprites/Common" />
|
||||
|
|
@ -82,26 +95,35 @@
|
|||
<Asset Guid="4209bea5e51753141ae060017f42afdc" ResourceName="UI/UIForms" />
|
||||
<Asset Guid="429ed03405bf8854eab46552b7470ac0" ResourceName="Materials" />
|
||||
<Asset Guid="4473d81b14ddb0143addf0e6050d8491" ResourceName="Scenes" />
|
||||
<Asset Guid="44b2eb1016babff49866138a705af9f6" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="44c8db52241385c45bbb14a1718f17bf" ResourceName="Configs" />
|
||||
<Asset Guid="44cfa1c448225554c961ad6eb667d80b" ResourceName="DataTables" />
|
||||
<Asset Guid="4b1e2f50f0632d9478c096a9ad7b5509" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="4c3865b2ac420cd46a9cde6ab468d016" ResourceName="Materials" />
|
||||
<Asset Guid="4ca22ae3bc068c84eb7858d5b9bdf3e2" ResourceName="Fonts" />
|
||||
<Asset Guid="4f688097e85071841a2c3ba165000c20" ResourceName="Textures" />
|
||||
<Asset Guid="5282f20eba4d44213820e21af8481932" ResourceName="Meshes" />
|
||||
<Asset Guid="5461b0fc87a2ab04fbcfd898d18f6107" ResourceName="Configs" />
|
||||
<Asset Guid="56142b46ec15fe74b85ca4fdd3324751" ResourceName="UI/UIForms" />
|
||||
<Asset Guid="56b8df63bbad60749a69e38bc687fadf" ResourceName="UI/UISprites/Common" />
|
||||
<Asset Guid="578af1667322bab45b652b79a40bb4fb" ResourceName="Materials" />
|
||||
<Asset Guid="583ff7026dac91849b7c7b2468ba456b" ResourceName="Materials" />
|
||||
<Asset Guid="598cee40dd61c3349acd508f5c2c92c1" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="5b5a6a737c460eb4abc105d6583d405e" ResourceName="Fonts" />
|
||||
<Asset Guid="5dcd89912e222bf4c87f76db4044bc5e" ResourceName="Localization/Dictionaries" ResourceVariant="ko-kr" />
|
||||
<Asset Guid="5ebb46af6f16ae94e87f64a7dc0a49cb" ResourceName="Entities" />
|
||||
<Asset Guid="62242e716ff2d274da787fe558f06b06" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="62af9e5c8f39cfa49af9e10ccf42f1da" ResourceName="UI/UISprites/Common" />
|
||||
<Asset Guid="632ea7a45da70a34984e1280b03fc579" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="638ff8ae4a0d15047839cd265d3bc296" ResourceName="Music/Background" />
|
||||
<Asset Guid="63fe6ff9ab9e1433f8db4ebd940f2442" ResourceName="Materials" />
|
||||
<Asset Guid="64c7bcc7087b03d4b9bc0ac32f9b2b48" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="65a506fc3ca171347ac74203416a3d7f" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="65ffa78c2e8cbb346826cc2f3a7b6ea4" ResourceName="DataTables" />
|
||||
<Asset Guid="66261723fe421be498ce5957449fc972" ResourceName="Scenes" />
|
||||
<Asset Guid="68729f225481f3a49b1daacf924dd109" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="6a58ea03d3bd54e428d969b85afa5680" ResourceName="Fonts" />
|
||||
<Asset Guid="6c80f46064f8e74429d9fdc5190abfb0" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="6cbc2c323b77f804fb958fa4eca33998" ResourceName="UI/UISprites/Common" />
|
||||
<Asset Guid="6d9b42ac01f24bf4d98923573f103575" ResourceName="Textures" />
|
||||
<Asset Guid="6db0c8354d868834abf29840037591b1" ResourceName="Textures" />
|
||||
|
|
@ -111,10 +133,12 @@
|
|||
<Asset Guid="6e5d026bf0652ed4380f6a66f4aa26c5" ResourceName="Textures" />
|
||||
<Asset Guid="707360a9c581a4bd7aa53bfeb1429f71" ResourceName="URPAssets" />
|
||||
<Asset Guid="71646ebaae78d43aeb8b53cacdb69671" ResourceName="Textures" />
|
||||
<Asset Guid="717aeb9eec580f74b8ba8c4e2b657efb" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="72e76810224064300b7d32e8322a5d12" ResourceName="Sounds" />
|
||||
<Asset Guid="74de26a1b47fa13468ea72894a720176" ResourceName="UI/UIForms" />
|
||||
<Asset Guid="77cbb7c5404c10242ab59953e0746314" ResourceName="Fonts" />
|
||||
<Asset Guid="78595a129d0438c44b2d52720e9c0edd" ResourceName="UI/UIItems" />
|
||||
<Asset Guid="7aac48e4d5b44884b8cafa4de4e489ef" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="7b7fd9122c28c4d15b667c7040e3b3fd" ResourceName="URPAssets" />
|
||||
<Asset Guid="7e6ecd46ba625fb43ab2b4bc52dcb3c1" ResourceName="DataTables" />
|
||||
<Asset Guid="7e91cd9bad7babf4b975882a4b7453cb" ResourceName="Textures" />
|
||||
|
|
@ -122,17 +146,24 @@
|
|||
<Asset Guid="7f1361f834115be4ea4ec2387c67334e" ResourceName="Fonts" />
|
||||
<Asset Guid="7f5aee8da226edf4991598327cb32ce0" ResourceName="UI/UISprites/Logos" />
|
||||
<Asset Guid="7fd11dc5d29076d469d414dec2818f11" ResourceName="Configs" />
|
||||
<Asset Guid="800f7cb88c9f452479b6ad9576c7b25d" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="836be25be3e1e8c41ae5545bc8a9a4d7" ResourceName="Textures" />
|
||||
<Asset Guid="83e5fce2d1e5b3e4ab6551de03cc9c22" ResourceName="Materials" />
|
||||
<Asset Guid="85c9ccd84e0717f4dba80fd64bc9fb53" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="8940b037a9b441c4cbd3d2b446838424" ResourceName="Materials" />
|
||||
<Asset Guid="8e27380ee68aa4a219b4db9018e7da31" ResourceName="Materials" />
|
||||
<Asset Guid="903fe490f7ddf7b489e01f02c7983c79" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="91b565625868b59428114c4a5b945e80" ResourceName="UI/UISprites/SelectRoleFormRT" />
|
||||
<Asset Guid="92e207ca452785d478c7a2994d0c8351" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="92e9102fc83c8e949971efe6f1fa6501" ResourceName="UI/UIForms" />
|
||||
<Asset Guid="9400f2349c8b48a4b9fa86bd63f169cb" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="9538765dceb3e9248aec104646e501ad" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="955000b4d1441470e8cbf94f483228b5" ResourceName="Materials" />
|
||||
<Asset Guid="97b1f8b25cca2bc458cb9d6127c8d186" ResourceName="Materials" />
|
||||
<Asset Guid="99d811b0183246646a2ce8df996f4bca" ResourceName="Fonts" />
|
||||
<Asset Guid="9ab9adabcf369c44e89076c7e5b454ba" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="9ad79a3e50af5244eb233da7e4f21233" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="9afa958d6d8235941b9badb42aae4370" ResourceName="Meshes" />
|
||||
<Asset Guid="9bc1d62ccbd7a754f9612f310b40be8c" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="9be2e1e45f4edd74c8764538ad306b78" ResourceName="Localization/Dictionaries" ResourceVariant="zh-cn" />
|
||||
<Asset Guid="9d193ac5b4294e0e9ba6e867320944b7" ResourceName="Entities" />
|
||||
<Asset Guid="9ddab293e2a8af3499dac05f5fd6169c" ResourceName="Meshes" />
|
||||
|
|
@ -140,55 +171,82 @@
|
|||
<Asset Guid="9f847ec5e66e03e4ead1d3c5f7b510e8" ResourceName="UI/UISprites/Common" />
|
||||
<Asset Guid="a019ae3af8e864616b85773c509f5285" ResourceName="Sounds" />
|
||||
<Asset Guid="a23eef5e20ff8cb46adf33491fc443fb" ResourceName="Materials" />
|
||||
<Asset Guid="a266178dac3c9e448ae7bf85617cfd6a" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="a4b74a0ecf03ffb47b0b0e5dfa8ca35f" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="a6560a915ef98420e9faacc1c7438823" ResourceName="URPAssets" />
|
||||
<Asset Guid="a6ac41115088b5946bc544429260c997" ResourceName="Entities" />
|
||||
<Asset Guid="a71f8bb1b1b2c51438e2bafc884cb02c" ResourceName="DataTables" />
|
||||
<Asset Guid="a76ff56683a2bc2479ebd63dcdd658b0" ResourceName="UI/UIItems" />
|
||||
<Asset Guid="a77acddad3f780148b867a6ccdfe95b8" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="a7b030cffa2dc44478c14e49a22771c2" ResourceName="Materials" />
|
||||
<Asset Guid="a8c07bbe04fdaf04b80e27f651a8edd6" ResourceName="UI/UISprites/Common" />
|
||||
<Asset Guid="a9be0531a19af934e97a1f3b47b78872" ResourceName="UI/UISprites/Common" />
|
||||
<Asset Guid="aa90f2691281f1e429893fabd7656264" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="ab01163442b94ad4794a345dd5a49ec9" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="ab1c66f8a301fe043930c9f0c23716cf" ResourceName="Fonts" />
|
||||
<Asset Guid="ab45c3f613f388d43bbf43ec05eb92e2" ResourceName="UI/UISprites/Common" />
|
||||
<Asset Guid="ab4774faf71b57a40a29a9e902403fe3" ResourceName="DataTables" />
|
||||
<Asset Guid="abb5b3b95f1a42c46a251da378cbeace" ResourceName="Entities" />
|
||||
<Asset Guid="adad702a675d15945aa01e882420d653" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="ae6a7f967521769458b0913fa39caaf4" ResourceName="Textures" />
|
||||
<Asset Guid="b031b4f2980561542a7f7ba41391edc3" ResourceName="Scenes" />
|
||||
<Asset Guid="b0c7cf51d3fecb446ab93bf854419715" ResourceName="Materials" />
|
||||
<Asset Guid="b6539f2b0fa989d4fb7e057799b9260d" ResourceName="Fonts" />
|
||||
<Asset Guid="b6f06390b8e233345b9a089681f14b81" ResourceName="Entities" />
|
||||
<Asset Guid="b8848e672f7437f42a6285a4fe499afb" ResourceName="UI/UIForms" />
|
||||
<Asset Guid="b9611b00d258c1c40adf809817828ec1" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="ba157ba55f72c424a9e88f3c029997c4" ResourceName="Textures" />
|
||||
<Asset Guid="babce70282f41c6419b2e1807532b375" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="baedbbad82997f445a8cb4da210404e0" ResourceName="Meshes" />
|
||||
<Asset Guid="bbfd75fe6fe00e1448fe988173ede7f9" ResourceName="UI/UIForms" />
|
||||
<Asset Guid="bc065bcf1474d7d4387fafd202678c37" ResourceName="Fonts" />
|
||||
<Asset Guid="bf75b984df8a84987bcf3a8bf6e2862d" ResourceName="Sounds" />
|
||||
<Asset Guid="c27d1aa86b4c7054a82432a9d71e5f85" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="c3a86ff7445c9c94cbf24ef544cecf4c" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="c3f12cb3b19f78748bc2a90894790dd4" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="c40be3174f62c4acf8c1216858c64956" ResourceName="URPAssets" />
|
||||
<Asset Guid="c49cffd4fc1dfb549b2b30448a0becda" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="c4f37184fcb9306428d7d002f7dca96d" ResourceName="Materials" />
|
||||
<Asset Guid="c547624e174de984882f0a14b4bb32e1" ResourceName="Materials" />
|
||||
<Asset Guid="c58c9afddbd36d14d837fa218d772996" ResourceName="Materials" />
|
||||
<Asset Guid="c7d1e11dd37634b48a9dd4012b8e4306" ResourceName="UI/UISounds" />
|
||||
<Asset Guid="c972fe1ec8a1e0b4292f01575b0b3898" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="caa829ab2ffc71340a69253afdf58365" ResourceName="Music/Menu" />
|
||||
<Asset Guid="cadd0764941c8b646ae79b51d0ea8285" ResourceName="UI/UISprites/Common" />
|
||||
<Asset Guid="cd819288654317a49853341f3f17ee50" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="ce3f3526692a08a489042130fa47039e" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="ce8bbe245fa50b74bac0eea7bff0dc3a" ResourceName="UI/UIItems" />
|
||||
<Asset Guid="cf05d7e458e9c4c4b8e78442e9277815" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="cfe53cf384344bd47a8680f8c5f97a7b" ResourceName="DataTables" />
|
||||
<Asset Guid="d0e2fc18fe036412f8223b3b3d9ad574" ResourceName="URPAssets" />
|
||||
<Asset Guid="d39d823848837064f84424b6621a3e6b" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="d3bdbf0dec5b2864f902c43899017cbc" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="d5396f61766946c4db970694836a49fc" ResourceName="UI/UIItems" />
|
||||
<Asset Guid="d607728ea8898a048bd3beba30fe5853" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="d9808401c68af274a8edfbed3d1b53c7" ResourceName="Meshes" />
|
||||
<Asset Guid="db58965402f12ed47b4dad61a9e48c9d" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="dd972bed1926aa4489426be921651ec5" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="e03343286e97c824c8e1595b0ccb1000" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="e1260c1148f6143b28bae5ace5e9c5d1" ResourceName="URPAssets" />
|
||||
<Asset Guid="e198b017eb054ef41879410763964076" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="e3547eea3b25dbc4bb1170421633a004" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="e3616cef1ab22d642903eb59f34feea1" ResourceName="Entities" />
|
||||
<Asset Guid="e5ca26c53b6ab8a46b52817008d7c7fa" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="e634585d5c4544dd297acaee93dc2beb" ResourceName="URPAssets" />
|
||||
<Asset Guid="e82837c9099f69a48b48fc44eb8d119d" ResourceName="UI/UISprites/Common" />
|
||||
<Asset Guid="e830964cdb85ff3429bca484c16bab44" ResourceName="UI/UISounds" />
|
||||
<Asset Guid="e85864330b68dde498dcb6e8711815d3" ResourceName="UI/UISprites/Common" />
|
||||
<Asset Guid="e8904198a64b17443b96e2bf83d7055b" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="e8def20f1612e8844b8f0dda497fa5ba" ResourceName="DataTables" />
|
||||
<Asset Guid="eabb37cb6d738b443b398b701a64cd88" ResourceName="Textures" />
|
||||
<Asset Guid="edfd1e0fa2ccc4b4e94879d87eada2f7" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="f06c2627a191cc1468383483fbafca04" ResourceName="Fonts" />
|
||||
<Asset Guid="f17bc7e2694233349a8b22e96c5c43de" ResourceName="Materials" />
|
||||
<Asset Guid="f2f4df0b7211e4c42a5638273525d8ee" ResourceName="UI/UISprites/Common" />
|
||||
<Asset Guid="f2f97a713beae744181ba934f9c4113a" ResourceName="DataTables" />
|
||||
<Asset Guid="f319082377c69d74484c7fa612e50cf8" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="f36c72c738c55f741afcd674a0b1245f" ResourceName="Materials" />
|
||||
<Asset Guid="f3e6e933f81f117478eed5a4baccbc46" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="f438a72a91e1c3c4a9ced40888ffec96" ResourceName="UI/UISprites/Icons" />
|
||||
<Asset Guid="f5b2cc6c7ce8cc5408ad507a4f40af49" ResourceName="Fonts" />
|
||||
<Asset Guid="f6bd6a95990ae92469c5c9ab4293064f" ResourceName="UI/UIForms" />
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using GameFramework.Fsm;
|
|||
using GameFramework.Procedure;
|
||||
using SepCore.EnemyManager;
|
||||
using SepCore.Simulation;
|
||||
using SepCore.Timer;
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.Procedure
|
||||
|
|
@ -20,7 +21,7 @@ namespace SepCore.Procedure
|
|||
|
||||
private int _currentLevel;
|
||||
|
||||
private float _levelTimeLeft;
|
||||
private TimerHandle _levelTimerHandle;
|
||||
|
||||
private Player Player => _procedureGame.Player;
|
||||
|
||||
|
|
@ -29,7 +30,11 @@ namespace SepCore.Procedure
|
|||
public void AddBattleDuration(float seconds)
|
||||
{
|
||||
if (seconds <= 0f) return;
|
||||
_levelTimeLeft += seconds;
|
||||
|
||||
float remaining = GameEntry.Timer.GetRemainingTime(_levelTimerHandle);
|
||||
if (remaining < 0f) return;
|
||||
|
||||
GameEntry.Timer.ResetRemainingTime(_levelTimerHandle, remaining + seconds);
|
||||
}
|
||||
|
||||
#region FSM
|
||||
|
|
@ -51,7 +56,7 @@ namespace SepCore.Procedure
|
|||
throw new Exception($"GameStateBattle.OnEnter: {_currentLevel} is not found.");
|
||||
}
|
||||
|
||||
_levelTimeLeft = drLevel.Duration;
|
||||
_levelTimerHandle = GameEntry.Timer.ScheduleOnce(drLevel.Duration, OnLevelTimeUp, this);
|
||||
_enemyManager.OnInit(drLevel, Player);
|
||||
|
||||
if (Player != null) Player.Enable = true;
|
||||
|
|
@ -64,12 +69,6 @@ namespace SepCore.Procedure
|
|||
|
||||
public override void OnUpdate(float elapseSeconds, float realElapseSeconds)
|
||||
{
|
||||
if (_levelTimeLeft < 0)
|
||||
{
|
||||
_procedureGame.BattleToShopOrLevelUp();
|
||||
return;
|
||||
}
|
||||
|
||||
_enemyManager.OnUpdate(elapseSeconds, realElapseSeconds);
|
||||
|
||||
SimulationWorld simulationWorld = GameEntry.SimulationWorld;
|
||||
|
|
@ -79,14 +78,22 @@ namespace SepCore.Procedure
|
|||
simulationWorld.Tick(new SimulationTickContext(elapseSeconds, realElapseSeconds, playerPosition));
|
||||
}
|
||||
|
||||
_levelTimeLeft -= elapseSeconds;
|
||||
GameEntry.Event.Fire(this, LevelProcessEventArgs.Create((int)_levelTimeLeft));
|
||||
int timeLeft = Mathf.Max(0, (int)GameEntry.Timer.GetRemainingTime(_levelTimerHandle));
|
||||
GameEntry.Event.Fire(this, LevelProcessEventArgs.Create(timeLeft));
|
||||
}
|
||||
|
||||
private void OnLevelTimeUp()
|
||||
{
|
||||
_procedureGame.BattleToShopOrLevelUp();
|
||||
}
|
||||
|
||||
public override void OnLeave()
|
||||
{
|
||||
GameEntry.UIRouter.CloseUIAsync(UIFormType.JoystickForm).Forget();
|
||||
|
||||
GameEntry.Timer.Cancel(_levelTimerHandle);
|
||||
_levelTimerHandle = TimerHandle.Invalid;
|
||||
|
||||
// 隐藏所有敌人实体
|
||||
_enemyManager.OnReset();
|
||||
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ namespace SepCore.EnemyManager
|
|||
_spawnCts?.Dispose();
|
||||
_spawnCts = null;
|
||||
_enemyRegistry = null;
|
||||
_spawnScheduler?.Reset();
|
||||
_spawnScheduler = null;
|
||||
_entity = null;
|
||||
}
|
||||
|
|
@ -71,7 +72,7 @@ namespace SepCore.EnemyManager
|
|||
_duration = _baseDuration;
|
||||
_currentLevel = level.Id;
|
||||
|
||||
_spawnScheduler.Init(level);
|
||||
_spawnScheduler.Init(level, OnWaveSpawn);
|
||||
_enemyRegistry.Clear();
|
||||
_currentSpawnEnemyId = 0;
|
||||
}
|
||||
|
|
@ -79,13 +80,14 @@ namespace SepCore.EnemyManager
|
|||
public void OnUpdate(float elapseSeconds, float realElapseSeconds)
|
||||
{
|
||||
_enemyRegistry.PruneInvalidEntries();
|
||||
var spawnRequests = _spawnScheduler.Tick(elapseSeconds);
|
||||
foreach (var request in spawnRequests)
|
||||
_spawnScheduler.Tick(elapseSeconds);
|
||||
}
|
||||
|
||||
private void OnWaveSpawn(EnemyType enemyType, int count)
|
||||
{
|
||||
for (int j = 0; j < count; j++)
|
||||
{
|
||||
for (int j = 0; j < request.Count; j++)
|
||||
{
|
||||
SpawnEnemyAsync(request.EnemyType).Forget();
|
||||
}
|
||||
SpawnEnemyAsync(enemyType).Forget();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using SepCore.DataTable;
|
||||
using SepCore.Definition;
|
||||
using SepCore.Timer;
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.EnemyManager
|
||||
|
|
@ -12,98 +12,67 @@ namespace SepCore.EnemyManager
|
|||
|
||||
private float _elapsedTime;
|
||||
private float[] _baseIntervals;
|
||||
private float[] _currentIntervals;
|
||||
private EnemyType[] _enemyTypes;
|
||||
private int[] _spawnCounts;
|
||||
private float[] _nextSpawnTimes;
|
||||
private TimerHandle[] _waveHandles;
|
||||
private float _spawnRateScale = 1f;
|
||||
private Action<EnemyType, int> _onSpawn;
|
||||
|
||||
public float SpawnRateScale => _spawnRateScale;
|
||||
public float ElapsedTime => _elapsedTime;
|
||||
public int WaveCount => _enemyTypes?.Length ?? 0;
|
||||
|
||||
public void Init(DRLevel level)
|
||||
public void Init(DRLevel level, Action<EnemyType, int> onSpawn)
|
||||
{
|
||||
GameEntry.Timer.CancelByOwner(this);
|
||||
|
||||
_onSpawn = onSpawn;
|
||||
_baseIntervals = (float[])level.Intervals.Clone();
|
||||
_currentIntervals = (float[])_baseIntervals.Clone();
|
||||
_enemyTypes = level.EntityTypes;
|
||||
_spawnCounts = level.EntityCounts;
|
||||
_elapsedTime = 0f;
|
||||
|
||||
SetSpawnRateScale(_spawnRateScale);
|
||||
_waveHandles = new TimerHandle[_baseIntervals.Length];
|
||||
for (int i = 0; i < _baseIntervals.Length; i++)
|
||||
{
|
||||
int waveIndex = i;
|
||||
float interval = GetScaledInterval(_baseIntervals[i], _spawnRateScale);
|
||||
_waveHandles[i] = GameEntry.Timer.ScheduleRepeat(interval, () => OnWaveTick(waveIndex), -1, this);
|
||||
}
|
||||
}
|
||||
|
||||
public List<SpawnRequest> Tick(float deltaTime)
|
||||
public void Tick(float deltaTime)
|
||||
{
|
||||
_elapsedTime += deltaTime;
|
||||
var requests = new List<SpawnRequest>();
|
||||
|
||||
if (_nextSpawnTimes == null) return requests;
|
||||
|
||||
for (int i = 0; i < _nextSpawnTimes.Length; i++)
|
||||
{
|
||||
if (_elapsedTime < _nextSpawnTimes[i]) continue;
|
||||
|
||||
requests.Add(new SpawnRequest
|
||||
{
|
||||
EnemyType = _enemyTypes[i],
|
||||
Count = _spawnCounts[i],
|
||||
WaveIndex = i
|
||||
});
|
||||
|
||||
_nextSpawnTimes[i] += _currentIntervals[i];
|
||||
}
|
||||
|
||||
return requests;
|
||||
}
|
||||
|
||||
public void SetSpawnRateScale(float scale)
|
||||
{
|
||||
float newScale = Mathf.Max(MinSpawnRateScale, scale);
|
||||
if (_baseIntervals == null || _baseIntervals.Length == 0)
|
||||
_spawnRateScale = Mathf.Max(MinSpawnRateScale, scale);
|
||||
if (_waveHandles == null) return;
|
||||
|
||||
for (int i = 0; i < _waveHandles.Length; i++)
|
||||
{
|
||||
_spawnRateScale = newScale;
|
||||
return;
|
||||
}
|
||||
|
||||
bool hasRuntimeState = _nextSpawnTimes != null && _currentIntervals != null &&
|
||||
_nextSpawnTimes.Length == _baseIntervals.Length &&
|
||||
_currentIntervals.Length == _baseIntervals.Length;
|
||||
float oldScale = _spawnRateScale;
|
||||
_spawnRateScale = newScale;
|
||||
|
||||
if (!hasRuntimeState)
|
||||
{
|
||||
for (int i = 0; i < _baseIntervals.Length; i++)
|
||||
{
|
||||
_currentIntervals[i] = GetScaledInterval(_baseIntervals[i], _spawnRateScale);
|
||||
}
|
||||
|
||||
_nextSpawnTimes = (float[])_currentIntervals.Clone();
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _baseIntervals.Length; i++)
|
||||
{
|
||||
float oldInterval = GetScaledInterval(_baseIntervals[i], oldScale);
|
||||
float newInterval = GetScaledInterval(_baseIntervals[i], _spawnRateScale);
|
||||
|
||||
float remainTime = Mathf.Max(0f, _nextSpawnTimes[i] - _elapsedTime);
|
||||
float remainRatio = oldInterval > Mathf.Epsilon ? Mathf.Clamp01(remainTime / oldInterval) : 0f;
|
||||
|
||||
_currentIntervals[i] = newInterval;
|
||||
_nextSpawnTimes[i] = _elapsedTime + newInterval * remainRatio;
|
||||
GameEntry.Timer.SetInterval(_waveHandles[i], newInterval, adjustRemainingTime: true);
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
GameEntry.Timer.CancelByOwner(this);
|
||||
_elapsedTime = 0;
|
||||
_baseIntervals = null;
|
||||
_currentIntervals = null;
|
||||
_enemyTypes = null;
|
||||
_spawnCounts = null;
|
||||
_nextSpawnTimes = null;
|
||||
_waveHandles = null;
|
||||
_spawnRateScale = 1f;
|
||||
_onSpawn = null;
|
||||
}
|
||||
|
||||
private void OnWaveTick(int waveIndex)
|
||||
{
|
||||
_onSpawn?.Invoke(_enemyTypes[waveIndex], _spawnCounts[waveIndex]);
|
||||
}
|
||||
|
||||
private static float GetScaledInterval(float baseInterval, float scale)
|
||||
|
|
@ -112,11 +81,4 @@ namespace SepCore.EnemyManager
|
|||
return baseInterval / safeScale;
|
||||
}
|
||||
}
|
||||
|
||||
public struct SpawnRequest
|
||||
{
|
||||
public EnemyType EnemyType;
|
||||
public int Count;
|
||||
public int WaveIndex;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
using SepCore.AsyncTask;
|
||||
using SepCore.Definition;
|
||||
using SepCore.Entity;
|
||||
using SepCore.Timer;
|
||||
using UnityEngine;
|
||||
|
||||
public abstract class EnemyBase : TargetableObject
|
||||
|
|
@ -15,6 +16,29 @@ public abstract class EnemyBase : TargetableObject
|
|||
|
||||
protected EnemyData _enemyData;
|
||||
|
||||
protected bool _canAttack;
|
||||
protected TimerHandle _attackTimerHandle;
|
||||
|
||||
protected void StartAttackCooldown(float cooldown)
|
||||
{
|
||||
_canAttack = false;
|
||||
_attackTimerHandle = GameEntry.Timer.ScheduleOnce(cooldown, () => _canAttack = true, this);
|
||||
}
|
||||
|
||||
protected void ResetAttackCooldown(float cooldown)
|
||||
{
|
||||
GameEntry.Timer.Cancel(_attackTimerHandle);
|
||||
_canAttack = false;
|
||||
_attackTimerHandle = GameEntry.Timer.ScheduleOnce(cooldown, () => _canAttack = true, this);
|
||||
}
|
||||
|
||||
protected void CancelAttackCooldown()
|
||||
{
|
||||
GameEntry.Timer.Cancel(_attackTimerHandle);
|
||||
_attackTimerHandle = TimerHandle.Invalid;
|
||||
_canAttack = false;
|
||||
}
|
||||
|
||||
protected override void OnShow(object userData)
|
||||
{
|
||||
base.OnShow(userData);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
using SepCore.Components;
|
||||
using SepCore.CustomUtility;
|
||||
using SepCore.Definition;
|
||||
using SepCore.Timer;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
|
|
@ -24,8 +23,6 @@ namespace SepCore.Entity
|
|||
private int _attackDamage = 1;
|
||||
|
||||
private float _sqrAttackRange;
|
||||
private TimerHandle _attackTimerHandle;
|
||||
private bool _canAttack;
|
||||
|
||||
private AttackStateType _attackState = AttackStateType.Idle;
|
||||
|
||||
|
|
@ -71,8 +68,7 @@ namespace SepCore.Entity
|
|||
_attackDamage = Mathf.Max(1, _meleeEnemyData.AttackDamage);
|
||||
_sqrAttackRange = _attackRange * _attackRange;
|
||||
|
||||
_canAttack = false;
|
||||
_attackTimerHandle = GameEntry.Timer.ScheduleOnce(_attackCooldown, () => _canAttack = true, this);
|
||||
StartAttackCooldown(_attackCooldown);
|
||||
_attackState = AttackStateType.Idle;
|
||||
_targetableTarget = null;
|
||||
|
||||
|
|
@ -96,8 +92,7 @@ namespace SepCore.Entity
|
|||
_movementComponent.OnReset();
|
||||
_healthComponent.OnReset();
|
||||
_targetableTarget = null;
|
||||
GameEntry.Timer.Cancel(_attackTimerHandle);
|
||||
_attackTimerHandle = TimerHandle.Invalid;
|
||||
CancelAttackCooldown();
|
||||
_attackState = AttackStateType.Idle;
|
||||
|
||||
base.OnHide(isShutdown, userData);
|
||||
|
|
@ -155,8 +150,7 @@ namespace SepCore.Entity
|
|||
|
||||
if (_canAttack)
|
||||
{
|
||||
_canAttack = false;
|
||||
_attackTimerHandle = GameEntry.Timer.ScheduleOnce(_attackCooldown, () => _canAttack = true, this);
|
||||
ResetAttackCooldown(_attackCooldown);
|
||||
TransitionTo(AttackStateType.Attack);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ using SepCore.AsyncTask;
|
|||
using SepCore.CustomUtility;
|
||||
using SepCore.Definition;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using SepCore.Timer;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
|
|
@ -28,8 +27,6 @@ namespace SepCore.Entity
|
|||
private float _attackRangeSquared;
|
||||
private float _attackCooldown = 1f;
|
||||
private int _attackDamage = 1;
|
||||
private TimerHandle _attackTimerHandle;
|
||||
private bool _canAttack;
|
||||
|
||||
[SerializeField] private float _projectileSpeed = 12f;
|
||||
[SerializeField] private float _projectileLifeTime = 3f;
|
||||
|
|
@ -83,8 +80,7 @@ namespace SepCore.Entity
|
|||
_projectileSpawnHeightOffset);
|
||||
_projectileAssetName = ReadStringParam(ProjectileAssetNameParamKey, _projectileAssetName);
|
||||
|
||||
_canAttack = false;
|
||||
_attackTimerHandle = GameEntry.Timer.ScheduleOnce(_attackCooldown, () => _canAttack = true, this);
|
||||
StartAttackCooldown(_attackCooldown);
|
||||
this.CachedTransform.position = enemyData.Position;
|
||||
}
|
||||
else
|
||||
|
|
@ -112,8 +108,7 @@ namespace SepCore.Entity
|
|||
if (_canAttack)
|
||||
{
|
||||
TryFireProjectile();
|
||||
_canAttack = false;
|
||||
_attackTimerHandle = GameEntry.Timer.ScheduleOnce(_attackCooldown, () => _canAttack = true, this);
|
||||
ResetAttackCooldown(_attackCooldown);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -127,8 +122,7 @@ namespace SepCore.Entity
|
|||
{
|
||||
_movementComponent.OnReset();
|
||||
_healthComponent.OnReset();
|
||||
GameEntry.Timer.Cancel(_attackTimerHandle);
|
||||
_attackTimerHandle = TimerHandle.Invalid;
|
||||
CancelAttackCooldown();
|
||||
|
||||
base.OnHide(isShutdown, userData);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -738,7 +738,7 @@ PrefabInstance:
|
|||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 11499388, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
||||
propertyPath: m_EditorResourceMode
|
||||
value: 1
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 11499388, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
||||
propertyPath: m_JsonHelperTypeName
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@
|
|||
"GUID:d54b9488b03814a44ab937f0aeb738b1",
|
||||
"GUID:75469ad4d38634e559750d17036d5f7c",
|
||||
"GUID:363c5eb08ff8e6a439b85e37b8c20d96",
|
||||
"GUID:436e23dbdc31e7d4fb5c3f804548b2df"
|
||||
"GUID:436e23dbdc31e7d4fb5c3f804548b2df",
|
||||
"GUID:0e1d182005e0ae647ab3fa40f5492dbb"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
|
|
|
|||
|
|
@ -492,7 +492,7 @@ namespace SepCore.Timer
|
|||
return;
|
||||
}
|
||||
|
||||
taskInfo.RemainingTime = taskInfo.Interval;
|
||||
taskInfo.RemainingTime += taskInfo.Interval;
|
||||
}
|
||||
|
||||
private void InvokeCallback(TimerTaskInfo taskInfo)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
UnityConnectSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 1
|
||||
m_Enabled: 0
|
||||
m_Enabled: 1
|
||||
m_TestMode: 0
|
||||
m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events
|
||||
m_EventUrl: https://cdp.cloud.unity3d.com/v1/events
|
||||
|
|
@ -25,7 +25,7 @@ UnityConnectSettings:
|
|||
m_Enabled: 0
|
||||
m_TestMode: 0
|
||||
m_InitializeOnStartup: 1
|
||||
m_PackageRequiringCoreStatsPresent: 0
|
||||
m_PackageRequiringCoreStatsPresent: 1
|
||||
UnityAdsSettings:
|
||||
m_Enabled: 0
|
||||
m_InitializeOnStartup: 1
|
||||
|
|
|
|||
|
|
@ -1,103 +0,0 @@
|
|||
---
|
||||
name: simulation-development
|
||||
description: Maintain, review, refactor, and extend VampireLike SimulationWorld architecture. Use when working on SimulationWorld data ownership, entity lifecycle sync, tick pipeline orchestration, Job/Burst data channels, projectile or area collision settlement, target-selection indexing, presentation write-back, or Simulation regression tests and architecture documentation that must preserve core invariants.
|
||||
---
|
||||
|
||||
# Simulation Development
|
||||
|
||||
1. Read `./references/SimulationDevelopmentSkill.md` first.
|
||||
2. Treat current code as the source of truth when the reference and implementation diverge.
|
||||
3. Load only the source files needed for the task from the map below.
|
||||
4. Keep architecture changes and behavior changes explicit; do not hide them inside unrelated edits.
|
||||
|
||||
## Source Map
|
||||
|
||||
- Core entry: `../../Assets/GameMain/Scripts/Simulation/SimulationWorld.cs`
|
||||
- Sim state lifecycle: `../../Assets/GameMain/Scripts/Simulation/SimulationWorld.SimEntityState.cs`
|
||||
- Entity lifecycle bridge: `../../Assets/GameMain/Scripts/Simulation/SimulationWorld.EntitySync.cs`
|
||||
- Job data channel: `../../Assets/GameMain/Scripts/Simulation/DataChannel/SimulationWorld.JobDataChannel.cs`
|
||||
- Enemy pipeline: `../../Assets/GameMain/Scripts/Simulation/Jobs/SimulationWorld.EnemyJobs.cs`
|
||||
- Projectile pipeline: `../../Assets/GameMain/Scripts/Simulation/Jobs/SimulationWorld.ProjectileJobs.cs`
|
||||
- Collision pipeline: `../../Assets/GameMain/Scripts/Simulation/Jobs/SimulationWorld.CollisionPipeline.cs`
|
||||
- Target selection index: `../../Assets/GameMain/Scripts/Simulation/SimulationWorld.TargetSelectionSpatialIndex.cs`
|
||||
- Transform write-back: `../../Assets/GameMain/Scripts/Simulation/Presentation/SimulationWorld.TransformSync.cs`
|
||||
- Hit presentation bridge: `../../Assets/GameMain/Scripts/Simulation/Presentation/SimulationWorld.HitPresentation.cs`
|
||||
- Tick context: `../../Assets/GameMain/Scripts/Simulation/SimulationTickContext.cs`
|
||||
- Entity index binding: `../../Assets/GameMain/Scripts/Simulation/EntityBinding.cs`
|
||||
- Battle update entry: `../../Assets/GameMain/Scripts/Procedure/Game/GameStateBattle.cs`
|
||||
- Procedure-level cleanup: `../../Assets/GameMain/Scripts/Procedure/Game/ProcedureGame.cs`
|
||||
- Damage and collision utility: `../../Assets/GameMain/Scripts/Utility/AIUtility.cs`
|
||||
- Regression tests:
|
||||
- `../../Assets/Tests/Simulation/EditMode/SimulationWorldTickTests.cs`
|
||||
- `../../Assets/Tests/Simulation/PlayMode/SimulationWorldPlayModeTests.cs`
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Classify the change before editing:
|
||||
- simulation state contract
|
||||
- entity lifecycle mapping
|
||||
- tick pipeline stage
|
||||
- collision or area query semantics
|
||||
- presentation write-back
|
||||
- test or architecture doc maintenance
|
||||
2. Preserve the main boundaries:
|
||||
- `Tick` remains the only simulation logic entry
|
||||
- lifecycle registration and removal remain centralized
|
||||
- logic does not write `Transform`
|
||||
- damage, event dispatch, entity hiding, and recycle stay on the main thread
|
||||
3. Extend data first when behavior depends on new state:
|
||||
- update `SimData`
|
||||
- update job input/output structs
|
||||
- update conversion and initialization paths
|
||||
4. Reuse an existing pipeline stage before adding a new one.
|
||||
5. Update `./references/SimulationDevelopmentSkill.md` when module boundaries, invariants, or execution flow change.
|
||||
6. Add or adjust Simulation tests for every behavior change.
|
||||
|
||||
## Non-Negotiable Invariants
|
||||
|
||||
- Keep `_enemies`, `_projectiles`, and `_pickups` as the persistent source of truth.
|
||||
- Keep `EntityBinding` consistent with container indices.
|
||||
- Use swap-back removal with remap before unbind.
|
||||
- Drive container add/remove only through lifecycle sync and sim state helpers.
|
||||
- Keep target-selection buckets and collision buckets as rebuildable caches, not persistent business state.
|
||||
- Keep area query snapshot semantics intact.
|
||||
- Avoid managed allocations and LINQ in hot paths.
|
||||
|
||||
## Change Guidance
|
||||
|
||||
### Extend Simulation State
|
||||
|
||||
1. Add fields to the relevant sim data and job structs.
|
||||
2. Populate defaults in the lifecycle registration path.
|
||||
3. Flow the data through the execution stage that owns it.
|
||||
4. Consume presentation-only values in Presentation code, not in simulation jobs.
|
||||
|
||||
### Extend Lifecycle Mapping
|
||||
|
||||
1. Add the entity group mapping in `SimulationWorld.EntitySync.cs`.
|
||||
2. Register and unregister through dedicated sim state helpers.
|
||||
3. Preserve clear ownership over which container the entity enters.
|
||||
|
||||
### Extend Tick Pipeline
|
||||
|
||||
1. Place logic inside the smallest existing stage that fits.
|
||||
2. Keep job work data-oriented and side-effect free.
|
||||
3. Apply outputs back to sim state before any presentation write-back.
|
||||
|
||||
### Extend Collision Behavior
|
||||
|
||||
1. Separate broad-phase candidate generation from final settlement.
|
||||
2. Preserve dedup and snapshot behavior on the main thread.
|
||||
3. Route gameplay effects through the existing main-thread settlement path.
|
||||
|
||||
### Extend Presentation
|
||||
|
||||
1. Read simulation output only after logic settlement is complete.
|
||||
2. Do not mutate simulation state from presentation code.
|
||||
|
||||
## Validation
|
||||
|
||||
- Verify index stability after removal paths.
|
||||
- Verify clear/reset paths leave no stale bindings or transient buffers.
|
||||
- Verify behavior under the relevant Simulation tests.
|
||||
- Verify the reference doc still matches the code after architectural edits.
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
interface:
|
||||
display_name: "Simulation Development"
|
||||
short_description: "Extend VampireLike SimulationWorld safely"
|
||||
default_prompt: "Use $simulation-development to implement, review, or extend a SimulationWorld change while preserving architecture invariants."
|
||||
|
|
@ -1,311 +0,0 @@
|
|||
# SimulationWorld Architecture Specification
|
||||
|
||||
## 文档定位
|
||||
本文件是 `SimulationWorld` 的架构规范与扩展开发约束。
|
||||
|
||||
用途分为两部分:
|
||||
- 作为当前 `SimulationWorld` 实现的架构总览,说明模块职责、依赖边界、运行链路和数据所有权。
|
||||
- 作为后续扩展、重构、性能优化和回归修复时的约束文档,防止破坏核心不变量。
|
||||
|
||||
文档与实现冲突时,当前分支源码优先;提交前必须同步修正文档。
|
||||
|
||||
## 适用范围
|
||||
- `Assets/GameMain/Scripts/Simulation/*`
|
||||
- `Assets/GameMain/Scripts/Procedure/Game/GameStateBattle.cs`
|
||||
- `Assets/GameMain/Scripts/Procedure/Game/ProcedureGame.cs`
|
||||
- `Assets/GameMain/Scripts/Utility/AIUtility.cs`
|
||||
- `Assets/Tests/Simulation/EditMode/*`
|
||||
- `Assets/Tests/Simulation/PlayMode/*`
|
||||
|
||||
## 架构目标
|
||||
- 将战斗中的敌人、投射物、掉落物运行时状态收口到统一仿真容器。
|
||||
- 将热路径逻辑与 Unity 表现层解耦,避免在仿真阶段直接读写 `Transform`。
|
||||
- 为 Job/Burst 提供稳定的数据通道、生命周期管理和主线程结算收口点。
|
||||
- 保持 `SimulationWorld` 对外是单一战斗调度入口,而不是分散的业务入口集合。
|
||||
- 保证扩展新仿真对象或新碰撞规则时,能够沿着既有管线接入,而不是旁路修改。
|
||||
|
||||
## 非目标
|
||||
- 不负责完整战斗规则定义。伤害公式、碰撞业务语义仍由 `AIUtility` 和实体逻辑承担。
|
||||
- 不负责实体创建策略。实体创建与隐藏仍由外部流程和 Entity 系统负责。
|
||||
- 不追求全局 ECS 化。本模块仍以 `SimulationWorld + partial + Native 容器` 为中心组织。
|
||||
- 不在 Job 中直接驱动表现层、事件系统或 Unity 对象生命周期。
|
||||
|
||||
## 外部依赖与系统边界
|
||||
`SimulationWorld` 处于战斗流程中层,位于 `GameStateBattle` 和具体实体逻辑之间。
|
||||
|
||||
上游依赖:
|
||||
- `GameStateBattle.OnUpdate` 驱动每帧 `Tick`。
|
||||
- `GameEntry.Event` 提供实体显示/隐藏事件,用于同步仿真容器生命周期。
|
||||
- `GameEntry.Entity` 提供实体查询、隐藏和表现事件消费。
|
||||
|
||||
下游协作:
|
||||
- `AIUtility` 负责伤害与碰撞业务结算。
|
||||
- Enemy/Projectile/Drop 实体提供初始化所需运行时数据。
|
||||
- Presentation 子模块负责把仿真结果写回表现层。
|
||||
|
||||
边界要求:
|
||||
- 外部业务代码不得直接增删 `_enemies`、`_projectiles`、`_pickups`。
|
||||
- 外部业务代码不得绕过 `SimulationWorld` 直接维护仿真索引。
|
||||
- `SimulationWorld` 不直接拥有实体生成权,只消费实体生命周期事件。
|
||||
|
||||
## 模块结构
|
||||
`SimulationWorld` 使用 `partial` 拆分,职责按以下边界划分:
|
||||
|
||||
- `SimulationWorld.cs`
|
||||
- 核心组件入口、主状态容器、基础依赖、Unity 生命周期入口。
|
||||
- `SimulationWorld.SimEntityState.cs`
|
||||
- 敌人、投射物、掉落物的仿真态创建、更新、删除和清空。
|
||||
- `SimulationWorld.EntitySync.cs`
|
||||
- 监听实体 show/hide 事件,将实体生命周期映射到仿真容器。
|
||||
- `DataChannel/SimulationWorld.JobDataChannel.cs`
|
||||
- Native 容器持有、初始化、清理、容量准备、仿真数据到 Job 数据的转换。
|
||||
- `Jobs/SimulationWorld.EnemyJobs.cs`
|
||||
- 每帧仿真主编排、敌人移动与互斥分离 Job 调度。
|
||||
- `Jobs/SimulationWorld.ProjectileJobs.cs`
|
||||
- 投射物移动、寿命处理、越界回收。
|
||||
- `Jobs/SimulationWorld.CollisionPipeline.cs`
|
||||
- 投射物与区域碰撞查询构建、候选筛选、主线程命中结算。
|
||||
- `SimulationWorld.TargetSelectionSpatialIndex.cs`
|
||||
- 敌人目标选择空间索引。
|
||||
- `Presentation/SimulationWorld.TransformSync.cs`
|
||||
- `LateUpdate` 表现写回。
|
||||
- `Presentation/SimulationWorld.HitPresentation.cs`
|
||||
- 命中事件的表现消费桥。
|
||||
|
||||
## 核心数据所有权
|
||||
### 主容器
|
||||
- `_enemies`
|
||||
- `_projectiles`
|
||||
- `_pickups`
|
||||
|
||||
这些容器是真实仿真态所有者。Job 输入输出缓冲只是当前帧的镜像通道,不是持久源数据。
|
||||
|
||||
### 绑定关系
|
||||
- `EntityBinding` 维护 `EntityId <-> SimulationIndex` 双向映射。
|
||||
- 容器删除使用 `swap-back`。
|
||||
- 发生尾元素覆盖时,必须同步 `RemapIndex`。
|
||||
- 删除完成后再 `Unbind`,避免索引悬挂。
|
||||
|
||||
### Native 容器
|
||||
- Job 通道一律使用 `Allocator.Persistent`。
|
||||
- 生命周期由 `InitializeJobDataChannels` / `DisposeJobDataChannels` 集中管理。
|
||||
- 帧间复用时使用 `Clear`,不允许用临时重建替代正常复用。
|
||||
- Job 数据与主容器数据之间的转换必须集中在 `JobDataChannel` 侧完成。
|
||||
|
||||
## 生命周期模型
|
||||
### 实体进入仿真
|
||||
统一由 `EntitySync` 监听实体显示事件后触发:
|
||||
- Enemy group -> `RegisterEnemyLifecycle`
|
||||
- Drop group -> `RegisterPickupLifecycle`
|
||||
- Bullet / Projectile / EnemyProjectile group -> `RegisterProjectileLifecycle`
|
||||
|
||||
### 实体退出仿真
|
||||
统一由 `EntitySync` 监听实体隐藏事件后触发:
|
||||
- Enemy -> `UnregisterEnemyLifecycle`
|
||||
- Drop -> `UnregisterPickupLifecycle`
|
||||
- Projectile 相关 group -> `UnregisterProjectileLifecycle`
|
||||
|
||||
### 清场
|
||||
`ClearSimulationState` 负责:
|
||||
- 清空主容器
|
||||
- 清空投射物回收与结算缓存
|
||||
- 清空区域碰撞请求与命中缓存
|
||||
- 清空 Job 通道
|
||||
- 清空全部 `EntityBinding`
|
||||
|
||||
## 运行时执行链路
|
||||
### 帧级入口
|
||||
1. `GameStateBattle.OnUpdate`
|
||||
2. `_enemyManager.OnUpdate(...)`
|
||||
3. `SimulationWorld.Tick(...)`
|
||||
4. `SimulationWorld.LateUpdate()`
|
||||
|
||||
### Tick 总流程
|
||||
`SimulationWorld.Tick` 是战斗仿真的唯一主入口。
|
||||
|
||||
约束:
|
||||
- 当 `UseSimulationMovement == false` 时,直接返回。
|
||||
- `Tick` 只负责逻辑仿真与结算,不直接写 `Transform`。
|
||||
|
||||
### 每帧仿真管线
|
||||
当前实现的标准顺序为:
|
||||
1. Early Return
|
||||
- `DeltaTime <= 0` 时只清理碰撞临时通道和统计。
|
||||
2. BuildInput
|
||||
- 将 `_enemies` / `_projectiles` 同步为 Job 输入。
|
||||
- 准备敌人输出、投射物输出、碰撞查询缓冲。
|
||||
3. StateUpdate
|
||||
- 调度敌人移动 Job。
|
||||
- 调度投射物移动 Job。
|
||||
4. Schedule
|
||||
- 按需调度敌人互斥分离 Job。
|
||||
- 合并敌人与投射物 Job 依赖。
|
||||
5. Complete
|
||||
- 等待本帧仿真 Job 完成。
|
||||
6. Collision
|
||||
- 构建碰撞查询。
|
||||
- 构建敌人碰撞桶。
|
||||
- 生成候选并统计。
|
||||
7. WriteBack
|
||||
- 把输出写回主容器。
|
||||
- 在主线程结算碰撞与伤害。
|
||||
- 回收失效投射物。
|
||||
|
||||
### LateUpdate
|
||||
`LateUpdate` 只做表现写回,不做逻辑判定:
|
||||
- 敌人位置/朝向写回
|
||||
- 投射物位置/朝向写回
|
||||
|
||||
## 线程模型与边界
|
||||
### Job/Burst 允许做的事
|
||||
- 读取 Job 输入缓冲
|
||||
- 写入 Job 输出缓冲
|
||||
- 写入 NativeHashMap / NativeList 等碰撞与分桶数据
|
||||
- 执行纯数据计算
|
||||
|
||||
### Job/Burst 禁止做的事
|
||||
- 读写 `Transform`
|
||||
- 操作 GameObject / Entity 生命周期
|
||||
- 调用事件系统
|
||||
- 直接调用 `AIUtility.PerformCollision`
|
||||
- 进行托管分配、LINQ、装箱
|
||||
|
||||
### 主线程必须做的事
|
||||
- 应用输出到仿真主容器
|
||||
- 命中结算与伤害计算
|
||||
- 投射物失效回收
|
||||
- 命中表现事件派发
|
||||
- `LateUpdate` 表现写回
|
||||
|
||||
## 子系统约束
|
||||
### 敌人仿真
|
||||
固定接入点:
|
||||
- BuildInput
|
||||
- Movement
|
||||
- Separation
|
||||
- WriteBack
|
||||
|
||||
约束:
|
||||
- 敌人状态必须以 `EnemySimData` 为中心流动。
|
||||
- 互斥与移动结果必须先写入输出缓冲,再统一提交。
|
||||
- 与目标选择相关的空间索引脏标记必须在主容器变更时维护。
|
||||
|
||||
### 投射物仿真
|
||||
固定接入点:
|
||||
- BuildInput
|
||||
- Movement
|
||||
- Collision Query
|
||||
- Resolve
|
||||
- Recycle
|
||||
|
||||
约束:
|
||||
- 投射物生命周期状态必须由 `ProjectileSimData.Active` 和 `State` 共同表达。
|
||||
- 投射物实际隐藏与移除只能在主线程回收阶段完成。
|
||||
|
||||
### 碰撞管线
|
||||
职责:
|
||||
- 构建投射物查询和区域查询
|
||||
- 生成 broad-phase 候选
|
||||
- 在主线程做最终业务结算
|
||||
|
||||
约束:
|
||||
- Broad-phase 只能筛候选,不能替代最终命中判定。
|
||||
- Area Query 必须保留 `SourceWasActiveAtQueryTime` 快照语义。
|
||||
- 候选去重与区域命中去重只能在主线程收口。
|
||||
|
||||
### 目标选择空间索引
|
||||
职责:
|
||||
- 提供按位置查询最近敌人的能力。
|
||||
|
||||
约束:
|
||||
- 仅在仿真启用时对外提供结果。
|
||||
- 敌人主容器变更后必须标记脏。
|
||||
- 索引是缓存,不是源数据;源数据仍是 `_enemies`。
|
||||
|
||||
### Presentation
|
||||
职责:
|
||||
- 将仿真层结果写回表现层。
|
||||
- 消费命中表现事件。
|
||||
|
||||
约束:
|
||||
- Presentation 只消费仿真结果,不反向修改仿真逻辑状态。
|
||||
- 任何新增表现都应接在 `Presentation` 子模块,而不是接回 Job 或业务结算热路径。
|
||||
|
||||
## 不可破坏的不变量
|
||||
### 生命周期单入口
|
||||
仿真容器的增删必须只经过 `EntitySync` 和 `SimEntityState`。
|
||||
|
||||
### 数据单一事实来源
|
||||
主容器是持续态事实来源,Job 缓冲只是帧级副本。
|
||||
|
||||
### 逻辑与表现分离
|
||||
逻辑阶段不写 `Transform`,表现阶段不做业务结算。
|
||||
|
||||
### 索引一致性
|
||||
任何 `swap-back` 删除都必须同步 remap,否则视为架构级错误。
|
||||
|
||||
### 主线程结算收口
|
||||
伤害、事件派发、实体隐藏和回收必须回到主线程。
|
||||
|
||||
### 空间索引与碰撞桶是缓存
|
||||
它们可以重建,不可被外部业务当作持久数据依赖。
|
||||
|
||||
## 扩展开发流程
|
||||
### Step 0:判定接入位置
|
||||
先判断新需求属于:
|
||||
- 新仿真态字段
|
||||
- 新执行阶段逻辑
|
||||
- 新碰撞查询类型
|
||||
- 新表现桥接
|
||||
|
||||
不要一开始就直接改 `Tick` 主流程。
|
||||
|
||||
### Step 1:扩状态
|
||||
先补 `SimData`、必要的 Job 输入输出结构和转换逻辑。
|
||||
|
||||
### Step 2:接生命周期
|
||||
如果是新实体类型,先定义 show/hide 到仿真态的映射,再进入执行阶段。
|
||||
|
||||
### Step 3:接执行管线
|
||||
优先复用已有阶段;只有确实无法收纳时才新增阶段,并补可观测的 profiler 标记。
|
||||
|
||||
### Step 4:接主线程结算
|
||||
需要业务判定、伤害、事件派发、实体隐藏时,一律回主线程收口。
|
||||
|
||||
### Step 5:接表现
|
||||
视觉写回、命中反馈、临时特效都放在 `Presentation` 侧。
|
||||
|
||||
### Step 6:补测试
|
||||
至少覆盖:
|
||||
- 正常行为
|
||||
- 空容器和边界条件
|
||||
- 删除后的索引稳定性
|
||||
- 碰撞去重或快照语义
|
||||
- 与旧路径一致的关键行为
|
||||
|
||||
### Step 7:更新文档
|
||||
修改模块边界、数据契约、不变量或执行阶段时,必须同步更新本文件。
|
||||
|
||||
## 回归关注点
|
||||
- `ClearSimulationState` 是否把主容器、缓存和 binding 一并清干净。
|
||||
- 删除路径是否保持 `swap-back + remap` 一致。
|
||||
- Job Native 容器是否有泄漏或容量管理回退。
|
||||
- 是否在热路径引入托管分配。
|
||||
- 是否让表现逻辑重新侵入仿真逻辑。
|
||||
- 是否破坏 Area Query 快照语义。
|
||||
- 是否破坏碰撞候选与命中去重。
|
||||
|
||||
## 测试建议
|
||||
至少保留并持续扩展以下类型的测试:
|
||||
- Tick 行为正确性
|
||||
- 主线程与 Job 管线一致性
|
||||
- 最近敌查询正确性
|
||||
- 投射物候选上限与玩家候选覆盖
|
||||
- Area Query 快照语义
|
||||
- 清场和 Battle 循环稳定性
|
||||
|
||||
## 维护原则
|
||||
如果未来需要继续扩展为多模式仿真开关、更多 Job 管线层级或新的仿真对象类型,应优先维护以下三点:
|
||||
- `Tick` 仍然只有一个主入口
|
||||
- 仿真态生命周期仍然只有一个注册/反注册入口
|
||||
- 主线程结算与表现写回边界不被打穿
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
---
|
||||
name: ui-five-layer-architecture
|
||||
description: Define, review, and refactor UI modules using a strict five-layer architecture (UseCase, RawData, Controller, Context, View). Use when creating cross-project UI architecture standards, designing new UI modules, reviewing layer boundaries and event flow, converting ad-hoc UI code into layered structure, or validating UI test strategy for business-driven interfaces.
|
||||
---
|
||||
|
||||
# UI Five-Layer Architecture
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. Read `./references/ui-five-layer-standard.md`.
|
||||
2. Classify the UI as `standard-five-layer` or `lightweight`.
|
||||
3. Apply boundary rules before editing code or writing design output.
|
||||
4. Use the checklists in this file to drive design, review, or refactor tasks.
|
||||
|
||||
## Workflow
|
||||
|
||||
### 1. Scope the task
|
||||
|
||||
Decide which mode the user needs:
|
||||
|
||||
- architecture-spec mode: create or revise a UI architecture standard
|
||||
- design mode: design one or more UI modules before coding
|
||||
- implementation mode: implement or refactor code to match the standard
|
||||
- review mode: audit existing code for boundary or dependency violations
|
||||
|
||||
### 2. Choose module level
|
||||
|
||||
Use `standard-five-layer` when UI owns business state transitions, validations, or branching behavior.
|
||||
|
||||
Use `lightweight` when UI only handles display/navigation and has no independent business rules.
|
||||
|
||||
### 3. Enforce non-negotiable boundaries
|
||||
|
||||
Apply these constraints in every mode:
|
||||
|
||||
- keep `UseCase` business-only and return only `RawData/Result`
|
||||
- build `Context` only inside `Controller`
|
||||
- keep `View` presentation-only and event-emitting only
|
||||
- keep `View` out of global business event subscriptions
|
||||
- route external UI open/close/refresh through `Controller`
|
||||
|
||||
### 4. Apply communication and dependency checks
|
||||
|
||||
Validate:
|
||||
|
||||
- dependency direction is valid for all touched files
|
||||
- UI-specific events stay UI-local in meaning
|
||||
- `Controller` filters sender and instance scope when needed
|
||||
- no `RawData` field uses `*Context` types
|
||||
|
||||
### 5. Produce mode-specific output
|
||||
|
||||
- architecture-spec mode:
|
||||
- output the final standard text
|
||||
- include strict rules, permitted exceptions, and checklists
|
||||
- design mode:
|
||||
- output layer map and flow diagram for each UI module
|
||||
- include type list and event list
|
||||
- implementation mode:
|
||||
- implement code changes matching the standard
|
||||
- update tests if `UseCase` behavior changes
|
||||
- review mode:
|
||||
- report findings first, ordered by severity
|
||||
- include concrete file and line references
|
||||
|
||||
## Architecture Checklist
|
||||
|
||||
Use this list before closing any task:
|
||||
|
||||
1. Classify each UI module correctly: `standard-five-layer` or `lightweight`.
|
||||
2. Ensure `UseCase` does not construct `Context` or touch view concerns.
|
||||
3. Ensure `RawData` does not include `*Context` or presentation types.
|
||||
4. Ensure `Controller` owns all `RawData/Result -> Context` transformation.
|
||||
5. Ensure `View` only consumes `Context` and emits UI-local events.
|
||||
6. Ensure external open/close/update operations enter through `Controller`.
|
||||
7. Ensure event ownership and sender filtering are explicit.
|
||||
8. Ensure test approach matches policy in the reference file.
|
||||
|
||||
## References
|
||||
|
||||
Read `./references/ui-five-layer-standard.md` for the full specification.
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
interface:
|
||||
display_name: "UI Five-Layer Architecture"
|
||||
short_description: "Cross-project UI five-layer architecture standards"
|
||||
default_prompt: "Use $ui-five-layer-architecture to define, review, or refactor a UI module with clear five-layer boundaries."
|
||||
|
|
@ -1,274 +0,0 @@
|
|||
# UI Five-Layer Architecture Standard
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Scope and Intent](#scope-and-intent)
|
||||
2. [Core Model](#core-model)
|
||||
3. [Layer Definitions](#layer-definitions)
|
||||
4. [UI Module Levels](#ui-module-levels)
|
||||
5. [Dependency Rules](#dependency-rules)
|
||||
6. [Event Communication Rules](#event-communication-rules)
|
||||
7. [Interaction Flow](#interaction-flow)
|
||||
8. [Naming and Folder Conventions](#naming-and-folder-conventions)
|
||||
9. [Testing Policy](#testing-policy)
|
||||
10. [Anti-Patterns](#anti-patterns)
|
||||
11. [Delivery Checklist](#delivery-checklist)
|
||||
|
||||
## Scope and Intent
|
||||
|
||||
Use this standard to define and enforce a stable UI architecture that can be reused across projects.
|
||||
|
||||
Primary goals:
|
||||
|
||||
- keep business logic independent from UI rendering
|
||||
- keep UI rendering deterministic and testable
|
||||
- make reviews and refactors consistent
|
||||
- reduce coupling and regression risk
|
||||
|
||||
## Core Model
|
||||
|
||||
Base chain:
|
||||
|
||||
```text
|
||||
External Flow
|
||||
-> Controller
|
||||
-> UseCase
|
||||
-> RawData / Result
|
||||
-> BuildContext
|
||||
-> View
|
||||
|
||||
View
|
||||
--(UI-local event)--> Controller
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
- `UseCase` produces business outputs only.
|
||||
- `Controller` is the only layer that creates `Context`.
|
||||
- `View` only renders and emits interaction events.
|
||||
|
||||
## Layer Definitions
|
||||
|
||||
### UseCase
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- own business rules and state transitions
|
||||
- validate business actions
|
||||
- return `RawData` or result objects
|
||||
|
||||
Constraints:
|
||||
|
||||
- do not depend on `Context`, `View`, or rendering types
|
||||
- do not format display strings or map visual assets
|
||||
- do not publish UI-local events
|
||||
|
||||
### RawData
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- carry business data from `UseCase` to `Controller`
|
||||
|
||||
Constraints:
|
||||
|
||||
- keep data business-oriented
|
||||
- do not reference any `*Context` type
|
||||
- do not contain rendering objects (for example UI components)
|
||||
|
||||
### Controller
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- be the external entry point for open/close/refresh
|
||||
- bind and call `UseCase`
|
||||
- transform `RawData/Result` into `Context`
|
||||
- subscribe/unsubscribe UI-local events
|
||||
- coordinate full or partial refresh
|
||||
|
||||
Constraints:
|
||||
|
||||
- do not let `View` bypass controller orchestration
|
||||
- do not hide heavy business logic that belongs in `UseCase`
|
||||
|
||||
### Context
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- carry display-ready data for rendering
|
||||
|
||||
Constraints:
|
||||
|
||||
- construct/update only in `Controller`
|
||||
- do not enter `UseCase`
|
||||
- allow composition (`FormContext`, `ItemContext`, `AreaContext`)
|
||||
|
||||
### View
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- bind controls and render `Context`
|
||||
- emit UI-local interaction events
|
||||
|
||||
Constraints:
|
||||
|
||||
- do not call `UseCase`
|
||||
- do not mutate domain state
|
||||
- do not subscribe to global business events
|
||||
- do not become external entry points
|
||||
|
||||
## UI Module Levels
|
||||
|
||||
### Standard Five-Layer Module
|
||||
|
||||
Structure:
|
||||
|
||||
- `UseCase + RawData + Controller + Context + View`
|
||||
|
||||
Use when:
|
||||
|
||||
- module owns business rules, validations, or branching state transitions
|
||||
- user actions mutate domain state
|
||||
- behavior requires automated verification
|
||||
|
||||
### Lightweight Module
|
||||
|
||||
Structure:
|
||||
|
||||
- `Controller + Context + View`
|
||||
|
||||
Use when:
|
||||
|
||||
- module is display/navigation/confirmation only
|
||||
- no independent business rules are present
|
||||
|
||||
Rule:
|
||||
|
||||
- upgrade to standard five-layer as soon as business rules appear
|
||||
|
||||
## Dependency Rules
|
||||
|
||||
Allowed:
|
||||
|
||||
- `UseCase -> domain/services/RawData/Result`
|
||||
- `Controller -> UseCase/RawData/Result/Context/View/UI-local events`
|
||||
- `Context -> child context/value objects`
|
||||
- `View -> Context/UI-local events`
|
||||
|
||||
Forbidden:
|
||||
|
||||
- `UseCase -> Context/View/rendering types`
|
||||
- `RawData/Result -> Context/View`
|
||||
- `Context -> UseCase/View`
|
||||
- `View -> UseCase`
|
||||
- `View -> global business events`
|
||||
- `View -> domain state mutation`
|
||||
|
||||
## Event Communication Rules
|
||||
|
||||
### Event Ownership
|
||||
|
||||
- `View -> Controller` uses UI-local events only
|
||||
- UI-local events are not global business contracts
|
||||
- business/domain modules must not consume UI-local event semantics
|
||||
|
||||
### Safety Requirements
|
||||
|
||||
- validate sender ownership in `Controller`
|
||||
- scope handling to the active UI instance
|
||||
- keep subscribe/unsubscribe symmetric
|
||||
|
||||
## Interaction Flow
|
||||
|
||||
### Standard Module
|
||||
|
||||
```text
|
||||
External Flow
|
||||
-> create/bind UseCase
|
||||
-> open UI via Controller
|
||||
|
||||
Controller
|
||||
-> UseCase action
|
||||
-> RawData/Result
|
||||
-> BuildContext
|
||||
-> View refresh
|
||||
|
||||
View
|
||||
--(UI-local event)--> Controller
|
||||
```
|
||||
|
||||
### Lightweight Module
|
||||
|
||||
```text
|
||||
External Flow
|
||||
-> open UI via Controller(userData)
|
||||
|
||||
Controller
|
||||
-> BuildContext(userData)
|
||||
-> View refresh
|
||||
|
||||
View
|
||||
--(UI-local event)--> Controller
|
||||
```
|
||||
|
||||
## Naming and Folder Conventions
|
||||
|
||||
Recommended folders:
|
||||
|
||||
- `UI/<Domain>/UseCase`
|
||||
- `UI/<Domain>/RawData`
|
||||
- `UI/<Domain>/Controller`
|
||||
- `UI/<Domain>/Context`
|
||||
- `UI/<Domain>/View`
|
||||
|
||||
Recommended naming:
|
||||
|
||||
- `XXXFormUseCase`
|
||||
- `XXXFormRawData`
|
||||
- `XXXFormController`
|
||||
- `XXXFormContext`, `XXXItemContext`, `XXXAreaContext`
|
||||
- `XXXResult`, `XXXActionResult`
|
||||
|
||||
## Testing Policy
|
||||
|
||||
Policy:
|
||||
|
||||
- if a UI has a `UseCase` and automated tests are added, use EditMode tests for the `UseCase`
|
||||
|
||||
Priority coverage:
|
||||
|
||||
- initial model generation
|
||||
- business branch and validation behavior
|
||||
- action result correctness
|
||||
- boundary and invalid input handling
|
||||
|
||||
Manual verification focus:
|
||||
|
||||
- first open
|
||||
- interaction refresh
|
||||
- partial refresh
|
||||
- close and reopen
|
||||
- null/invalid userData behavior
|
||||
|
||||
## Anti-Patterns
|
||||
|
||||
Do not allow:
|
||||
|
||||
- `UseCase` returning `Context`
|
||||
- `RawData` carrying `*Context`
|
||||
- `View` subscribing global business events
|
||||
- direct domain mutation inside `View`
|
||||
- skipping `Controller` as module entry
|
||||
- module marked lightweight while carrying business state transitions
|
||||
|
||||
## Delivery Checklist
|
||||
|
||||
Use this checklist before marking work complete:
|
||||
|
||||
1. classify each module as standard or lightweight
|
||||
2. verify business rules sit in `UseCase` only
|
||||
3. verify `Context` is built only in `Controller`
|
||||
4. verify `RawData` has no presentation model leakage
|
||||
5. verify `View` is render-and-emit only
|
||||
6. verify UI-local events are scoped and sender-checked
|
||||
7. verify dependency direction constraints pass
|
||||
8. verify tests/manual checks match the testing policy
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
---
|
||||
name: weapon-development
|
||||
description: Develop and extend the VampireLike weapon system. Use when creating new weapons, updating weapon state machines, changing target selection/effects/data parsing, or integrating weapon behavior with shop, inventory, and entity flow.
|
||||
---
|
||||
|
||||
# Weapon Development
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. Read full baseline spec: `./references/WeaponDevelopmentSkill.md`.
|
||||
2. Confirm change scope:
|
||||
- weapon runtime (`WeaponBase`, concrete weapons)
|
||||
- state flow (`Idle`, `Check_OutRange`, `Check_InRange`, `Attack`)
|
||||
- target selector (`ITargetSelector`, `TargetSelectorType`)
|
||||
- effect layer (`IWeaponAttackEffect`)
|
||||
- data contract (`DRWeapon`, `WeaponData`, `ParamsData`)
|
||||
3. Keep behavior compatibility with current gameplay loop, shop flow, inventory flow, and UI/event chain.
|
||||
|
||||
## Source Map
|
||||
|
||||
- Weapon base:
|
||||
- `../../Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponBase.cs`
|
||||
- Existing weapons:
|
||||
- `../../Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponKnife/`
|
||||
- `../../Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponHandgun/`
|
||||
- `../../Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponSlash/`
|
||||
- `../../Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponLightning/`
|
||||
- Selectors:
|
||||
- `../../Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/TargetSelector/`
|
||||
- Attack effects:
|
||||
- `../../Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/AttackEffects/`
|
||||
- Weapon data:
|
||||
- `../../Assets/GameMain/Scripts/Entity/EntityData/Weapon/`
|
||||
- Weapon table:
|
||||
- `../../Assets/GameMain/DataTables/Weapon.txt`
|
||||
- Data row:
|
||||
- `../../Assets/GameMain/Scripts/DataTable/DRWeapon.cs`
|
||||
- Shop integration:
|
||||
- `../../Assets/GameMain/Scripts/UI/GameScene/UseCase/ShopFormUseCase.cs`
|
||||
- Entity show flow:
|
||||
- `../../Assets/GameMain/Scripts/Entity/EntityExtension.cs`
|
||||
|
||||
## Non-Negotiable Invariants
|
||||
|
||||
- Do not duplicate logic already owned by `WeaponBase`.
|
||||
- Keep state transitions explicit and non-blocking.
|
||||
- Keep cooldown accumulation valid even when no target is found.
|
||||
- Keep attack logic and visual effect logic decoupled.
|
||||
- Parse weapon-specific parameters into strong-typed `ParamsData` at data initialization time.
|
||||
- Treat `Weapon.txt` `Params` as a JSON object column; empty params must use `{}`.
|
||||
- Preserve compatibility with shop/inventory/UI refresh flow.
|
||||
|
||||
## Change Recipes
|
||||
|
||||
### Add a New Weapon
|
||||
|
||||
1. Extend `WeaponType` without reordering existing enum values.
|
||||
2. Add `WeaponXxxData : WeaponData` and `WeaponXxxParamsData` for weapon-specific parameters.
|
||||
3. Parse `ParamsJson` through `ParseParams<TParams>()` inside the weapon data constructor.
|
||||
4. Add `WeaponXxx : WeaponBase` and implement only weapon-specific behavior.
|
||||
5. Build state files under `Weapon/WeaponXxx/` with partial class layout.
|
||||
6. Register display/data mapping path so `ShowWeapon` and shop purchase can instantiate correctly.
|
||||
|
||||
### Add or Update a Target Selector
|
||||
|
||||
1. Implement `ITargetSelector`.
|
||||
2. Update `TargetSelectorType`.
|
||||
3. Register creation in `WeaponBase.CreateSelector`.
|
||||
4. Validate target semantics with current-health/runtime-health rules where applicable.
|
||||
|
||||
### Add or Update Attack Effect
|
||||
|
||||
1. Implement `IWeaponAttackEffect`.
|
||||
2. Trigger effect from weapon attack state only.
|
||||
3. Keep damage resolution outside effect code.
|
||||
|
||||
### Add or Update Weapon Parameters
|
||||
|
||||
1. Update `Weapon.txt` `Params` JSON object.
|
||||
2. Add or update the corresponding `WeaponXxxParamsData` fields.
|
||||
3. Keep key names aligned with `ParamsData` property names.
|
||||
4. Read values from `ParamsData` in weapon initialization, not by manual string parsing in runtime logic.
|
||||
|
||||
## Validation Checklist
|
||||
|
||||
- Weapon can be shown, attached, and updated without exceptions.
|
||||
- State machine does not stall across target loss/reacquire.
|
||||
- Cooldown and range checks match design expectation.
|
||||
- Damage path and effect path remain decoupled.
|
||||
- `ParamsData` matches table content and default fallback behavior.
|
||||
- UI/shop/inventory interactions stay stable after the change.
|
||||
- Update `./references/WeaponDevelopmentSkill.md` if contracts or recommended patterns changed.
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
interface:
|
||||
display_name: "Weapon Development"
|
||||
short_description: "Build and extend VampireLike weapon architecture"
|
||||
default_prompt: "Use $weapon-development to implement a weapon system change with stable state flow and data contracts."
|
||||
|
|
@ -1,262 +0,0 @@
|
|||
# Weapon Development Skill(VampireLike)
|
||||
|
||||
## 目标
|
||||
本文件是 `Entity.Weapon` 体系的开发规范与速查手册。
|
||||
后续新增武器、扩展参数、调整状态机或联动商店/背包时,优先按本文档执行,避免重复通读历史上下文。
|
||||
|
||||
## 当前架构总览
|
||||
- 武器运行时入口:`WeaponBase`(`Assets/GameMain/Scripts/Entity/EntityLogic/Weapon/WeaponBase.cs`)
|
||||
- 武器具体实现:`WeaponKnife`、`WeaponHandgun`、`WeaponSlash`、`WeaponLightning`
|
||||
- 目标选择策略:`ITargetSelector` + `TargetSelectorType`
|
||||
- 攻击可视化:`IWeaponAttackEffect`
|
||||
- 数据入口:`DRWeapon` -> `WeaponData`(及其子类)
|
||||
- 实体生成:`EntityExtension.ShowWeapon`
|
||||
- 商店接入:`ShopFormUseCase.CreateWeaponData`
|
||||
|
||||
## WeaponBase 统一职责(已上收)
|
||||
`WeaponBase` 负责以下通用逻辑,子类不要重复实现:
|
||||
- 生命周期模板:`OnShow/OnHide/OnAttachTo/OnDetachFrom`
|
||||
- 状态机管理:`RegisterState`、`EnsureStatesBuilt`、`TransitionTo`
|
||||
- 通用运行字段:`_target`、`_currAttackTimer`、`_sqrRange`
|
||||
- 启用门控:`OnUpdate` 中统一 `if (!_isEnabled) return`
|
||||
- 目标选择入口:`SelectTarget`、`SetTargetSelector`、`CreateSelector`
|
||||
- 距离判定:`IsInRange`(基于 XZ 平面距离)
|
||||
- Simulation 命中请求:`TryQueueAreaCollisionQuery`、`TryQueueSectorCollisionQuery`
|
||||
- 玩家攻击属性订阅:`BindAttackStatFromOwner` / `ReleaseAttackStatSubscription`
|
||||
|
||||
约束:
|
||||
- 不要在子类里重复实现 `WeaponBase` 已有能力。
|
||||
- 行为差异优先收敛在:`BuildStates`、`Check`、`Attack`、少量专属辅助方法。
|
||||
|
||||
## 当前武器模板分类
|
||||
### 1. `WeaponKnife`
|
||||
- 模式:近身前刺 + 圆形范围命中
|
||||
- 典型参数:`HitRadius`
|
||||
- 适合派生:长枪、刺剑、短矛、震地锤近身版
|
||||
|
||||
### 2. `WeaponHandgun`
|
||||
- 模式:单次 `Raycast` 瞬发命中
|
||||
- 当前参数化程度较低,仍适合作为远程枪械母版继续扩展
|
||||
- 适合派生:手枪、霰弹枪、狙击枪、三连发枪
|
||||
|
||||
### 3. `WeaponSlash`
|
||||
- 模式:扇形范围命中
|
||||
- 典型参数:`SectorAngle`
|
||||
- 适合派生:大剑、斧头、半月斩、横扫类武器
|
||||
|
||||
### 4. `WeaponLightning`
|
||||
- 模式:锁定目标点 + 落点范围打击
|
||||
- 典型参数:`HitRadius`、`HoverHeight`
|
||||
- 适合派生:闪电、陨石杖、圣光柱、空袭类武器
|
||||
|
||||
## 状态机约定
|
||||
统一状态枚举:
|
||||
- `Idle`
|
||||
- `Check_OutRange`
|
||||
- `Check_InRange`
|
||||
- `Attack`
|
||||
- `Disabled`(可选)
|
||||
|
||||
推荐流程:
|
||||
1. `Idle`:查找目标,计时器持续累积。
|
||||
2. `Check_OutRange`:有目标但不在攻击范围,继续转向并累积计时。
|
||||
3. `Check_InRange`:在攻击范围内,若 `currAttackTimer >= Cooldown` 切 `Attack`。
|
||||
4. `Attack`:执行攻击,重置计时器,结束后回 `Check_InRange`。
|
||||
|
||||
关键规则:
|
||||
- 即使没有目标,也允许蓄力(计时器持续走)。
|
||||
- 一旦进入 `Check_InRange` 且冷却已满,应立即触发攻击。
|
||||
- 攻击过程中若需要多帧动画,使用 `_isAttacking` 控制状态退出时机。
|
||||
|
||||
## 3D 场景下的距离/朝向原则
|
||||
- 射程与目标筛选:优先使用 XZ 平面距离(忽略 Y),调用 `AIUtility.GetSqrMagnitudeXZ`。
|
||||
- 视觉朝向与弹道:可按武器设计决定是否使用完整 3D 向量。
|
||||
- `WeaponHandgun`:允许俯仰瞄准,逻辑上用射线命中对象判定伤害。
|
||||
- 近战地面范围类(Knife/Slash):伤害检测建议投影到地面(XZ)再判定。
|
||||
- 落点类(Lightning):锁点可取目标当前位置,但范围判定仍建议按地面距离收口。
|
||||
|
||||
## 目标选择策略规范
|
||||
接口:`ITargetSelector.SelectTarget(WeaponBase weapon, IEnumerable<EntityBase> candidates, float maxSqrRange)`
|
||||
|
||||
现有策略:
|
||||
- `NearestTargetSelector`
|
||||
- `HighestHealthTargetSelector`
|
||||
- `LowestHealthTargetSelector`
|
||||
|
||||
语义约定:
|
||||
- `NearestTargetSelector` 在 Simulation 启用时优先走空间索引。
|
||||
- `HighestHealth` / `LowestHealth` 当前基于运行时生命值选择目标。
|
||||
- 若新增新策略,必须明确“按当前值”还是“按最大值”筛选,避免语义漂移。
|
||||
|
||||
扩展策略步骤:
|
||||
1. 新建 selector 类并实现 `ITargetSelector`。
|
||||
2. 更新 `TargetSelectorType` 枚举。
|
||||
3. 在 `WeaponBase.CreateSelector` 中注册。
|
||||
4. 武器在 `OnWeaponShow` 或初始化阶段选择策略。
|
||||
|
||||
## 攻击可视化效果规范
|
||||
接口:`IWeaponAttackEffect.Play(WeaponBase weapon, Vector3 position, EntityBase target, float radius)`
|
||||
|
||||
约定:
|
||||
- 可视化逻辑与伤害逻辑解耦。
|
||||
- 武器类只负责触发 `Play`,不把可视化细节塞回武器核心逻辑。
|
||||
- 当前阶段允许临时对象创建;后续若有性能压力再统一对象池化。
|
||||
- 命中特效、范围预警、扇形描边都属于 effect 层,不属于伤害层。
|
||||
|
||||
## 数据层规范(DRWeapon / WeaponData)
|
||||
### `DRWeapon`
|
||||
提供通用字段:
|
||||
- `Attack`
|
||||
- `Cooldown`
|
||||
- `AttackRange`
|
||||
- `AttackSoundId`
|
||||
- `ParamsJson`
|
||||
- `Pramas`
|
||||
- `Modifiers`
|
||||
|
||||
约定:
|
||||
- `Params` 列现在使用标准 JSON 对象。
|
||||
- 空参数统一写 `{}`。
|
||||
- 不再兼容 `[]`。
|
||||
- `Pramas` 保留为描述/UI 的兼容字典视图,不再作为武器逻辑主读取入口。
|
||||
|
||||
### `WeaponData`
|
||||
提供公共武器字段与通用解析入口:
|
||||
- 公共战斗字段:`Attack`、`Cooldown`、`AttackRange`
|
||||
- 公共展示字段:`Title`、`IconAssetName`、`Rarity`、`Price`
|
||||
- 参数入口:`ParamsJson`、`Params`
|
||||
- 通用强类型解析:`ParseParams<TParams>()`
|
||||
|
||||
约定:
|
||||
- 参数解析优先在数据层完成。
|
||||
- 武器逻辑层读取强类型 `ParamsData`,不要散落字符串 `Parse`。
|
||||
- 只有描述/UI 等弱类型场景才继续读取 `Params` 字典。
|
||||
|
||||
### 具体武器数据子类
|
||||
每种武器数据子类都应持有自己的 `ParamsData`:
|
||||
- `WeaponKnifeData -> WeaponKnifeParamsData`
|
||||
- `WeaponHandgunData -> WeaponHandgunParamsData`
|
||||
- `WeaponSlashData -> WeaponSlashParamsData`
|
||||
- `WeaponLightningData -> WeaponLightningParamsData`
|
||||
|
||||
当前已接通字段:
|
||||
- `WeaponKnifeParamsData`
|
||||
- `HitRadius`
|
||||
- `WeaponHandgunParamsData`
|
||||
- 暂无字段
|
||||
- `WeaponSlashParamsData`
|
||||
- `SectorAngle`
|
||||
- `WeaponLightningParamsData`
|
||||
- `HitRadius`
|
||||
- `HoverHeight`
|
||||
|
||||
JSON 约束:
|
||||
- key 名应与 `ParamsData` 属性名一致。
|
||||
- 统一使用 JSON 对象,不要再使用自定义 KV 串。
|
||||
- 不建议在 `ParamsJson` 中使用制表符和跨行内容,避免 txt 表分列出错。
|
||||
|
||||
## 新增武器标准流程
|
||||
1. 定义枚举
|
||||
- 更新 `WeaponType`,保持递增值,避免重排已有值。
|
||||
|
||||
2. 建立数据类
|
||||
- 新建 `WeaponXxxData : WeaponData`。
|
||||
- 新建 `WeaponXxxParamsData`。
|
||||
- 在构造阶段调用 `ParseParams<TParams>()`,把参数初始化为强类型字段。
|
||||
|
||||
3. 建立行为类
|
||||
- 新建 `WeaponXxx : WeaponBase`。
|
||||
- 只实现差异化逻辑:`BuildStates`、`Check`、`Attack`、特有检测/动画。
|
||||
|
||||
4. 建立状态类
|
||||
- 推荐放在 `Weapon/WeaponXxx/` 目录,采用 partial 组织:
|
||||
- `WeaponXxx.cs`
|
||||
- `WeaponXxx.IdleState.cs`
|
||||
- `WeaponXxx.CheckOutRangeState.cs`
|
||||
- `WeaponXxx.CheckInRangeState.cs`
|
||||
- `WeaponXxx.AttackState.cs`
|
||||
|
||||
5. 建立可视化(可选)
|
||||
- 新建 `WeaponXxxAttackEffect : IWeaponAttackEffect`,在武器中组合调用。
|
||||
|
||||
6. 接入实体展示与数据表
|
||||
- 确保 `DRWeapon` / `DREntity` 配置齐全。
|
||||
- `EntityExtension.ShowWeapon` 可正确映射到 `Entity.Weapon.WeaponXxx`。
|
||||
- 商店/背包创建入口能正确构造 `WeaponXxxData`。
|
||||
|
||||
7. 联动系统
|
||||
- 背包、商店购买/出售、UI 展示、事件流刷新。
|
||||
|
||||
8. 验证点
|
||||
- 武器能正确生成、附着、更新。
|
||||
- `ParamsData` 与数据表一致。
|
||||
- 描述文本仍正确展示。
|
||||
- Simulation 模式和非 Simulation 模式都能命中。
|
||||
|
||||
## 扩展优先级建议
|
||||
### 第一批:低成本高收益
|
||||
- 长枪 / 刺剑
|
||||
- 基于 `WeaponKnife`
|
||||
- 大剑 / 半月斩
|
||||
- 基于 `WeaponSlash`
|
||||
- 战锤 / 震地锤
|
||||
- 基于 `WeaponLightning` 或 `WeaponKnife`
|
||||
- 霰弹枪
|
||||
- 基于参数化后的 `WeaponHandgun`
|
||||
- 狙击枪
|
||||
- 基于参数化后的 `WeaponHandgun`
|
||||
- 陨石杖 / 圣光柱
|
||||
- 基于 `WeaponLightning`
|
||||
|
||||
### 第二批:中成本扩展
|
||||
- 链式闪电
|
||||
- 穿透弹 / 火球
|
||||
- 地雷 / 陷阱
|
||||
- 回旋镖
|
||||
|
||||
### 暂缓项
|
||||
- 持续激光
|
||||
- 喷火器
|
||||
- 环绕飞剑
|
||||
- 常驻法球
|
||||
- 状态异常驱动的复杂武器流派
|
||||
|
||||
原因:
|
||||
- 当前武器主流程仍是单次攻击结算。
|
||||
- 持续伤害、异常状态和常驻 orbit 行为尚未形成统一挂点。
|
||||
|
||||
## `WeaponHandgun` 后续建议
|
||||
当前 `WeaponHandgun` 参数化仍偏弱,建议作为下一阶段母版优先扩展。
|
||||
|
||||
建议新增字段:
|
||||
- `PelletCount`
|
||||
- `SpreadAngle`
|
||||
- `PenetrationCount`
|
||||
- `FireOriginOffsetX`
|
||||
- `FireOriginOffsetY`
|
||||
- `FireOriginOffsetZ`
|
||||
- `HitMarkerSize`
|
||||
- `HitMarkerYOffset`
|
||||
- `HitMarkerDuration`
|
||||
|
||||
完成后可快速派生:
|
||||
- 手枪
|
||||
- 霰弹枪
|
||||
- 狙击枪
|
||||
- 三连发枪
|
||||
|
||||
## 代码检查清单(提交前)
|
||||
- 是否重复实现了 `WeaponBase` 已有通用逻辑。
|
||||
- 状态流转是否会卡死或漏转场。
|
||||
- 冷却计时是否在无目标时仍正常累积。
|
||||
- 目标失效(null/Unavailable/死亡)是否安全处理。
|
||||
- 命中检测是否符合武器设计(地面范围/射线/扇形/落点)。
|
||||
- 数据参数是否全部收敛到 `ParamsData`。
|
||||
- 可视化是否与伤害逻辑解耦。
|
||||
- 是否正确订阅/解绑攻击属性(或复用基类方法)。
|
||||
- 商店、背包、武器描述是否仍保持兼容。
|
||||
|
||||
## 已知注意点
|
||||
- 目录中存在 `Pramas` 命名拼写历史包袱,当前保持兼容即可。
|
||||
- 文档中的“规范”优先级高于历史实现;历史实现若偏离,按本规范逐步收敛。
|
||||
- 当前更推荐“公共 `WeaponData` + 专属 `ParamsData`”结构,不建议把每种武器做成一套完全独立的数据总线。
|
||||
Loading…
Reference in New Issue