UI 系统

This commit is contained in:
2026-06-08 11:26:17 +08:00
parent 1897658a00
commit b582317692
94 changed files with 33540 additions and 3726 deletions

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,16 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 23dad55c2f7bcc54a92ed61cc6f27c5b, type: 3}
m_Name: EVT_BestiaryUpdated
m_EditorClassIdentifier:
description:
_replayLastValueToNewSubscribers: 0

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8f88dc093b15bd24fa4431d52d542b5b
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,15 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 07c5881d0d5ca3c42949a79f40939c3e, type: 3}
m_Name: EVT_QuickOpenMap
m_EditorClassIdentifier:
description:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ee46ee2d7b009904f9f8e9eda86da01c
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,13 +1,137 @@
{
"entries": [
{
"key": "ABL_CHARGEATTACK",
"value": "蓄力攻击"
},
{
"key": "ABL_DASH",
"value": "冲刺"
},
{
"key": "ABL_DOUBLEJUMP",
"value": "二段跳"
},
{
"key": "ABL_DOWNDASH",
"value": "下冲刺"
},
{
"key": "ABL_DOWNSLASH",
"value": "下斩"
},
{
"key": "ABL_FASTTRAVEL",
"value": "快速旅行"
},
{
"key": "ABL_FORM_DIHUN",
"value": "地魂"
},
{
"key": "ABL_FORM_MINGHUN",
"value": "命魂"
},
{
"key": "ABL_FORM_TIANHUN",
"value": "天魂"
},
{
"key": "ABL_INTERACT",
"value": "互动"
},
{
"key": "ABL_INVINCIBLEDASH",
"value": "无敌冲刺"
},
{
"key": "ABL_OVERVIEW_TITLE",
"value": "能力"
},
{
"key": "ABL_PARRY",
"value": "弹反"
},
{
"key": "ABL_SPELL1",
"value": "法术槽 1"
},
{
"key": "ABL_SPELL2",
"value": "法术槽 2"
},
{
"key": "ABL_SPELL3",
"value": "法术槽 3"
},
{
"key": "ABL_SPIRITDASH",
"value": "灵魄冲刺"
},
{
"key": "ABL_SPIRITFORM",
"value": "灵魄形态"
},
{
"key": "ABL_SUPERJUMP",
"value": "超级跳"
},
{
"key": "ABL_SWIM",
"value": "游泳"
},
{
"key": "ABL_WALLCLING",
"value": "贴墙悬挂"
},
{
"key": "ABL_WALLJUMP",
"value": "墙跳"
},
{
"key": "BADGE_STEELSOUL",
"value": "钢魂"
},
{
"key": "BESTIARY_HP",
"value": "生命"
},
{
"key": "BESTIARY_KILLS",
"value": "击杀"
},
{
"key": "BESTIARY_LOCKED",
"value": "???"
},
{
"key": "BESTIARY_LOCKED_DESC",
"value": "尚未发现该敌人。"
},
{
"key": "BESTIARY_TITLE",
"value": "图鉴"
},
{
"key": "BTN_BACK",
"value": "返回"
},
{
"key": "CHARM_CATALOG",
"value": "收藏"
},
{
"key": "CHARM_EQUIPPED",
"value": "已装备"
},
{
"key": "CHARM_NOTCHES",
"value": "凹槽"
},
{
"key": "CHARM_TITLE",
"value": "护符"
},
{
"key": "CONFIRM_DELETE_BODY",
"value": "确定删除该存档槽的所有进度吗?此操作不可撤销。"
@@ -40,6 +164,30 @@
"key": "CREDITS_TITLE",
"value": "制作团队"
},
{
"key": "ENM_E001_DESC",
"value": "(占位)该敌人的背景与弱点描述,由策划填写。"
},
{
"key": "ENM_E001_NAME",
"value": "敌人 E001"
},
{
"key": "FORMSKILL_TITLE",
"value": "形态技能"
},
{
"key": "FORM_DIHUN",
"value": "地魂"
},
{
"key": "FORM_MINGHUN",
"value": "命魂"
},
{
"key": "FORM_TIANHUN",
"value": "天魂"
},
{
"key": "LOADING_TIP_COMBAT",
"value": "把握闪避与格挡的时机,是战斗的关键。"
@@ -68,6 +216,14 @@
"key": "MAP_PROGRESS_REGION",
"value": "{1}{0:P0}"
},
{
"key": "MENU_BESTIARY",
"value": "图鉴"
},
{
"key": "MENU_CHARM",
"value": "护符"
},
{
"key": "MENU_CONTINUE",
"value": "继续"
@@ -76,10 +232,22 @@
"key": "MENU_CREDITS",
"value": "制作团队"
},
{
"key": "MENU_INVENTORY",
"value": "物品"
},
{
"key": "MENU_MAP",
"value": "地图"
},
{
"key": "MENU_NEW_GAME",
"value": "新游戏"
},
{
"key": "MENU_QUESTS",
"value": "任务"
},
{
"key": "MENU_QUIT",
"value": "退出"

View File

@@ -1,13 +1,137 @@
{
"entries": [
{
"key": "ABL_CHARGEATTACK",
"value": "Charge Attack"
},
{
"key": "ABL_DASH",
"value": "Dash"
},
{
"key": "ABL_DOUBLEJUMP",
"value": "Double Jump"
},
{
"key": "ABL_DOWNDASH",
"value": "Down Dash"
},
{
"key": "ABL_DOWNSLASH",
"value": "Down Slash"
},
{
"key": "ABL_FASTTRAVEL",
"value": "Fast Travel"
},
{
"key": "ABL_FORM_DIHUN",
"value": "Earth Soul"
},
{
"key": "ABL_FORM_MINGHUN",
"value": "Death Soul"
},
{
"key": "ABL_FORM_TIANHUN",
"value": "Sky Soul"
},
{
"key": "ABL_INTERACT",
"value": "Interact"
},
{
"key": "ABL_INVINCIBLEDASH",
"value": "Invincible Dash"
},
{
"key": "ABL_OVERVIEW_TITLE",
"value": "Abilities"
},
{
"key": "ABL_PARRY",
"value": "Parry"
},
{
"key": "ABL_SPELL1",
"value": "Spell Slot 1"
},
{
"key": "ABL_SPELL2",
"value": "Spell Slot 2"
},
{
"key": "ABL_SPELL3",
"value": "Spell Slot 3"
},
{
"key": "ABL_SPIRITDASH",
"value": "Spirit Dash"
},
{
"key": "ABL_SPIRITFORM",
"value": "Spirit Form"
},
{
"key": "ABL_SUPERJUMP",
"value": "Super Jump"
},
{
"key": "ABL_SWIM",
"value": "Swim"
},
{
"key": "ABL_WALLCLING",
"value": "Wall Cling"
},
{
"key": "ABL_WALLJUMP",
"value": "Wall Jump"
},
{
"key": "BADGE_STEELSOUL",
"value": "STEEL"
},
{
"key": "BESTIARY_HP",
"value": "HP"
},
{
"key": "BESTIARY_KILLS",
"value": "Kills"
},
{
"key": "BESTIARY_LOCKED",
"value": "???"
},
{
"key": "BESTIARY_LOCKED_DESC",
"value": "Not yet discovered."
},
{
"key": "BESTIARY_TITLE",
"value": "Bestiary"
},
{
"key": "BTN_BACK",
"value": "Back"
},
{
"key": "CHARM_CATALOG",
"value": "Collected"
},
{
"key": "CHARM_EQUIPPED",
"value": "Equipped"
},
{
"key": "CHARM_NOTCHES",
"value": "Notches"
},
{
"key": "CHARM_TITLE",
"value": "Charms"
},
{
"key": "CONFIRM_DELETE_BODY",
"value": "Delete all progress in this slot? This cannot be undone."
@@ -40,6 +164,30 @@
"key": "CREDITS_TITLE",
"value": "Credits"
},
{
"key": "ENM_E001_DESC",
"value": "(Placeholder) Lore and weakness description, to be filled by design."
},
{
"key": "ENM_E001_NAME",
"value": "Enemy E001"
},
{
"key": "FORMSKILL_TITLE",
"value": "Form Skills"
},
{
"key": "FORM_DIHUN",
"value": "Earth Soul"
},
{
"key": "FORM_MINGHUN",
"value": "Death Soul"
},
{
"key": "FORM_TIANHUN",
"value": "Sky Soul"
},
{
"key": "LOADING_TIP_COMBAT",
"value": "Timing your dodge and parry is the key to combat."
@@ -68,6 +216,14 @@
"key": "MAP_PROGRESS_REGION",
"value": "{1}: {0:P0}"
},
{
"key": "MENU_BESTIARY",
"value": "Bestiary"
},
{
"key": "MENU_CHARM",
"value": "Charms"
},
{
"key": "MENU_CONTINUE",
"value": "Continue"
@@ -76,10 +232,22 @@
"key": "MENU_CREDITS",
"value": "Credits"
},
{
"key": "MENU_INVENTORY",
"value": "Inventory"
},
{
"key": "MENU_MAP",
"value": "Map"
},
{
"key": "MENU_NEW_GAME",
"value": "New Game"
},
{
"key": "MENU_QUESTS",
"value": "Quests"
},
{
"key": "MENU_QUIT",
"value": "Quit"

View File

@@ -14,7 +14,10 @@ MonoBehaviour:
m_EditorClassIdentifier:
_inputActions: {fileID: -944628639613478452, guid: 6d0341a640ba64043a8cd70f771b962d, type: 3}
_onPauseRequested: {fileID: 11400000, guid: a02c7f0e5fa99054bac624adc82c4a53, type: 2}
_onInventoryOpen: {fileID: 0}
_onInventoryTabNext: {fileID: 0}
_onInventoryTabPrev: {fileID: 0}
_onInventoryOpen: {fileID: 11400000, guid: f723ead60ca68e24c84a30d8adb535d1, type: 2}
_onInventoryTabNext: {fileID: 11400000, guid: 3c1e15b4e86e9ef4c81009cf845e5839, type: 2}
_onInventoryTabPrev: {fileID: 11400000, guid: 49f53b8989b492d448eb04b803767da3, type: 2}
_onQuickMap: {fileID: 11400000, guid: ee46ee2d7b009904f9f8e9eda86da01c, type: 2}
_onQuickInventory: {fileID: 11400000, guid: ac99163db5fe6a444b175388b6c26582, type: 2}
_onQuickQuests: {fileID: 11400000, guid: c056115e1cb5d734684daa827c725f0a, type: 2}
_onUICancelPressed: {fileID: 11400000, guid: 7d520a6b9d8d4004cb772e875f1c4364, type: 2}

View File

@@ -0,0 +1,30 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 812ef8f0ed1f58c469c7c35ace58b10f, type: 3}
m_Name: FormSkillDatabase
m_EditorClassIdentifier:
_entries:
- formType: 0
formLabelKey: FORM_TIANHUN
soulSkill: {fileID: 0}
spiritSkill1: {fileID: 0}
spiritSkill2: {fileID: 0}
- formType: 1
formLabelKey: FORM_DIHUN
soulSkill: {fileID: 0}
spiritSkill1: {fileID: 0}
spiritSkill2: {fileID: 0}
- formType: 2
formLabelKey: FORM_MINGHUN
soulSkill: {fileID: 0}
spiritSkill1: {fileID: 0}
spiritSkill2: {fileID: 0}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6726937a7b200fe48b4fee44bf9eb5d9
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,99 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 381fcefcad0b4544c88188bf7e8d695e, type: 3}
m_Name: UI_AbilityMeta
m_EditorClassIdentifier:
_items:
- type: 1
labelKey: ABL_WALLCLING
descKey:
icon: {fileID: 0}
- type: 2
labelKey: ABL_WALLJUMP
descKey:
icon: {fileID: 0}
- type: 4
labelKey: ABL_DASH
descKey:
icon: {fileID: 0}
- type: 16
labelKey: ABL_DOUBLEJUMP
descKey:
icon: {fileID: 0}
- type: 32
labelKey: ABL_SUPERJUMP
descKey:
icon: {fileID: 0}
- type: 64
labelKey: ABL_SWIM
descKey:
icon: {fileID: 0}
- type: 128
labelKey: ABL_DOWNDASH
descKey:
icon: {fileID: 0}
- type: 262144
labelKey: ABL_INVINCIBLEDASH
descKey:
icon: {fileID: 0}
- type: 256
labelKey: ABL_SPELL1
descKey:
icon: {fileID: 0}
- type: 512
labelKey: ABL_SPELL2
descKey:
icon: {fileID: 0}
- type: 1024
labelKey: ABL_SPELL3
descKey:
icon: {fileID: 0}
- type: 2048
labelKey: ABL_SPIRITFORM
descKey:
icon: {fileID: 0}
- type: 4096
labelKey: ABL_SPIRITDASH
descKey:
icon: {fileID: 0}
- type: 524288
labelKey: ABL_FORM_TIANHUN
descKey:
icon: {fileID: 0}
- type: 1048576
labelKey: ABL_FORM_DIHUN
descKey:
icon: {fileID: 0}
- type: 2097152
labelKey: ABL_FORM_MINGHUN
descKey:
icon: {fileID: 0}
- type: 8192
labelKey: ABL_PARRY
descKey:
icon: {fileID: 0}
- type: 16384
labelKey: ABL_CHARGEATTACK
descKey:
icon: {fileID: 0}
- type: 32768
labelKey: ABL_DOWNSLASH
descKey:
icon: {fileID: 0}
- type: 65536
labelKey: ABL_INTERACT
descKey:
icon: {fileID: 0}
- type: 131072
labelKey: ABL_FASTTRAVEL
descKey:
icon: {fileID: 0}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ef6d27ecd5ec95b45a78e10ca72f901d
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,23 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 6d7e33770928593459417c4dab65ced5, type: 3}
m_Name: UI_BestiaryDatabase
m_EditorClassIdentifier:
_entries:
- enemyId: E001
displayNameKey: ENM_E001_NAME
descKey: ENM_E001_DESC
icon: {fileID: 0}
tier: 0
region:
fullLoreKillCount: 1
displayMaxHP: 50

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: cc1b8d981de8b9a45a6f24fb71aef549
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -16,20 +16,24 @@ MonoBehaviour:
- labelKey: PAUSE_RESUME
icon: {fileID: 0}
action: 0
targetPanel: 0
sceneKey:
eventChannel: {fileID: 0}
- labelKey: MENU_SETTINGS
icon: {fileID: 0}
action: 1
targetPanel: 0
sceneKey:
eventChannel: {fileID: 0}
- labelKey: PAUSE_MAIN_MENU
icon: {fileID: 0}
action: 2
action: 3
targetPanel: 0
sceneKey:
eventChannel: {fileID: 0}
- labelKey: MENU_QUIT
icon: {fileID: 0}
action: 3
action: 4
targetPanel: 0
sceneKey:
eventChannel: {fileID: 0}

View File

@@ -556,7 +556,7 @@ MonoBehaviour:
_formController: {fileID: 777120280222230040}
_modifiers: {fileID: 8042055702654754671}
_skillSocket: {fileID: 2686118482929949427}
_formSkillSets: []
_skillDatabase: {fileID: 11400000, guid: 6726937a7b200fe48b4fee44bf9eb5d9, type: 2}
--- !u!114 &3526481760530697137
MonoBehaviour:
m_ObjectHideFlags: 0

View File

@@ -0,0 +1,425 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &1634081538682688295
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 7621173430521640725}
- component: {fileID: 4960598188176280531}
- component: {fileID: 8665928432703001724}
m_Layer: 0
m_Name: Icon
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &7621173430521640725
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1634081538682688295}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1639513482261165172}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 1}
m_AnchorMax: {x: 0.5, y: 1}
m_AnchoredPosition: {x: 0, y: -50}
m_SizeDelta: {x: 72, y: 72}
m_Pivot: {x: 0.5, y: 1}
--- !u!222 &4960598188176280531
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1634081538682688295}
m_CullTransparentMesh: 1
--- !u!114 &8665928432703001724
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1634081538682688295}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 0
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 0}
m_Type: 0
m_PreserveAspect: 1
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!1 &2322039928480162756
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 5155816936399704854}
- component: {fileID: 3531378629214921856}
- component: {fileID: 1711389621720004230}
- component: {fileID: 1479187555911938506}
- component: {fileID: 3280365467884612915}
m_Layer: 0
m_Name: Name
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &5155816936399704854
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2322039928480162756}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1639513482261165172}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0}
m_AnchorMax: {x: 0.5, y: 0}
m_AnchoredPosition: {x: 0, y: 18}
m_SizeDelta: {x: -12, y: 44}
m_Pivot: {x: 0.5, y: 0}
--- !u!222 &3531378629214921856
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2322039928480162756}
m_CullTransparentMesh: 1
--- !u!114 &1711389621720004230
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2322039928480162756}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 0
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_text:
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: c9ebf78286d2b6345b16575012502acc, type: 2}
m_sharedMaterial: {fileID: 1445647621079294416, guid: c9ebf78286d2b6345b16575012502acc, type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
m_fontMaterials: []
m_fontColor32:
serializedVersion: 2
rgba: 4294967295
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
m_enableVertexGradient: 0
m_colorMode: 3
m_fontColorGradient:
topLeft: {r: 1, g: 1, b: 1, a: 1}
topRight: {r: 1, g: 1, b: 1, a: 1}
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
bottomRight: {r: 1, g: 1, b: 1, a: 1}
m_fontColorGradientPreset: {fileID: 0}
m_spriteAsset: {fileID: 0}
m_tintAllSprites: 0
m_StyleSheet: {fileID: 0}
m_TextStyleHashCode: 0
m_overrideHtmlColors: 0
m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 20
m_fontSizeBase: 20
m_fontWeight: 400
m_enableAutoSizing: 0
m_fontSizeMin: 18
m_fontSizeMax: 72
m_fontStyle: 0
m_HorizontalAlignment: 2
m_VerticalAlignment: 512
m_textAlignment: 65535
m_characterSpacing: 0
m_wordSpacing: 0
m_lineSpacing: 0
m_lineSpacingMax: 0
m_paragraphSpacing: 0
m_charWidthMaxAdj: 0
m_enableWordWrapping: 1
m_wordWrappingRatios: 0.4
m_overflowMode: 0
m_linkedTextComponent: {fileID: 0}
parentLinkedComponent: {fileID: 0}
m_enableKerning: 1
m_enableExtraPadding: 0
checkPaddingRequired: 0
m_isRichText: 1
m_parseCtrlCharacters: 1
m_isOrthographic: 1
m_isCullingEnabled: 0
m_horizontalMapping: 0
m_verticalMapping: 0
m_uvLineOffset: 0
m_geometrySortingOrder: 0
m_IsTextObjectScaleStatic: 0
m_VertexBufferAutoSizeReduction: 0
m_useMaxVisibleDescender: 1
m_pageToDisplay: 1
m_margin: {x: 0, y: 0, z: 0, w: 0}
m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0
m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
--- !u!114 &1479187555911938506
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2322039928480162756}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 964e3a3ab86805244bbde47d5f54950b, type: 3}
m_Name:
m_EditorClassIdentifier:
_key:
_table: UI
_fontConfig: {fileID: 0}
--- !u!114 &3280365467884612915
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2322039928480162756}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1fa7f5f3910b010489199ef7ddee773e, type: 3}
m_Name:
m_EditorClassIdentifier:
_kind: 7
_overrideFontSize: 0
--- !u!1 &7177395350122629075
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 4367285374197142973}
- component: {fileID: 846294020038920790}
- component: {fileID: 448350837364743089}
m_Layer: 0
m_Name: LockedOverlay
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 0
--- !u!224 &4367285374197142973
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7177395350122629075}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1639513482261165172}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &846294020038920790
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7177395350122629075}
m_CullTransparentMesh: 1
--- !u!114 &448350837364743089
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7177395350122629075}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0, g: 0, b: 0, a: 0.55}
m_RaycastTarget: 0
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 0}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!1 &8106631252188738407
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1639513482261165172}
- component: {fileID: 3352583467711433562}
- component: {fileID: 2584146654661311467}
- component: {fileID: 9124488740705629695}
- component: {fileID: 4938301642281296628}
m_Layer: 0
m_Name: UI_AbilityCell
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &1639513482261165172
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8106631252188738407}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 7621173430521640725}
- {fileID: 5155816936399704854}
- {fileID: 4367285374197142973}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 180, y: 150}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!225 &3352583467711433562
CanvasGroup:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8106631252188738407}
m_Enabled: 1
m_Alpha: 1
m_Interactable: 1
m_BlocksRaycasts: 1
m_IgnoreParentGroups: 0
--- !u!114 &2584146654661311467
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8106631252188738407}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 759137176b2cfdd47b53d655d10b170f, type: 3}
m_Name:
m_EditorClassIdentifier:
_icon: {fileID: 8665928432703001724}
_label: {fileID: 1479187555911938506}
_lockedOverlay: {fileID: 7177395350122629075}
_group: {fileID: 3352583467711433562}
--- !u!222 &9124488740705629695
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8106631252188738407}
m_CullTransparentMesh: 1
--- !u!114 &4938301642281296628
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8106631252188738407}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 0.05}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
m_Type: 1
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d61349f905604f244a7e85bbca89a02b
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,471 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &2896016232823025998
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1529083837976743201}
- component: {fileID: 2252767286896220494}
- component: {fileID: 4598901582900529729}
- component: {fileID: 2412949974959584255}
- component: {fileID: 7862706350387296420}
m_Layer: 0
m_Name: Name
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &1529083837976743201
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2896016232823025998}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 7102637998092335812}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0}
m_AnchorMax: {x: 0.5, y: 0}
m_AnchoredPosition: {x: 0, y: 14}
m_SizeDelta: {x: 154, y: 40}
m_Pivot: {x: 0.5, y: 0}
--- !u!222 &2252767286896220494
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2896016232823025998}
m_CullTransparentMesh: 1
--- !u!114 &4598901582900529729
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2896016232823025998}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 0
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_text:
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: c9ebf78286d2b6345b16575012502acc, type: 2}
m_sharedMaterial: {fileID: 1445647621079294416, guid: c9ebf78286d2b6345b16575012502acc, type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
m_fontMaterials: []
m_fontColor32:
serializedVersion: 2
rgba: 4294967295
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
m_enableVertexGradient: 0
m_colorMode: 3
m_fontColorGradient:
topLeft: {r: 1, g: 1, b: 1, a: 1}
topRight: {r: 1, g: 1, b: 1, a: 1}
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
bottomRight: {r: 1, g: 1, b: 1, a: 1}
m_fontColorGradientPreset: {fileID: 0}
m_spriteAsset: {fileID: 0}
m_tintAllSprites: 0
m_StyleSheet: {fileID: 0}
m_TextStyleHashCode: 0
m_overrideHtmlColors: 0
m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 18
m_fontSizeBase: 18
m_fontWeight: 400
m_enableAutoSizing: 0
m_fontSizeMin: 18
m_fontSizeMax: 72
m_fontStyle: 0
m_HorizontalAlignment: 2
m_VerticalAlignment: 512
m_textAlignment: 65535
m_characterSpacing: 0
m_wordSpacing: 0
m_lineSpacing: 0
m_lineSpacingMax: 0
m_paragraphSpacing: 0
m_charWidthMaxAdj: 0
m_enableWordWrapping: 1
m_wordWrappingRatios: 0.4
m_overflowMode: 0
m_linkedTextComponent: {fileID: 0}
parentLinkedComponent: {fileID: 0}
m_enableKerning: 1
m_enableExtraPadding: 0
checkPaddingRequired: 0
m_isRichText: 1
m_parseCtrlCharacters: 1
m_isOrthographic: 1
m_isCullingEnabled: 0
m_horizontalMapping: 0
m_verticalMapping: 0
m_uvLineOffset: 0
m_geometrySortingOrder: 0
m_IsTextObjectScaleStatic: 0
m_VertexBufferAutoSizeReduction: 0
m_useMaxVisibleDescender: 1
m_pageToDisplay: 1
m_margin: {x: 0, y: 0, z: 0, w: 0}
m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0
m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
--- !u!114 &2412949974959584255
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2896016232823025998}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 964e3a3ab86805244bbde47d5f54950b, type: 3}
m_Name:
m_EditorClassIdentifier:
_key:
_table: UI
_fontConfig: {fileID: 0}
--- !u!114 &7862706350387296420
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2896016232823025998}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1fa7f5f3910b010489199ef7ddee773e, type: 3}
m_Name:
m_EditorClassIdentifier:
_kind: 7
_overrideFontSize: 0
--- !u!1 &2997881328911015144
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 7644037852533164499}
- component: {fileID: 3237970644973317964}
- component: {fileID: 2634062636110067921}
m_Layer: 0
m_Name: LockedOverlay
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 0
--- !u!224 &7644037852533164499
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2997881328911015144}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 7102637998092335812}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &3237970644973317964
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2997881328911015144}
m_CullTransparentMesh: 1
--- !u!114 &2634062636110067921
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2997881328911015144}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0, g: 0, b: 0, a: 0.5}
m_RaycastTarget: 0
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 0}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!1 &6220222334124907477
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 7102637998092335812}
- component: {fileID: 9166943631181726569}
- component: {fileID: 1404828388023685448}
- component: {fileID: 993189946965399717}
- component: {fileID: 8924253800485510318}
- component: {fileID: 3925107870086657813}
m_Layer: 0
m_Name: UI_BestiaryCell
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &7102637998092335812
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6220222334124907477}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 109918452772175674}
- {fileID: 1529083837976743201}
- {fileID: 7644037852533164499}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 170, y: 130}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!225 &9166943631181726569
CanvasGroup:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6220222334124907477}
m_Enabled: 1
m_Alpha: 1
m_Interactable: 1
m_BlocksRaycasts: 1
m_IgnoreParentGroups: 0
--- !u!114 &1404828388023685448
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6220222334124907477}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 7734d0120f3b75b41905933b325a823e, type: 3}
m_Name:
m_EditorClassIdentifier:
_icon: {fileID: 1680118432201936944}
_label: {fileID: 2412949974959584255}
_lockedOverlay: {fileID: 2997881328911015144}
_group: {fileID: 9166943631181726569}
_selectButton: {fileID: 3925107870086657813}
--- !u!222 &993189946965399717
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6220222334124907477}
m_CullTransparentMesh: 1
--- !u!114 &8924253800485510318
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6220222334124907477}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 0.05}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
m_Type: 1
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!114 &3925107870086657813
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6220222334124907477}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Navigation:
m_Mode: 3
m_WrapAround: 0
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
m_SelectOnRight: {fileID: 0}
m_Transition: 1
m_Colors:
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
m_ColorMultiplier: 1
m_FadeDuration: 0.1
m_SpriteState:
m_HighlightedSprite: {fileID: 0}
m_PressedSprite: {fileID: 0}
m_SelectedSprite: {fileID: 0}
m_DisabledSprite: {fileID: 0}
m_AnimationTriggers:
m_NormalTrigger: Normal
m_HighlightedTrigger: Highlighted
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 1
m_TargetGraphic: {fileID: 8924253800485510318}
m_OnClick:
m_PersistentCalls:
m_Calls: []
--- !u!1 &9006788155265253894
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 109918452772175674}
- component: {fileID: 1375849703927834707}
- component: {fileID: 1680118432201936944}
m_Layer: 0
m_Name: Icon
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &109918452772175674
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 9006788155265253894}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 7102637998092335812}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 1}
m_AnchorMax: {x: 0.5, y: 1}
m_AnchoredPosition: {x: 0, y: -44}
m_SizeDelta: {x: 72, y: 72}
m_Pivot: {x: 0.5, y: 1}
--- !u!222 &1375849703927834707
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 9006788155265253894}
m_CullTransparentMesh: 1
--- !u!114 &1680118432201936944
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 9006788155265253894}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 0
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 0}
m_Type: 0
m_PreserveAspect: 1
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d8808f4b54bb4b94997f6a7d4e5b8a30
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,830 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &1763794691949497564
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 4132358276738456989}
- component: {fileID: 6087283166429833622}
- component: {fileID: 6130157718267853529}
- component: {fileID: 4070109231453679368}
- component: {fileID: 3106161499516767422}
- component: {fileID: 5239446412181103806}
- component: {fileID: 8700568282154637204}
m_Layer: 0
m_Name: UI_AbilityOverviewPanel
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 0
--- !u!224 &4132358276738456989
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1763794691949497564}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0, y: 0, z: 0}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 5208692459180828571}
- {fileID: 198539661235847941}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0, y: 0}
--- !u!223 &6087283166429833622
Canvas:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1763794691949497564}
m_Enabled: 1
serializedVersion: 3
m_RenderMode: 0
m_Camera: {fileID: 0}
m_PlaneDistance: 100
m_PixelPerfect: 0
m_ReceivesEvents: 1
m_OverrideSorting: 0
m_OverridePixelPerfect: 0
m_SortingBucketNormalizedSize: 0
m_VertexColorAlwaysGammaSpace: 0
m_AdditionalShaderChannelsFlag: 0
m_UpdateRectTransformForStandalone: 0
m_SortingLayerID: 0
m_SortingOrder: 60
m_TargetDisplay: 0
--- !u!114 &6130157718267853529
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1763794691949497564}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
m_Name:
m_EditorClassIdentifier:
m_UiScaleMode: 1
m_ReferencePixelsPerUnit: 100
m_ScaleFactor: 1
m_ReferenceResolution: {x: 1920, y: 1080}
m_ScreenMatchMode: 0
m_MatchWidthOrHeight: 0.5
m_PhysicalUnit: 3
m_FallbackScreenDPI: 96
m_DefaultSpriteDPI: 96
m_DynamicPixelsPerUnit: 1
m_PresetInfoIsWorld: 0
--- !u!114 &4070109231453679368
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1763794691949497564}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
m_Name:
m_EditorClassIdentifier:
m_IgnoreReversedGraphics: 1
m_BlockingObjects: 0
m_BlockingMask:
serializedVersion: 2
m_Bits: 4294967295
--- !u!225 &3106161499516767422
CanvasGroup:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1763794691949497564}
m_Enabled: 1
m_Alpha: 1
m_Interactable: 1
m_BlocksRaycasts: 1
m_IgnoreParentGroups: 0
--- !u!114 &5239446412181103806
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1763794691949497564}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ba7e35964864d7d44b021a24a7213c52, type: 3}
m_Name:
m_EditorClassIdentifier:
_meta: {fileID: 11400000, guid: ef6d27ecd5ec95b45a78e10ca72f901d, type: 2}
_container: {fileID: 8654936868285929732}
_cellPrefab: {fileID: 2584146654661311467, guid: d61349f905604f244a7e85bbca89a02b, type: 3}
_btnClose: {fileID: 2057024099330673706}
_onAbilityUnlocked: {fileID: 11400000, guid: a8b3a59db23ed8d48970b73c8c2e3092, type: 2}
--- !u!114 &8700568282154637204
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1763794691949497564}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 50572ad108fd3354da04ea8fba66370b, type: 3}
m_Name:
m_EditorClassIdentifier:
_theme: {fileID: 11400000, guid: 88bab5495f6103f4d9d69fa043d4c3e1, type: 2}
_applyOnEnable: 1
--- !u!1 &2328847075665347172
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1841678434823181245}
- component: {fileID: 5732726943855753727}
- component: {fileID: 6058426367402214506}
- component: {fileID: 2057024099330673706}
m_Layer: 0
m_Name: Btn_Close
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &1841678434823181245
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2328847075665347172}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 7742257911161152340}
m_Father: {fileID: 198539661235847941}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0}
m_AnchorMax: {x: 0.5, y: 0}
m_AnchoredPosition: {x: 0, y: 36}
m_SizeDelta: {x: 240, y: 56}
m_Pivot: {x: 0.5, y: 0}
--- !u!222 &5732726943855753727
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2328847075665347172}
m_CullTransparentMesh: 1
--- !u!114 &6058426367402214506
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2328847075665347172}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 0.06}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
m_Type: 1
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!114 &2057024099330673706
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2328847075665347172}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Navigation:
m_Mode: 3
m_WrapAround: 0
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
m_SelectOnRight: {fileID: 0}
m_Transition: 1
m_Colors:
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
m_ColorMultiplier: 1
m_FadeDuration: 0.1
m_SpriteState:
m_HighlightedSprite: {fileID: 0}
m_PressedSprite: {fileID: 0}
m_SelectedSprite: {fileID: 0}
m_DisabledSprite: {fileID: 0}
m_AnimationTriggers:
m_NormalTrigger: Normal
m_HighlightedTrigger: Highlighted
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 1
m_TargetGraphic: {fileID: 6058426367402214506}
m_OnClick:
m_PersistentCalls:
m_Calls: []
--- !u!1 &3679843519855191783
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 5208692459180828571}
- component: {fileID: 7305623740564558464}
- component: {fileID: 4662356083144844757}
m_Layer: 0
m_Name: Overlay
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &5208692459180828571
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3679843519855191783}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 4132358276738456989}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &7305623740564558464
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3679843519855191783}
m_CullTransparentMesh: 1
--- !u!114 &4662356083144844757
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3679843519855191783}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0, g: 0, b: 0, a: 0.6}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 0}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!1 &4286209296690380696
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 198539661235847941}
- component: {fileID: 8913356614820389452}
- component: {fileID: 3936163859701694422}
- component: {fileID: 1492649012449139078}
m_Layer: 0
m_Name: DialogBox
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &198539661235847941
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4286209296690380696}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 4664494096848154450}
- {fileID: 8654936868285929732}
- {fileID: 1841678434823181245}
m_Father: {fileID: 4132358276738456989}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 1120, y: 760}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &8913356614820389452
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4286209296690380696}
m_CullTransparentMesh: 1
--- !u!114 &3936163859701694422
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4286209296690380696}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0.1, g: 0.11, b: 0.15, a: 0.98}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
m_Type: 1
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!114 &1492649012449139078
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4286209296690380696}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1fa7f5f3910b010489199ef7ddee773e, type: 3}
m_Name:
m_EditorClassIdentifier:
_kind: 3
_overrideFontSize: 0
--- !u!1 &5010713966950121665
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 7742257911161152340}
- component: {fileID: 4807781777839692819}
- component: {fileID: 1911251165025033609}
- component: {fileID: 7494373216662822444}
- component: {fileID: 8811385710266776651}
m_Layer: 0
m_Name: Label
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &7742257911161152340
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5010713966950121665}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1841678434823181245}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &4807781777839692819
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5010713966950121665}
m_CullTransparentMesh: 1
--- !u!114 &1911251165025033609
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5010713966950121665}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_text: "\u8FD4\u56DE"
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: c9ebf78286d2b6345b16575012502acc, type: 2}
m_sharedMaterial: {fileID: 1445647621079294416, guid: c9ebf78286d2b6345b16575012502acc, type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
m_fontMaterials: []
m_fontColor32:
serializedVersion: 2
rgba: 4294967295
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
m_enableVertexGradient: 0
m_colorMode: 3
m_fontColorGradient:
topLeft: {r: 1, g: 1, b: 1, a: 1}
topRight: {r: 1, g: 1, b: 1, a: 1}
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
bottomRight: {r: 1, g: 1, b: 1, a: 1}
m_fontColorGradientPreset: {fileID: 0}
m_spriteAsset: {fileID: 0}
m_tintAllSprites: 0
m_StyleSheet: {fileID: 0}
m_TextStyleHashCode: 0
m_overrideHtmlColors: 0
m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 26
m_fontSizeBase: 26
m_fontWeight: 400
m_enableAutoSizing: 0
m_fontSizeMin: 18
m_fontSizeMax: 72
m_fontStyle: 0
m_HorizontalAlignment: 2
m_VerticalAlignment: 512
m_textAlignment: 65535
m_characterSpacing: 0
m_wordSpacing: 0
m_lineSpacing: 0
m_lineSpacingMax: 0
m_paragraphSpacing: 0
m_charWidthMaxAdj: 0
m_enableWordWrapping: 1
m_wordWrappingRatios: 0.4
m_overflowMode: 0
m_linkedTextComponent: {fileID: 0}
parentLinkedComponent: {fileID: 0}
m_enableKerning: 1
m_enableExtraPadding: 0
checkPaddingRequired: 0
m_isRichText: 1
m_parseCtrlCharacters: 1
m_isOrthographic: 1
m_isCullingEnabled: 0
m_horizontalMapping: 0
m_verticalMapping: 0
m_uvLineOffset: 0
m_geometrySortingOrder: 0
m_IsTextObjectScaleStatic: 0
m_VertexBufferAutoSizeReduction: 0
m_useMaxVisibleDescender: 1
m_pageToDisplay: 1
m_margin: {x: 0, y: 0, z: 0, w: 0}
m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0
m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
--- !u!114 &7494373216662822444
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5010713966950121665}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 964e3a3ab86805244bbde47d5f54950b, type: 3}
m_Name:
m_EditorClassIdentifier:
_key: BTN_BACK
_table: UI
_fontConfig: {fileID: 0}
--- !u!114 &8811385710266776651
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5010713966950121665}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1fa7f5f3910b010489199ef7ddee773e, type: 3}
m_Name:
m_EditorClassIdentifier:
_kind: 7
_overrideFontSize: 0
--- !u!1 &5657340154405606193
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8654936868285929732}
- component: {fileID: 756963533535110120}
m_Layer: 0
m_Name: GridContainer
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &8654936868285929732
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5657340154405606193}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 198539661235847941}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: 10}
m_SizeDelta: {x: 1056, y: 600}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &756963533535110120
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5657340154405606193}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 8a8695521f0d02e499659fee002a26c2, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Padding:
m_Left: 0
m_Right: 0
m_Top: 0
m_Bottom: 0
m_ChildAlignment: 1
m_StartCorner: 0
m_StartAxis: 0
m_CellSize: {x: 160, y: 130}
m_Spacing: {x: 16, y: 14}
m_Constraint: 1
m_ConstraintCount: 6
--- !u!1 &7478511894145044625
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 4664494096848154450}
- component: {fileID: 5547070628369317454}
- component: {fileID: 6284268977408847901}
- component: {fileID: 8224147191540403336}
- component: {fileID: 8804773471835973457}
m_Layer: 0
m_Name: Title
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &4664494096848154450
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7478511894145044625}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 198539661235847941}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 1}
m_AnchorMax: {x: 0.5, y: 1}
m_AnchoredPosition: {x: 0, y: -48}
m_SizeDelta: {x: -60, y: 56}
m_Pivot: {x: 0.5, y: 1}
--- !u!222 &5547070628369317454
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7478511894145044625}
m_CullTransparentMesh: 1
--- !u!114 &6284268977408847901
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7478511894145044625}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 0
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_text: "\u80FD\u529B"
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: c9ebf78286d2b6345b16575012502acc, type: 2}
m_sharedMaterial: {fileID: 1445647621079294416, guid: c9ebf78286d2b6345b16575012502acc, type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
m_fontMaterials: []
m_fontColor32:
serializedVersion: 2
rgba: 4294967295
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
m_enableVertexGradient: 0
m_colorMode: 3
m_fontColorGradient:
topLeft: {r: 1, g: 1, b: 1, a: 1}
topRight: {r: 1, g: 1, b: 1, a: 1}
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
bottomRight: {r: 1, g: 1, b: 1, a: 1}
m_fontColorGradientPreset: {fileID: 0}
m_spriteAsset: {fileID: 0}
m_tintAllSprites: 0
m_StyleSheet: {fileID: 0}
m_TextStyleHashCode: 0
m_overrideHtmlColors: 0
m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 40
m_fontSizeBase: 40
m_fontWeight: 400
m_enableAutoSizing: 0
m_fontSizeMin: 18
m_fontSizeMax: 72
m_fontStyle: 0
m_HorizontalAlignment: 2
m_VerticalAlignment: 512
m_textAlignment: 65535
m_characterSpacing: 0
m_wordSpacing: 0
m_lineSpacing: 0
m_lineSpacingMax: 0
m_paragraphSpacing: 0
m_charWidthMaxAdj: 0
m_enableWordWrapping: 1
m_wordWrappingRatios: 0.4
m_overflowMode: 0
m_linkedTextComponent: {fileID: 0}
parentLinkedComponent: {fileID: 0}
m_enableKerning: 1
m_enableExtraPadding: 0
checkPaddingRequired: 0
m_isRichText: 1
m_parseCtrlCharacters: 1
m_isOrthographic: 1
m_isCullingEnabled: 0
m_horizontalMapping: 0
m_verticalMapping: 0
m_uvLineOffset: 0
m_geometrySortingOrder: 0
m_IsTextObjectScaleStatic: 0
m_VertexBufferAutoSizeReduction: 0
m_useMaxVisibleDescender: 1
m_pageToDisplay: 1
m_margin: {x: 0, y: 0, z: 0, w: 0}
m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0
m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
--- !u!114 &8224147191540403336
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7478511894145044625}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 964e3a3ab86805244bbde47d5f54950b, type: 3}
m_Name:
m_EditorClassIdentifier:
_key: ABL_OVERVIEW_TITLE
_table: UI
_fontConfig: {fileID: 0}
--- !u!114 &8804773471835973457
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7478511894145044625}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1fa7f5f3910b010489199ef7ddee773e, type: 3}
m_Name:
m_EditorClassIdentifier:
_kind: 9
_overrideFontSize: 0

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 0e268e0385b521c45988e1c7b477730f
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 374ca8bba3c8da646b15d06bcf8cef57
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: b41ac8869103f614abb26dafa914c165
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 0b3024b5273e8bd46b54fae38b698dbd
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 434265e89d960e8418e26c68753a3bde
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,19 @@
namespace BaseGames.Core
{
/// <summary>
/// 图鉴运行时查询服务。UI 经 <see cref="ServiceLocator"/> 取用,读取"已发现 / 击杀次数"。
/// 实现见 BaseGames.Progression.BestiaryService订阅 EVT_EnemyDied持久化到 SaveData.Journal
/// 以字符串 enemyId 解耦UI 与服务均不依赖敌人程序集。
/// </summary>
public interface IBestiaryService
{
/// <summary>该敌人是否已被记录(击杀过 / 遭遇过)。</summary>
bool IsDiscovered(string enemyId);
/// <summary>对该敌人的累计击杀次数(用于完整词条解锁 / 完成度)。</summary>
int GetKillCount(string enemyId);
/// <summary>已发现敌人总数(完成度 = 此值 / 图鉴条目总数,由 UI 侧按数据表长度计算)。</summary>
int DiscoveredCount { get; }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9f371aeab3546c247bf0044d434e2518
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -88,6 +88,7 @@ namespace BaseGames.Editor
CreateAsset<IntEventChannelSO> ("UI/Inventory", "EVT_InventoryTabChanged"); // 当前激活 Tab 索引变化
CreateAsset<VoidEventChannelSO> ("UI/Inventory", "EVT_InventoryTabNext"); // L/R 肩键:切换到下一 Tab
CreateAsset<VoidEventChannelSO> ("UI/Inventory", "EVT_InventoryTabPrev"); // L/R 肩键:切换到上一 Tab
CreateAsset<VoidEventChannelSO> ("UI/Inventory", "EVT_QuickOpenMap"); // 快速直达:打开统一屏并定位地图 Tab默认 M
CreateAsset<StringEventChannelSO> ("UI/Inventory", "EVT_ItemAcquired"); // 道具首次获得itemId
CreateAsset<VoidEventChannelSO> ("UI/Inventory", "EVT_InventoryChanged"); // 背包内容变化(无负载)
@@ -154,6 +155,7 @@ namespace BaseGames.Editor
CreateAsset<CharmEventChannelSO> ("Progression", "EVT_CharmEquipped");
CreateAsset<CharmEventChannelSO> ("Progression", "EVT_CharmUnequipped");
CreateAsset<VoidEventChannelSO> ("Progression", "EVT_EquipmentChanged");
CreateAsset<StringEventChannelSO> ("Progression", "EVT_BestiaryUpdated");
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();

View File

@@ -145,10 +145,17 @@ namespace BaseGames.Editor
GameObject settingsRootGo = GetOrCreateChild(uiRootGo.transform, "SettingsRoot").gameObject;
GameObject mapRootGo = GetOrCreateChild(uiRootGo.transform, "MapRoot").gameObject;
GameObject shopRootGo = GetOrCreateChild(uiRootGo.transform, "ShopRoot").gameObject;
// 形态技能一览 / 能力解锁总览(实例化预制件,注册为 PanelId.FormSkills / Abilities供暂停菜单打开
GameObject formSkillRootGo = EnsureUIPanelInstance(uiRootGo.transform, "FormSkillRoot",
"Assets/_Game/Prefabs/UI/UI_FormSkillPanel.prefab", report);
GameObject abilityRootGo = EnsureUIPanelInstance(uiRootGo.transform, "AbilityRoot",
"Assets/_Game/Prefabs/UI/UI_AbilityOverviewPanel.prefab", report);
pauseRootGo.SetActive(false);
settingsRootGo.SetActive(false);
mapRootGo.SetActive(false);
shopRootGo.SetActive(false);
formSkillRootGo.SetActive(false);
abilityRootGo.SetActive(false);
GameObject deathCanvasGo = GetOrCreateCanvas(uiRootGo.transform, "DeathScreen Canvas", 10);
GameObject deathRootGo = GetOrCreateChild(deathCanvasGo.transform, "DeathScreenRoot").gameObject;
@@ -268,7 +275,7 @@ namespace BaseGames.Editor
// UIManager uses _panels (PanelRegistration[]) — NOT individual _pauseMenuRoot/_settingsRoot etc.
var so = new SerializedObject(uiManager);
var panelsProp = so.FindProperty("_panels");
panelsProp.arraySize = 4;
panelsProp.arraySize = 6;
var p0 = panelsProp.GetArrayElementAtIndex(0);
p0.FindPropertyRelative("id").intValue = (int)PanelId.Pause;
p0.FindPropertyRelative("root").objectReferenceValue = pauseRootGo;
@@ -281,6 +288,12 @@ namespace BaseGames.Editor
var p3 = panelsProp.GetArrayElementAtIndex(3);
p3.FindPropertyRelative("id").intValue = (int)PanelId.Shop;
p3.FindPropertyRelative("root").objectReferenceValue = shopRootGo;
var p4 = panelsProp.GetArrayElementAtIndex(4);
p4.FindPropertyRelative("id").intValue = (int)PanelId.FormSkills;
p4.FindPropertyRelative("root").objectReferenceValue = formSkillRootGo;
var p5 = panelsProp.GetArrayElementAtIndex(5);
p5.FindPropertyRelative("id").intValue = (int)PanelId.Abilities;
p5.FindPropertyRelative("root").objectReferenceValue = abilityRootGo;
so.ApplyModifiedPropertiesWithoutUndo();
}
AssignAsset(uiManager, "_onGameStateChanged", report, true, "EVT_GameStateChanged", "EVT_GameState");
@@ -1435,6 +1448,29 @@ namespace BaseGames.Editor
/// 历史的非预制件裸物体会被替换为预制件实例;绑定 <c>_config</c> 与三个加载事件频道。
/// 预制件缺失时仅在 report 提示(先跑「生成加载界面」菜单),不报错。
/// </summary>
/// <summary>
/// 通用:实例化 / 复用一个自足 UI 面板预制件为指定命名根(自身已绑好引用,不再额外绑定)。
/// 历史裸物体会被替换为预制件实例。预制件缺失时仅 report 提示,返回占位根(不报错)。
/// </summary>
private static GameObject EnsureUIPanelInstance(Transform uiParent, string instName, string prefabPath, List<string> report)
{
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
Transform existing = uiParent.Find(instName);
if (prefab == null)
{
report.Add($"缺少预制件 {prefabPath}请先运行对应「BaseGames/UI/控件库」生成菜单)。");
return existing != null ? existing.gameObject : GetOrCreateChild(uiParent, instName).gameObject;
}
if (existing != null && PrefabUtility.GetCorrespondingObjectFromSource(existing.gameObject) != null)
return existing.gameObject;
if (existing != null) Undo.DestroyObjectImmediate(existing.gameObject);
var go = (GameObject)PrefabUtility.InstantiatePrefab(prefab, uiParent);
go.name = instName;
Undo.RegisterCreatedObjectUndo(go, $"Instantiate {instName}");
report.Add($"{instName}:由 {System.IO.Path.GetFileName(prefabPath)} 实例化。");
return go;
}
private static void EnsureLoadingScreenInstance(Transform uiParent, List<string> report)
{
const string instName = "Canvas_Loading";

View File

@@ -0,0 +1,216 @@
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
using BaseGames.UI;
using BaseGames.Enemies;
using BaseGames.Localization;
using BaseGames.Editor.Localization;
namespace BaseGames.Editor.UI
{
/// <summary>
/// 图鉴条目同步 / 校验工具(策划友好)。从现有敌人数据自动补全 <see cref="BestiaryDatabaseSO"/>
/// <list type="bullet">
/// <item>来源 AAssets/_Game/Data/Enemies/{id}/ 下的 EnemyStatsSO文件夹名即 enemyId读 MaxHP</item>
/// <item>来源 B含 EnemyBase 的预制件(权威 _enemyId + StatsSO.MaxHP + Boss 判定),优先级高于 A</item>
/// </list>
/// 仅"补全缺失":已存在条目的策划字段(名/图标/描述/分级)一律保留,只在 displayMaxHP 为 0 时回填。
/// 新增条目自动生成 ENM_{id}_NAME / ENM_{id}_DESC 占位本地化(已存在不覆盖)。
/// 孤儿条目enemyId 无对应敌人数据,常为手敲错字)仅警告,不删除。
///
/// 菜单BaseGames/UI/控件库/同步图鉴条目(从敌人数据) · 校验图鉴条目
/// </summary>
public static class BestiarySyncTool
{
private const string DbPath = "Assets/_Game/Data/UI/UI_BestiaryDatabase.asset";
private const string EnemiesDir = "Assets/_Game/Data/Enemies";
private struct Src { public int hp; public bool boss; public string from; }
[MenuItem("BaseGames/UI/控件库/同步图鉴条目(从敌人数据)", priority = 300)]
public static void Sync()
{
var db = LoadDb();
if (db == null) return;
var discovered = Discover(out var srcLog);
var so = new SerializedObject(db);
var arr = so.FindProperty("_entries");
// 现有条目 id → 索引
var existing = new Dictionary<string, int>();
for (int i = 0; i < arr.arraySize; i++)
{
string id = arr.GetArrayElementAtIndex(i).FindPropertyRelative("enemyId").stringValue;
if (!string.IsNullOrEmpty(id) && !existing.ContainsKey(id)) existing[id] = i;
}
int added = 0, hpFilled = 0;
var newLocKeys = new List<string>();
foreach (var kv in discovered.OrderBy(k => k.Key))
{
string id = kv.Key;
if (existing.TryGetValue(id, out int idx))
{
// 已存在:仅在 HP 为 0 时回填,其余策划字段保留
var el = arr.GetArrayElementAtIndex(idx);
var hpProp = el.FindPropertyRelative("displayMaxHP");
if (hpProp.intValue == 0 && kv.Value.hp > 0) { hpProp.intValue = kv.Value.hp; hpFilled++; }
continue;
}
// 新增
int n = arr.arraySize;
arr.arraySize = n + 1;
var nel = arr.GetArrayElementAtIndex(n);
nel.FindPropertyRelative("enemyId").stringValue = id;
nel.FindPropertyRelative("displayNameKey").stringValue = $"ENM_{id}_NAME";
nel.FindPropertyRelative("descKey").stringValue = $"ENM_{id}_DESC";
nel.FindPropertyRelative("icon").objectReferenceValue = null;
nel.FindPropertyRelative("tier").enumValueIndex = kv.Value.boss ? 2 : 0; // Boss : Normal
nel.FindPropertyRelative("region").stringValue = "";
nel.FindPropertyRelative("fullLoreKillCount").intValue = 1;
nel.FindPropertyRelative("displayMaxHP").intValue = kv.Value.hp;
newLocKeys.Add(id);
added++;
}
so.ApplyModifiedPropertiesWithoutUndo();
EditorUtility.SetDirty(db);
int locAdded = SeedLocalization(newLocKeys);
// 孤儿DB 有、敌人数据无)
var orphans = existing.Keys.Where(id => !discovered.ContainsKey(id)).OrderBy(s => s).ToList();
AssetDatabase.SaveAssets();
Selection.activeObject = db;
EditorGUIUtility.PingObject(db);
var sb = new System.Text.StringBuilder();
sb.AppendLine($"[图鉴同步] 完成:新增 {added} 条 · 回填 HP {hpFilled} 条 · 本地化新增 {locAdded} 条 · 现有总计 {arr.arraySize} 条。");
sb.AppendLine($"发现敌人来源 {discovered.Count} 个:");
foreach (var l in srcLog) sb.AppendLine(" • " + l);
if (orphans.Count > 0)
sb.AppendLine($"⚠ 孤儿条目 {orphans.Count} 个enemyId 无对应敌人数据,请核对拼写,未自动删除):{string.Join(", ", orphans)}");
Debug.Log(sb.ToString(), db);
EditorUtility.DisplayDialog("图鉴同步",
$"新增 {added} 条,回填 HP {hpFilled} 条。\n现有总计 {arr.arraySize} 条。\n" +
(orphans.Count > 0 ? $"⚠ {orphans.Count} 个孤儿条目(见 Console。" : "无孤儿条目。") +
"\n\n详情见 Console已选中 UI_BestiaryDatabase。", "好");
}
[MenuItem("BaseGames/UI/控件库/校验图鉴条目", priority = 301)]
public static void Validate()
{
var db = LoadDb();
if (db == null) return;
var discovered = Discover(out _);
var so = new SerializedObject(db);
var arr = so.FindProperty("_entries");
var dbIds = new HashSet<string>();
var dupes = new List<string>();
var noKey = new List<string>();
for (int i = 0; i < arr.arraySize; i++)
{
var el = arr.GetArrayElementAtIndex(i);
string id = el.FindPropertyRelative("enemyId").stringValue;
if (string.IsNullOrEmpty(id)) { noKey.Add($"#{i}"); continue; }
if (!dbIds.Add(id)) dupes.Add(id);
if (string.IsNullOrEmpty(el.FindPropertyRelative("displayNameKey").stringValue))
noKey.Add(id);
}
var orphans = dbIds.Where(id => !discovered.ContainsKey(id)).OrderBy(s => s).ToList();
var missing = discovered.Keys.Where(id => !dbIds.Contains(id)).OrderBy(s => s).ToList();
var sb = new System.Text.StringBuilder("[图鉴校验]\n");
sb.AppendLine($"DB 条目 {arr.arraySize} · 敌人数据来源 {discovered.Count} · 已覆盖 {dbIds.Count - orphans.Count}/{discovered.Count}");
sb.AppendLine(missing.Count > 0 ? $"✗ 缺失(有敌人数据无条目){missing.Count}{string.Join(", ", missing)}" : "✓ 无缺失");
sb.AppendLine(orphans.Count > 0 ? $"⚠ 孤儿(条目无敌人数据){orphans.Count}{string.Join(", ", orphans)}" : "✓ 无孤儿");
sb.AppendLine(dupes.Count > 0 ? $"✗ 重复 enemyId {dupes.Count}{string.Join(", ", dupes)}" : "✓ 无重复");
sb.AppendLine(noKey.Count > 0 ? $"⚠ 缺 enemyId/名称 Key{string.Join(", ", noKey)}" : "✓ id/名称 Key 齐全");
Debug.Log(sb.ToString(), db);
EditorUtility.DisplayDialog("图鉴校验",
$"DB {arr.arraySize} 条 / 敌人数据 {discovered.Count} 个\n" +
$"缺失 {missing.Count} · 孤儿 {orphans.Count} · 重复 {dupes.Count}\n\n详情见 Console。",
missing.Count == 0 && orphans.Count == 0 && dupes.Count == 0 ? "全部通过" : "好");
}
// ── 发现敌人来源 ─────────────────────────────────────────────────────
private static Dictionary<string, Src> Discover(out List<string> log)
{
var map = new Dictionary<string, Src>();
log = new List<string>();
// 来源 AData/Enemies/{id}/ 子文件夹 + EnemyStatsSO
if (AssetDatabase.IsValidFolder(EnemiesDir))
{
foreach (var folder in AssetDatabase.GetSubFolders(EnemiesDir))
{
string id = folder.Substring(folder.LastIndexOf('/') + 1);
EnemyStatsSO stats = null;
foreach (var g in AssetDatabase.FindAssets("t:EnemyStatsSO", new[] { folder }))
{
stats = AssetDatabase.LoadAssetAtPath<EnemyStatsSO>(AssetDatabase.GUIDToAssetPath(g));
if (stats != null) break;
}
if (stats == null) continue; // 无 EnemyStatsSO 的文件夹不算敌人(跳过 Stats 等杂项目录)
map[id] = new Src { hp = stats.MaxHP, boss = false, from = "data" };
log.Add($"{id}data, HP={stats.MaxHP}");
}
}
// 来源 B含 EnemyBase 的预制件(权威 id优先覆盖
foreach (var g in AssetDatabase.FindAssets("t:Prefab"))
{
var go = AssetDatabase.LoadAssetAtPath<GameObject>(AssetDatabase.GUIDToAssetPath(g));
if (go == null) continue;
var eb = go.GetComponentInChildren<EnemyBase>(true);
if (eb == null || string.IsNullOrEmpty(eb.EnemyId)) continue;
int hp = eb.StatsSO != null ? eb.StatsSO.MaxHP : 0;
bool boss = eb.GetType().Name.IndexOf("Boss", System.StringComparison.OrdinalIgnoreCase) >= 0;
map[eb.EnemyId] = new Src { hp = hp, boss = boss, from = "prefab" };
log.Add($"{eb.EnemyId}prefab{(boss ? ",BOSS" : "")}, HP={hp}");
}
return map;
}
private static int SeedLocalization(List<string> ids)
{
if (ids == null || ids.Count == 0) return 0;
var zh = LocalizationFileIO.Read(Language.ChineseSimplified, LocalizationTable.UI);
var en = LocalizationFileIO.Read(Language.English, LocalizationTable.UI);
int added = 0;
foreach (var id in ids)
{
string nk = $"ENM_{id}_NAME", dk = $"ENM_{id}_DESC";
if (!zh.ContainsKey(nk)) { zh[nk] = $"敌人 {id}"; added++; }
if (!zh.ContainsKey(dk)) { zh[dk] = "(占位)该敌人的背景与弱点描述,由策划填写。"; added++; }
if (!en.ContainsKey(nk)) { en[nk] = $"Enemy {id}"; added++; }
if (!en.ContainsKey(dk)) { en[dk] = "(Placeholder) Lore and weakness, to be filled by design."; added++; }
}
if (added > 0)
{
LocalizationFileIO.Write(Language.ChineseSimplified, LocalizationTable.UI, zh);
LocalizationFileIO.Write(Language.English, LocalizationTable.UI, en);
}
return added;
}
private static BestiaryDatabaseSO LoadDb()
{
var db = AssetDatabase.LoadAssetAtPath<BestiaryDatabaseSO>(DbPath);
if (db == null)
EditorUtility.DisplayDialog("图鉴同步",
$"未找到 {DbPath}。\n请先运行「BaseGames/UI/控件库/生成图鉴(预制件 + 空表)」。", "好");
return db;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0fc04afec1231b24598e6b7bc81e7778
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -11,17 +11,30 @@ using UnityEngine.UI;
namespace BaseGames.Editor.UI
{
/// <summary>
/// 统一背包菜单脚手架(暂停菜单的 Tab Hub
/// 统一背包菜单脚手架(游戏内查看类面板的 Tab Hub
/// 在当前活动场景的 UIRoot 下生成 InventoryHub Canvas 完整层级,
/// 创建 Tab 头部栏与各 Tab 内容根,自动绑定事件频道并注册到 UIManager 面板栈。
/// 创建 Tab 头部栏与各 Tab 内容根,自动绑定事件频道并注册到 UIManager 面板栈PanelId.Inventory
/// 执行路径BaseGames ▸ Scene ▸ Setup ▸ Scaffold Inventory Hub
///
/// 设计与命名严格对照 <see cref="HUDScaffoldWizard"/>幂等、Undo 友好、报告未尽手动项。
/// 第一期 Tab结合本项目内容"工具"位由"形态技能"承载):
/// 地图(Map) · 形态技能(FormSkills) · 物品(Inventory)
/// 地图 / 形态技能:内嵌既有 standalone 预制件实例(编辑期中和自身 Canvas 链 + 隐藏 chrome
/// 单一面板逻辑两用 —— standalone 打开(全 chrome与 Hub Tab 内嵌(无 chrome。地图 standalone 仍保留 PanelId.Map。
/// 物品Hub 内联构建(与 EquipmentManager/InventoryManager 同源反应式刷新)。
/// 护符 / 能力 / 任务 / 图鉴:二期。
///
/// 设计与命名对照 <see cref="HUDScaffoldWizard"/>幂等重跑前整根清建、Undo 友好、报告未尽手动项。
/// </summary>
public static class InventoryHubScaffoldWizard
{
// Tab 顺序:Map · Inventory · Tools(护符) · Quests · Options
private static readonly string[] kTabNames = { "Map", "Inventory", "Tools", "Quests", "Options" };
// Tab 顺序:地图 / 形态技能 / 能力 / 护符 / 物品 / 任务 / 图鉴
private static readonly string[] kTabNames = { "Map", "FormSkills", "Abilities", "Charm", "Inventory", "Quests", "Bestiary" };
// 各 Tab 的内嵌 standalone 预制件名null = Hub 内联自建,不内嵌)
private static readonly string[] kEmbedPrefab = { "UI_MapPanel", "UI_FormSkillPanel", "UI_AbilityOverviewPanel", "UI_CharmPanel", null, null, "UI_BestiaryPanel" };
// 内嵌实例需隐藏的 chrome 子节点候选名(全屏遮罩 / 关闭按钮等;按名深度查找,命中才隐藏)
private static readonly string[] kChromeNames = { "Overlay", "Dim", "Btn_Close", "CloseButton", "Close" };
[MenuItem("BaseGames/Scene/Setup/Scaffold Inventory Hub", priority = 204)]
public static void ScaffoldInventoryHub()
@@ -33,21 +46,39 @@ namespace BaseGames.Editor.UI
// ── Canvas排序层 5HUD 之上、Pause 同级区间)─────────────────────
GameObject canvasGo = GetOrCreateHubCanvas("InventoryHub Canvas", 5);
// ── 幂等:整根清建(避免旧 Tab 结构残留)────────────────────────────
Transform oldRoot = canvasGo.transform.Find("InventoryHubRoot");
if (oldRoot != null) Object.DestroyImmediate(oldRoot.gameObject);
// ── Hub 根 ─────────────────────────────────────────────────────────
GameObject hubGo = GetOrCreateChild(canvasGo.transform, "InventoryHubRoot").gameObject;
GameObject hubGo = new GameObject("InventoryHubRoot", typeof(RectTransform));
Undo.RegisterCreatedObjectUndo(hubGo, "Create InventoryHubRoot");
hubGo.transform.SetParent(canvasGo.transform, false);
Stretch((RectTransform)hubGo.transform);
InventoryHubPanel hub = GetOrAddComponent<InventoryHubPanel>(hubGo);
CanvasGroup hubGroup = GetOrAddComponent<CanvasGroup>(hubGo);
RectTransform hubRect = GetOrAddComponent<RectTransform>(hubGo);
RectTransform hubRect = (RectTransform)hubGo.transform;
// 打开时冻结游戏 + 切 UI 输入;关闭时恢复(修复"开菜单后 Esc 不暂停")。
var pauseScope = GetOrAddComponent<BaseGames.UI.MenuPauseScope>(hubGo);
AssignAsset(pauseScope, "_inputReader", report, false, "InputReader");
// ── Tab 头部栏 ─────────────────────────────────────────────────────
GameObject tabBarGo = GetOrCreateChild(hubGo.transform, "TabBar").gameObject;
SetRect((RectTransform)tabBarGo.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0.5f, 1f),
new Vector2(0f, -36f), new Vector2(900f, 56f));
var tabBarLayout = GetOrAddComponent<HorizontalLayoutGroup>(tabBarGo);
tabBarLayout.childForceExpandWidth = false;
tabBarLayout.childForceExpandHeight = false;
tabBarLayout.childAlignment = TextAnchor.MiddleCenter;
tabBarLayout.spacing = 8f;
// ── Tab 内容容器 ───────────────────────────────────────────────────
GameObject contentGo = GetOrCreateChild(hubGo.transform, "TabContent").gameObject;
SetRect((RectTransform)contentGo.transform, Vector2.zero, Vector2.one, new Vector2(0.5f, 0.5f),
Vector2.zero, Vector2.zero);
((RectTransform)contentGo.transform).offsetMin = new Vector2(0f, 0f);
((RectTransform)contentGo.transform).offsetMax = new Vector2(0f, -72f); // 留出顶部 TabBar
var headerButtons = new Button[kTabNames.Length];
var headerHighlights = new GameObject[kTabNames.Length];
@@ -57,28 +88,52 @@ namespace BaseGames.Editor.UI
{
// Tab 头按钮
GameObject headerGo = GetOrCreateChild(tabBarGo.transform, $"Tab_{kTabNames[i]}").gameObject;
GetOrAddComponent<Image>(headerGo);
var headerLe = GetOrAddComponent<LayoutElement>(headerGo);
headerLe.preferredWidth = 200f; headerLe.preferredHeight = 48f;
var headerImg = GetOrAddComponent<Image>(headerGo);
headerImg.color = new Color(0.12f, 0.13f, 0.17f, 0.88f); // 深底,保证白字可见
headerButtons[i] = GetOrAddComponent<Button>(headerGo);
GameObject hlGo = GetOrCreateChild(headerGo.transform, "Highlight").gameObject;
GetOrAddComponent<Image>(hlGo);
var hlImg = GetOrAddComponent<Image>(hlGo);
hlImg.color = new Color(0.85f, 0.80f, 0.55f, 0.45f); // 选中高亮(米金,覆盖深底)
Stretch((RectTransform)hlGo.transform);
hlGo.SetActive(false);
headerHighlights[i] = hlGo;
GameObject labelGo = GetOrCreateChild(headerGo.transform, "Label").gameObject;
Stretch((RectTransform)labelGo.transform);
var label = GetOrAddComponent<TextMeshProUGUI>(labelGo);
label.text = kTabNames[i];
label.color = Color.white;
label.alignment = TextAlignmentOptions.Center; label.fontSize = 24f; label.raycastTarget = false;
// Tab 头标签走本地化 key地图/形态技能/物品)
var loc = GetOrAddComponent<BaseGames.Localization.LocalizedText>(labelGo);
SetString(loc, "_key", TabLabelKey(kTabNames[i]));
label.text = kTabNames[i]; // 编辑期占位,运行期由 LocalizedText 覆盖
// Tab 内容根
// Tab 内容根(铺满内容容器)
GameObject tabRoot = GetOrCreateChild(contentGo.transform, $"Content_{kTabNames[i]}").gameObject;
Stretch((RectTransform)tabRoot.transform);
contentRoots[i] = tabRoot;
tabRoot.SetActive(i == 0);
}
// ── 各 Tab 专属内容 ────────────────────────────────────────────────
BuildInventoryTab(contentRoots[1], report); // Inventory
BuildQuestsTab(contentRoots[3], report); // Quests
report.Add("Map TabContent_Map将现有 MapPanel 预制 / 节点作为子物体放入,或在此挂载 MapPanel 组件并配置。");
report.Add("Tools TabContent_Tools将现有 CharmEquipPanel 节点作为子物体放入。");
report.Add("Options TabContent_Options将现有 SettingsPanelController 节点作为子物体放入。");
// ── 各 Tab 内容 ────────────────────────────────────────────────────
for (int i = 0; i < kTabNames.Length; i++)
{
if (kEmbedPrefab[i] != null)
{
EmbedPrefabAsTab(contentRoots[i], kEmbedPrefab[i], report);
}
else if (kTabNames[i] == "Inventory")
{
AddTabBackground(contentRoots[i]); // 内联 Tab 补深底,视觉对齐内嵌 Tab
BuildInventoryTab(contentRoots[i], report);
}
else if (kTabNames[i] == "Quests")
{
AddTabBackground(contentRoots[i]);
BuildQuestsTab(contentRoots[i], report);
}
}
// ── Hub 字段绑定 ───────────────────────────────────────────────────
AssignRef(hub, "_rootGroup", hubGroup);
@@ -94,10 +149,79 @@ namespace BaseGames.Editor.UI
hubGo.SetActive(false); // 面板默认隐藏,由 UIManager.OpenPanel 激活
Undo.CollapseUndoOperations(undoGroup);
MarkDirtyAndLog("Inventory Hub 脚手架", canvasGo, report);
MarkDirtyAndLog("Inventory Hub 脚手架(地图/形态技能/物品)", canvasGo, report);
}
// ── Inventory Tab道具背包────────────────────────────────────────────
private static string TabLabelKey(string tab) => tab switch
{
"Map" => "MENU_MAP",
"FormSkills" => "FORMSKILL_TITLE",
"Abilities" => "ABL_OVERVIEW_TITLE",
"Charm" => "MENU_CHARM",
"Inventory" => "MENU_INVENTORY",
"Quests" => "MENU_QUESTS",
"Bestiary" => "MENU_BESTIARY",
_ => tab,
};
// ── 内嵌 standalone 预制件作 Tab 内容(编辑期中和 Canvas 链 + 隐藏 chrome──
private static void EmbedPrefabAsTab(GameObject contentRoot, string prefabName, List<string> report)
{
GameObject prefab = FindPrefab(prefabName);
if (prefab == null)
{
report.Add($"内嵌预制件 {prefabName} 未找到,{contentRoot.name} 留空(地图需先运行 Scaffold Map UI 并抽出 UI_MapPanel形态技能需先运行「生成形态技能一览」。");
return;
}
var inst = (GameObject)PrefabUtility.InstantiatePrefab(prefab, contentRoot.transform);
Undo.RegisterCreatedObjectUndo(inst, $"Embed {prefabName}");
// 解除预制件连接,便于就地中和 chromeTab 内嵌为快照,刷新重跑脚手架即可)
PrefabUtility.UnpackPrefabInstance(inst, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction);
// 中和自身 Canvas 链 —— 改用 Hub 的单一 Canvas 渲染(必须移除组件,禁用会令子树整体不渲染)
DestroyIfPresent<GraphicRaycaster>(inst);
DestroyIfPresent<CanvasScaler>(inst);
DestroyIfPresent<Canvas>(inst);
// 铺满 Tab 内容区
if (inst.transform is RectTransform rt)
{
rt.anchorMin = Vector2.zero; rt.anchorMax = Vector2.one;
rt.offsetMin = Vector2.zero; rt.offsetMax = Vector2.zero;
rt.localScale = Vector3.one;
}
// 隐藏 chrome全屏遮罩 / 关闭按钮)
foreach (string n in kChromeNames)
{
Transform t = FindDeep(inst.transform, n);
if (t != null) t.gameObject.SetActive(false);
}
inst.SetActive(true);
report.Add($"{contentRoot.name} ← 内嵌 {prefabName}(已中和 Canvas 链,隐藏 chrome。");
}
// ── 内联 Tab 背景(对齐内嵌 Tab 的 DialogBox 深底,避免透出下层)──────────
private static void AddTabBackground(GameObject root)
{
if (root.transform.Find("Background") != null) return; // 幂等
GameObject bgGo = new GameObject("Background", typeof(RectTransform));
Undo.RegisterCreatedObjectUndo(bgGo, "Create Tab Background");
bgGo.transform.SetParent(root.transform, false);
bgGo.transform.SetAsFirstSibling();
var rt = (RectTransform)bgGo.transform;
rt.anchorMin = Vector2.zero; rt.anchorMax = Vector2.one;
rt.offsetMin = new Vector2(40f, 40f); rt.offsetMax = new Vector2(-40f, -40f);
var img = bgGo.AddComponent<Image>();
img.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>("UI/Skin/UISprite.psd");
img.type = Image.Type.Sliced;
img.color = new Color(0.10f, 0.11f, 0.15f, 0.98f);
img.raycastTarget = false;
}
// ── Inventory Tab道具背包Hub 内联)──────────────────────────────────
private static void BuildInventoryTab(GameObject root, List<string> report)
{
ItemInventoryPanel panel = GetOrAddComponent<ItemInventoryPanel>(root);
@@ -155,7 +279,7 @@ namespace BaseGames.Editor.UI
AssignAsset(panel, "_onInventoryChanged", report, false, "EVT_InventoryChanged");
}
// ── Quests Tab任务日志)───────────────────────────────────────────────
// ── Quests Tab任务日志Hub 内联)─────────────────────────────────────
private static void BuildQuestsTab(GameObject root, List<string> report)
{
QuestLogPanel panel = GetOrAddComponent<QuestLogPanel>(root);
@@ -218,7 +342,6 @@ namespace BaseGames.Editor.UI
return;
}
// 检查是否已注册 PanelId.Inventory幂等
int inventoryId = (int)PanelId.Inventory;
for (int i = 0; i < panelsProp.arraySize; i++)
{
@@ -227,6 +350,7 @@ namespace BaseGames.Editor.UI
{
el.FindPropertyRelative("root").objectReferenceValue = hubGo;
so.ApplyModifiedPropertiesWithoutUndo();
AssignAsset(uiManager, "_onInventoryOpen", report, false, "EVT_InventoryOpen");
return;
}
}
@@ -259,8 +383,36 @@ namespace BaseGames.Editor.UI
}
// ─────────────────────────────────────────────────────────────────────
// Helpers(对照 HUDScaffoldWizard
// Helpers
// ─────────────────────────────────────────────────────────────────────
private static GameObject FindPrefab(string prefabName)
{
foreach (string guid in AssetDatabase.FindAssets($"{prefabName} t:Prefab"))
{
string path = AssetDatabase.GUIDToAssetPath(guid);
var go = AssetDatabase.LoadAssetAtPath<GameObject>(path);
if (go != null && go.name == prefabName) return go;
}
return null;
}
private static void DestroyIfPresent<T>(GameObject go) where T : Component
{
var c = go.GetComponent<T>();
if (c != null) Object.DestroyImmediate(c);
}
private static Transform FindDeep(Transform root, string name)
{
if (root.name == name) return root;
for (int i = 0; i < root.childCount; i++)
{
Transform found = FindDeep(root.GetChild(i), name);
if (found != null) return found;
}
return null;
}
private static GameObject GetOrCreateHubCanvas(string name, int sortOrder)
{
Scene scene = SceneManager.GetActiveScene();
@@ -301,7 +453,7 @@ namespace BaseGames.Editor.UI
{
Transform child = parent.Find(name);
if (child != null) return child;
GameObject go = new GameObject(name);
GameObject go = new GameObject(name, typeof(RectTransform));
Undo.RegisterCreatedObjectUndo(go, $"Create {name}");
go.transform.SetParent(parent, false);
return go.transform;
@@ -313,6 +465,26 @@ namespace BaseGames.Editor.UI
return c != null ? c : Undo.AddComponent<T>(go);
}
private static void Stretch(RectTransform rt)
{
rt.anchorMin = Vector2.zero; rt.anchorMax = Vector2.one;
rt.offsetMin = Vector2.zero; rt.offsetMax = Vector2.zero;
}
private static void SetRect(RectTransform rt, Vector2 aMin, Vector2 aMax, Vector2 pivot, Vector2 pos, Vector2 size)
{
rt.anchorMin = aMin; rt.anchorMax = aMax; rt.pivot = pivot;
rt.anchoredPosition = pos; rt.sizeDelta = size;
}
private static void SetString(Component c, string prop, string value)
{
if (c == null) return;
var so = new SerializedObject(c);
var p = so.FindProperty(prop);
if (p != null) { p.stringValue = value; so.ApplyModifiedPropertiesWithoutUndo(); }
}
private static void AssignRef(Object target, string propertyName, Object value)
{
var so = new SerializedObject(target);

View File

@@ -0,0 +1,250 @@
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using BaseGames.UI;
using BaseGames.UI.Theme;
using BaseGames.Player;
using BaseGames.Core.Events;
using BaseGames.Localization;
using BaseGames.Editor.Localization;
namespace BaseGames.Editor.UI
{
/// <summary>
/// 能力解锁总览脚手架:生成 <c>UI_AbilityCell</c> + <c>UI_AbilityOverviewPanel</c> 预制件
/// + 默认 <c>UI_AbilityMeta</c> 表(参照 AbilityTypeDrawer 分组)+ ABL_* 中英文案。
/// 面板据 AbilityMetaSO 列出全部能力 + 已解锁(亮)/未解锁(暗+锁)态,订阅 EVT_AbilityUnlocked 实时刷新。
///
/// 菜单BaseGames/UI/控件库/生成能力解锁总览(预制件 + 默认表)
/// </summary>
public static class UIAbilityOverviewScaffold
{
private const string PrefabDir = "Assets/_Game/Prefabs/UI";
private const string ControlsDir = "Assets/_Game/Prefabs/UI/Controls";
private const string ConfigDir = "Assets/_Game/Data/UI";
private const string ThemePath = "Assets/_Game/Data/UI/Themes/UI_Theme_Default.asset";
private const string PanelName = "UI_AbilityOverviewPanel";
private const string CellName = "UI_AbilityCell";
private const string MetaName = "UI_AbilityMeta";
// 默认能力项(参照 Editor/Equipment/AbilityTypeDrawer.Groupstype, labelKey, 中文, 英文
private static readonly (AbilityType t, string key, string zh, string en)[] Defaults =
{
(AbilityType.WallCling, "ABL_WALLCLING", "贴墙悬挂", "Wall Cling"),
(AbilityType.WallJump, "ABL_WALLJUMP", "墙跳", "Wall Jump"),
(AbilityType.Dash, "ABL_DASH", "冲刺", "Dash"),
(AbilityType.DoubleJump, "ABL_DOUBLEJUMP", "二段跳", "Double Jump"),
(AbilityType.SuperJump, "ABL_SUPERJUMP", "超级跳", "Super Jump"),
(AbilityType.Swim, "ABL_SWIM", "游泳", "Swim"),
(AbilityType.DownDash, "ABL_DOWNDASH", "下冲刺", "Down Dash"),
(AbilityType.InvincibleDash,"ABL_INVINCIBLEDASH","无敌冲刺","Invincible Dash"),
(AbilityType.Spell1, "ABL_SPELL1", "法术槽 1", "Spell Slot 1"),
(AbilityType.Spell2, "ABL_SPELL2", "法术槽 2", "Spell Slot 2"),
(AbilityType.Spell3, "ABL_SPELL3", "法术槽 3", "Spell Slot 3"),
(AbilityType.SpiritForm, "ABL_SPIRITFORM", "灵魄形态", "Spirit Form"),
(AbilityType.SpiritDash, "ABL_SPIRITDASH", "灵魄冲刺", "Spirit Dash"),
(AbilityType.FormTianHun, "ABL_FORM_TIANHUN", "天魂", "Sky Soul"),
(AbilityType.FormDiHun, "ABL_FORM_DIHUN", "地魂", "Earth Soul"),
(AbilityType.FormMingHun, "ABL_FORM_MINGHUN", "命魂", "Death Soul"),
(AbilityType.Parry, "ABL_PARRY", "弹反", "Parry"),
(AbilityType.ChargeAttack, "ABL_CHARGEATTACK", "蓄力攻击", "Charge Attack"),
(AbilityType.DownSlash, "ABL_DOWNSLASH", "下斩", "Down Slash"),
(AbilityType.Interact, "ABL_INTERACT", "互动", "Interact"),
(AbilityType.FastTravel, "ABL_FASTTRAVEL", "快速旅行", "Fast Travel"),
};
[MenuItem("BaseGames/UI/控件库/生成能力解锁总览(预制件 + 默认表)")]
public static void GeneratePrefab()
{
EnsureFolder(PrefabDir); EnsureFolder(ControlsDir); EnsureFolder(ConfigDir);
var report = new List<string>();
var theme = AssetDatabase.LoadAssetAtPath<UIThemeSO>(ThemePath);
var meta = EnsureMeta(report);
SeedLocalization(report);
var cell = BuildCellPrefab(theme, report);
BuildPanelPrefab(theme, meta, cell, report);
AssetDatabase.SaveAssets(); AssetDatabase.Refresh();
var sb = new System.Text.StringBuilder("[UIAbilityOverview] 能力总览已生成:\n");
foreach (var r in report) sb.AppendLine(" • " + r);
sb.AppendLine("策划改 UI_AbilityMeta 增删/重排能力;美术改 UI_AbilityCell / 面板预制件改样式。");
Debug.Log(sb.ToString());
}
private static AbilityMetaSO EnsureMeta(List<string> report)
{
string path = $"{ConfigDir}/{MetaName}.asset";
var meta = AssetDatabase.LoadAssetAtPath<AbilityMetaSO>(path);
bool created = meta == null;
if (created) { meta = ScriptableObject.CreateInstance<AbilityMetaSO>(); AssetDatabase.CreateAsset(meta, path); }
if (created)
{
var so = new SerializedObject(meta);
var p = so.FindProperty("_items");
p.arraySize = Defaults.Length;
for (int i = 0; i < Defaults.Length; i++)
{
var el = p.GetArrayElementAtIndex(i);
el.FindPropertyRelative("type").enumValueFlag = (int)(uint)Defaults[i].t;
el.FindPropertyRelative("labelKey").stringValue = Defaults[i].key;
}
so.ApplyModifiedPropertiesWithoutUndo();
report.Add($"{path}(默认 {Defaults.Length} 项能力)");
}
return meta;
}
private static void SeedLocalization(List<string> report)
{
var zh = new Dictionary<string, string> { { "ABL_OVERVIEW_TITLE", "能力" } };
var en = new Dictionary<string, string> { { "ABL_OVERVIEW_TITLE", "Abilities" } };
foreach (var d in Defaults) { zh[d.key] = d.zh; en[d.key] = d.en; }
int added = MergeWriteUI(Language.ChineseSimplified, zh) + MergeWriteUI(Language.English, en);
report.Add($"本地化新增 {added} 条(已存在不覆盖)。");
}
private static int MergeWriteUI(Language lang, Dictionary<string, string> kv)
{
var dict = LocalizationFileIO.Read(lang, LocalizationTable.UI);
int added = 0;
foreach (var p in kv) if (!dict.ContainsKey(p.Key)) { dict[p.Key] = p.Value; added++; }
if (added > 0) LocalizationFileIO.Write(lang, LocalizationTable.UI, dict);
return added;
}
// ── 单元格预制件 ─────────────────────────────────────────────────────
private static AbilityCellView BuildCellPrefab(UIThemeSO theme, List<string> report)
{
var root = new GameObject(CellName, typeof(RectTransform), typeof(CanvasGroup));
((RectTransform)root.transform).sizeDelta = new Vector2(180f, 150f);
var view = root.AddComponent<AbilityCellView>();
var bg = root.AddComponent<Image>();
bg.sprite = Std(); bg.type = Image.Type.Sliced; bg.color = new Color(1f, 1f, 1f, 0.05f);
var iconGo = NewUIChild(root.transform, "Icon", out var iconRt);
SetRect(iconRt, C(0.5f, 1f), C(0.5f, 1f), C(0.5f, 1f), new Vector2(0f, -50f), new Vector2(72f, 72f));
var icon = iconGo.AddComponent<Image>(); icon.preserveAspect = true; icon.raycastTarget = false;
var nameGo = NewUIChild(root.transform, "Name", out var nameRt);
SetRect(nameRt, C(0.5f, 0f), C(0.5f, 0f), C(0.5f, 0f), new Vector2(0f, 18f), new Vector2(-12f, 44f));
var nameTmp = nameGo.AddComponent<TextMeshProUGUI>();
nameTmp.alignment = TextAlignmentOptions.Center; nameTmp.fontSize = 20f; nameTmp.enableWordWrapping = true;
nameTmp.raycastTarget = false;
var loc = nameGo.AddComponent<LocalizedText>();
SetEnum(nameGo.AddComponent<UIThemeRole>(), "_kind", (int)UIThemeRoleKind.Text_Primary);
// 锁定遮罩(未解锁时显示):半透明暗罩(美术可替换为锁图标 sprite
var lockGo = NewUIChild(root.transform, "LockedOverlay", out var lockRt);
Stretch(lockRt);
var lockImg = lockGo.AddComponent<Image>(); lockImg.color = new Color(0f, 0f, 0f, 0.55f); lockImg.raycastTarget = false;
lockGo.SetActive(false);
var so = new SerializedObject(view);
so.FindProperty("_icon").objectReferenceValue = icon;
so.FindProperty("_label").objectReferenceValue = loc;
so.FindProperty("_lockedOverlay").objectReferenceValue = lockGo;
so.FindProperty("_group").objectReferenceValue = root.GetComponent<CanvasGroup>();
so.ApplyModifiedPropertiesWithoutUndo();
string path = $"{ControlsDir}/{CellName}.prefab";
var asset = PrefabUtility.SaveAsPrefabAsset(root, path);
Object.DestroyImmediate(root);
report.Add(path);
return asset.GetComponent<AbilityCellView>();
}
// ── 面板预制件 ───────────────────────────────────────────────────────
private static void BuildPanelPrefab(UIThemeSO theme, AbilityMetaSO meta, AbilityCellView cell, List<string> report)
{
var root = new GameObject(PanelName,
typeof(RectTransform), typeof(Canvas), typeof(CanvasScaler), typeof(GraphicRaycaster), typeof(CanvasGroup));
Stretch((RectTransform)root.transform);
SetupCanvas(root, 60);
var panel = root.AddComponent<DataDrivenAbilityPanel>();
var applier = root.AddComponent<UIThemeApplier>();
if (theme != null) AssignRef(applier, "_theme", theme);
var overlayGo = NewUIChild(root.transform, "Overlay", out var ovRt);
Stretch(ovRt);
overlayGo.AddComponent<Image>().color = new Color(0f, 0f, 0f, 0.6f);
var boxGo = NewUIChild(root.transform, "DialogBox", out var boxRt);
SetRect(boxRt, C(0.5f), C(0.5f), C(0.5f), Vector2.zero, new Vector2(1120f, 760f));
var box = boxGo.AddComponent<Image>(); box.sprite = Std(); box.type = Image.Type.Sliced;
box.color = new Color(0.10f, 0.11f, 0.15f, 0.98f);
SetEnum(boxGo.AddComponent<UIThemeRole>(), "_kind", (int)UIThemeRoleKind.Graphic_Background);
var titleGo = NewUIChild(boxGo.transform, "Title", out var titleRt);
SetRect(titleRt, C(0.5f, 1f), C(0.5f, 1f), C(0.5f, 1f), new Vector2(0f, -48f), new Vector2(-60f, 56f));
var title = titleGo.AddComponent<TextMeshProUGUI>();
title.alignment = TextAlignmentOptions.Center; title.fontSize = 40f; title.raycastTarget = false;
var titleLoc = titleGo.AddComponent<LocalizedText>();
SetString(titleLoc, "_key", "ABL_OVERVIEW_TITLE");
SetEnum(titleGo.AddComponent<UIThemeRole>(), "_kind", (int)UIThemeRoleKind.Text_Header);
// 能力格容器(网格)
var gridGo = NewUIChild(boxGo.transform, "GridContainer", out var gridRt);
SetRect(gridRt, C(0.5f, 0.5f), C(0.5f, 0.5f), C(0.5f, 0.5f), new Vector2(0f, 10f), new Vector2(1056f, 600f));
var grid = gridGo.AddComponent<GridLayoutGroup>();
// 6 列21 项 → 4 行,落在框内不溢出(美术可在预制件再调列数/格子尺寸)
grid.cellSize = new Vector2(160f, 130f); grid.spacing = new Vector2(16f, 14f);
grid.childAlignment = TextAnchor.UpperCenter;
grid.constraint = GridLayoutGroup.Constraint.FixedColumnCount; grid.constraintCount = 6;
var closeGo = NewUIChild(boxGo.transform, "Btn_Close", out var closeRt);
SetRect(closeRt, C(0.5f, 0f), C(0.5f, 0f), C(0.5f, 0f), new Vector2(0f, 36f), new Vector2(240f, 56f));
var closeImg = closeGo.AddComponent<Image>(); closeImg.sprite = Std(); closeImg.type = Image.Type.Sliced;
closeImg.color = new Color(1f, 1f, 1f, 0.06f);
var closeBtn = closeGo.AddComponent<Button>(); closeBtn.targetGraphic = closeImg;
var clblGo = NewUIChild(closeGo.transform, "Label", out var clblRt);
Stretch(clblRt);
var clbl = clblGo.AddComponent<TextMeshProUGUI>();
clbl.alignment = TextAlignmentOptions.Center; clbl.fontSize = 26f;
clblGo.AddComponent<LocalizedText>();
SetString(clblGo.GetComponent<LocalizedText>(), "_key", "BTN_BACK");
SetEnum(clblGo.AddComponent<UIThemeRole>(), "_kind", (int)UIThemeRoleKind.Text_Primary);
var so = new SerializedObject(panel);
so.FindProperty("_meta").objectReferenceValue = meta;
so.FindProperty("_container").objectReferenceValue = gridRt;
so.FindProperty("_cellPrefab").objectReferenceValue = cell;
so.FindProperty("_btnClose").objectReferenceValue = closeBtn;
so.FindProperty("_onAbilityUnlocked").objectReferenceValue = FindAsset<AbilityTypeEventChannelSO>("EVT_AbilityUnlocked");
so.ApplyModifiedPropertiesWithoutUndo();
root.SetActive(false);
PrefabUtility.SaveAsPrefabAsset(root, $"{PrefabDir}/{PanelName}.prefab");
Object.DestroyImmediate(root);
report.Add($"{PrefabDir}/{PanelName}.prefab");
}
// ── 助手 ─────────────────────────────────────────────────────────────
private static Vector2 C(float x = 0.5f, float y = 0.5f) => new Vector2(x, y);
private static GameObject NewUIChild(Transform parent, string name, out RectTransform rt)
{ var go = new GameObject(name, typeof(RectTransform)); rt = (RectTransform)go.transform; rt.SetParent(parent, false); return go; }
private static void Stretch(RectTransform rt) { rt.anchorMin = Vector2.zero; rt.anchorMax = Vector2.one; rt.offsetMin = Vector2.zero; rt.offsetMax = Vector2.zero; }
private static void SetRect(RectTransform rt, Vector2 aMin, Vector2 aMax, Vector2 pivot, Vector2 pos, Vector2 size)
{ rt.anchorMin = aMin; rt.anchorMax = aMax; rt.pivot = pivot; rt.anchoredPosition = pos; rt.sizeDelta = size; }
private static void SetEnum(Component c, string prop, int value) { var so = new SerializedObject(c); var p = so.FindProperty(prop); if (p != null) { p.enumValueIndex = value; so.ApplyModifiedPropertiesWithoutUndo(); } }
private static void SetString(Component c, string prop, string value) { if (c == null) return; var so = new SerializedObject(c); var p = so.FindProperty(prop); if (p != null) { p.stringValue = value; so.ApplyModifiedPropertiesWithoutUndo(); } }
private static void AssignRef(Object target, string prop, Object value) { var so = new SerializedObject(target); var p = so.FindProperty(prop); if (p != null) { p.objectReferenceValue = value; so.ApplyModifiedPropertiesWithoutUndo(); } }
private static T FindAsset<T>(string name) where T : Object
{ foreach (var g in AssetDatabase.FindAssets($"{name} t:{typeof(T).Name}")) { var pa = AssetDatabase.GUIDToAssetPath(g); var a = AssetDatabase.LoadAssetAtPath<T>(pa); if (a != null && a.name == name) return a; } return null; }
private static void SetupCanvas(GameObject go, int sortOrder)
{
var canvas = go.GetComponent<Canvas>();
canvas.renderMode = RenderMode.ScreenSpaceOverlay; canvas.sortingOrder = sortOrder;
var scaler = go.GetComponent<CanvasScaler>();
scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
scaler.referenceResolution = new Vector2(1920f, 1080f);
scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight;
scaler.matchWidthOrHeight = 0.5f;
}
private static Sprite Std() => AssetDatabase.GetBuiltinExtraResource<Sprite>("UI/Skin/UISprite.psd");
private static void EnsureFolder(string dir) { var parts = dir.Split('/'); string cur = parts[0]; for (int i = 1; i < parts.Length; i++) { string n = $"{cur}/{parts[i]}"; if (!AssetDatabase.IsValidFolder(n)) AssetDatabase.CreateFolder(cur, parts[i]); cur = n; } }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cbcf9174cf741d6499eea7b8443f18ea
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,266 @@
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using BaseGames.UI;
using BaseGames.UI.Theme;
using BaseGames.Core.Events;
using BaseGames.Localization;
using BaseGames.Editor.Localization;
namespace BaseGames.Editor.UI
{
/// <summary>
/// 图鉴脚手架:生成 <c>UI_BestiaryCell</c> + <c>UI_BestiaryPanel</c> 预制件 + 空 <c>UI_BestiaryDatabase</c> 表 + BESTIARY_* 中英文案。
/// 面板据 BestiaryDatabaseSO 列出全部敌人,经 IBestiaryService 读已发现态(已发现亮/未发现 ??? + 剪影 + 锁),
/// 订阅 EVT_BestiaryUpdated 实时刷新;点击格子在右侧详情区展示。
///
/// 数据:策划在 UI_BestiaryDatabase 增删条目enemyId 须与 EnemyBase._enemyId 一致),或用「同步图鉴条目」工具自动补。
/// 菜单BaseGames/UI/控件库/生成图鉴(预制件 + 空表)
/// </summary>
public static class UIBestiaryScaffold
{
private const string PrefabDir = "Assets/_Game/Prefabs/UI";
private const string ControlsDir = "Assets/_Game/Prefabs/UI/Controls";
private const string ConfigDir = "Assets/_Game/Data/UI";
private const string ThemePath = "Assets/_Game/Data/UI/Themes/UI_Theme_Default.asset";
private const string PanelName = "UI_BestiaryPanel";
private const string CellName = "UI_BestiaryCell";
private const string DbName = "UI_BestiaryDatabase";
[MenuItem("BaseGames/UI/控件库/生成图鉴(预制件 + 空表)")]
public static void GeneratePrefab()
{
EnsureFolder(PrefabDir); EnsureFolder(ControlsDir); EnsureFolder(ConfigDir);
var report = new List<string>();
var theme = AssetDatabase.LoadAssetAtPath<UIThemeSO>(ThemePath);
var db = EnsureDatabase(report);
SeedLocalization(report);
var cell = BuildCellPrefab(theme, report);
BuildPanelPrefab(theme, db, cell, report);
AssetDatabase.SaveAssets(); AssetDatabase.Refresh();
var sb = new System.Text.StringBuilder("[UIBestiary] 图鉴已生成:\n");
foreach (var r in report) sb.AppendLine(" • " + r);
sb.AppendLine("策划在 UI_BestiaryDatabase 填敌人条目enemyId 同 EnemyBase._enemyId重跑「Scaffold Inventory Hub」收编为图鉴 Tab。");
Debug.Log(sb.ToString());
}
private static BestiaryDatabaseSO EnsureDatabase(List<string> report)
{
string path = $"{ConfigDir}/{DbName}.asset";
var db = AssetDatabase.LoadAssetAtPath<BestiaryDatabaseSO>(path);
if (db == null)
{
db = ScriptableObject.CreateInstance<BestiaryDatabaseSO>();
AssetDatabase.CreateAsset(db, path);
report.Add($"{path}(空表,待策划/同步工具填充)");
}
return db;
}
private static void SeedLocalization(List<string> report)
{
var zh = new Dictionary<string, string>
{
{ "MENU_BESTIARY", "图鉴" }, { "BESTIARY_TITLE", "图鉴" },
{ "BESTIARY_LOCKED", "???" }, { "BESTIARY_LOCKED_DESC", "尚未发现该敌人。" },
{ "BESTIARY_HP", "生命" }, { "BESTIARY_KILLS", "击杀" },
};
var en = new Dictionary<string, string>
{
{ "MENU_BESTIARY", "Bestiary" }, { "BESTIARY_TITLE", "Bestiary" },
{ "BESTIARY_LOCKED", "???" }, { "BESTIARY_LOCKED_DESC", "Not yet discovered." },
{ "BESTIARY_HP", "HP" }, { "BESTIARY_KILLS", "Kills" },
};
int added = MergeWriteUI(Language.ChineseSimplified, zh) + MergeWriteUI(Language.English, en);
report.Add($"本地化新增 {added} 条(已存在不覆盖)。");
}
private static int MergeWriteUI(Language lang, Dictionary<string, string> kv)
{
var dict = LocalizationFileIO.Read(lang, LocalizationTable.UI);
int added = 0;
foreach (var p in kv) if (!dict.ContainsKey(p.Key)) { dict[p.Key] = p.Value; added++; }
if (added > 0) LocalizationFileIO.Write(lang, LocalizationTable.UI, dict);
return added;
}
// ── 单元格预制件 ─────────────────────────────────────────────────────
private static BestiaryCellView BuildCellPrefab(UIThemeSO theme, List<string> report)
{
var root = new GameObject(CellName, typeof(RectTransform), typeof(CanvasGroup));
((RectTransform)root.transform).sizeDelta = new Vector2(170f, 130f);
var view = root.AddComponent<BestiaryCellView>();
var bg = root.AddComponent<Image>();
bg.sprite = Std(); bg.type = Image.Type.Sliced; bg.color = new Color(1f, 1f, 1f, 0.05f);
var btn = root.AddComponent<Button>(); btn.targetGraphic = bg;
var iconGo = NewUIChild(root.transform, "Icon", out var iconRt);
SetRect(iconRt, C(0.5f, 1f), C(0.5f, 1f), C(0.5f, 1f), new Vector2(0f, -44f), new Vector2(72f, 72f));
var icon = iconGo.AddComponent<Image>(); icon.preserveAspect = true; icon.raycastTarget = false;
var nameGo = NewUIChild(root.transform, "Name", out var nameRt);
SetRect(nameRt, C(0.5f, 0f), C(0.5f, 0f), C(0.5f, 0f), new Vector2(0f, 14f), new Vector2(154f, 40f));
var nameTmp = nameGo.AddComponent<TextMeshProUGUI>();
nameTmp.alignment = TextAlignmentOptions.Center; nameTmp.fontSize = 18f; nameTmp.enableWordWrapping = true;
nameTmp.raycastTarget = false;
var loc = nameGo.AddComponent<LocalizedText>();
SetEnum(nameGo.AddComponent<UIThemeRole>(), "_kind", (int)UIThemeRoleKind.Text_Primary);
var lockGo = NewUIChild(root.transform, "LockedOverlay", out var lockRt);
Stretch(lockRt);
var lockImg = lockGo.AddComponent<Image>(); lockImg.color = new Color(0f, 0f, 0f, 0.5f); lockImg.raycastTarget = false;
lockGo.SetActive(false);
var so = new SerializedObject(view);
so.FindProperty("_icon").objectReferenceValue = icon;
so.FindProperty("_label").objectReferenceValue = loc;
so.FindProperty("_lockedOverlay").objectReferenceValue = lockGo;
so.FindProperty("_group").objectReferenceValue = root.GetComponent<CanvasGroup>();
so.FindProperty("_selectButton").objectReferenceValue = btn;
so.ApplyModifiedPropertiesWithoutUndo();
string path = $"{ControlsDir}/{CellName}.prefab";
var asset = PrefabUtility.SaveAsPrefabAsset(root, path);
Object.DestroyImmediate(root);
report.Add(path);
return asset.GetComponent<BestiaryCellView>();
}
// ── 面板预制件 ───────────────────────────────────────────────────────
private static void BuildPanelPrefab(UIThemeSO theme, BestiaryDatabaseSO db, BestiaryCellView cell, List<string> report)
{
var root = new GameObject(PanelName,
typeof(RectTransform), typeof(Canvas), typeof(CanvasScaler), typeof(GraphicRaycaster), typeof(CanvasGroup));
Stretch((RectTransform)root.transform);
SetupCanvas(root, 62);
var panel = root.AddComponent<BestiaryPanel>();
var applier = root.AddComponent<UIThemeApplier>();
if (theme != null) AssignRef(applier, "_theme", theme);
var overlayGo = NewUIChild(root.transform, "Overlay", out var ovRt);
Stretch(ovRt);
overlayGo.AddComponent<Image>().color = new Color(0f, 0f, 0f, 0.6f);
var boxGo = NewUIChild(root.transform, "DialogBox", out var boxRt);
SetRect(boxRt, C(0.5f), C(0.5f), C(0.5f), Vector2.zero, new Vector2(1280f, 760f));
var box = boxGo.AddComponent<Image>(); box.sprite = Std(); box.type = Image.Type.Sliced;
box.color = new Color(0.10f, 0.11f, 0.15f, 0.98f);
SetEnum(boxGo.AddComponent<UIThemeRole>(), "_kind", (int)UIThemeRoleKind.Graphic_Background);
// 标题
var titleGo = NewUIChild(boxGo.transform, "Title", out var titleRt);
SetRect(titleRt, C(0.5f, 1f), C(0.5f, 1f), C(0.5f, 1f), new Vector2(0f, -46f), new Vector2(600f, 54f));
var title = titleGo.AddComponent<TextMeshProUGUI>();
title.alignment = TextAlignmentOptions.Center; title.fontSize = 40f; title.raycastTarget = false;
titleGo.AddComponent<LocalizedText>();
SetString(titleGo.GetComponent<LocalizedText>(), "_key", "BESTIARY_TITLE");
SetEnum(titleGo.AddComponent<UIThemeRole>(), "_kind", (int)UIThemeRoleKind.Text_Header);
// 完成度(右上)
var compGo = NewUIChild(boxGo.transform, "Completion", out var compRt);
SetRect(compRt, C(1f, 1f), C(1f, 1f), C(1f, 1f), new Vector2(-40f, -52f), new Vector2(300f, 40f));
var comp = compGo.AddComponent<TextMeshProUGUI>();
comp.alignment = TextAlignmentOptions.Right; comp.fontSize = 26f; comp.raycastTarget = false;
SetEnum(compGo.AddComponent<UIThemeRole>(), "_kind", (int)UIThemeRoleKind.Text_Secondary);
// 敌人格网格(左)
var gridGo = NewUIChild(boxGo.transform, "GridContainer", out var gridRt);
SetRect(gridRt, C(0f, 1f), C(0f, 1f), C(0f, 1f), new Vector2(40f, -120f), new Vector2(760f, 600f));
var grid = gridGo.AddComponent<GridLayoutGroup>();
grid.cellSize = new Vector2(170f, 130f); grid.spacing = new Vector2(14f, 14f);
grid.childAlignment = TextAnchor.UpperLeft;
grid.constraint = GridLayoutGroup.Constraint.FixedColumnCount; grid.constraintCount = 4;
// 详情区(右)
var detailGo = NewUIChild(boxGo.transform, "DetailPane", out var detailRt);
SetRect(detailRt, C(1f, 1f), C(1f, 1f), C(1f, 1f), new Vector2(-40f, -120f), new Vector2(420f, 600f));
var detailBg = detailGo.AddComponent<Image>(); detailBg.color = new Color(1f, 1f, 1f, 0.03f);
detailBg.sprite = Std(); detailBg.type = Image.Type.Sliced;
var dIconGo = NewUIChild(detailGo.transform, "DetailIcon", out var dIconRt);
SetRect(dIconRt, C(0.5f, 1f), C(0.5f, 1f), C(0.5f, 1f), new Vector2(0f, -30f), new Vector2(160f, 160f));
var dIcon = dIconGo.AddComponent<Image>(); dIcon.preserveAspect = true; dIcon.raycastTarget = false;
var dNameGo = NewUIChild(detailGo.transform, "DetailName", out var dNameRt);
SetRect(dNameRt, C(0.5f, 1f), C(0.5f, 1f), C(0.5f, 1f), new Vector2(0f, -210f), new Vector2(384f, 44f));
var dName = dNameGo.AddComponent<TextMeshProUGUI>();
dName.alignment = TextAlignmentOptions.Center; dName.fontSize = 28f; dName.raycastTarget = false;
dNameGo.AddComponent<LocalizedText>();
SetEnum(dNameGo.AddComponent<UIThemeRole>(), "_kind", (int)UIThemeRoleKind.Text_Header);
var dStatsGo = NewUIChild(detailGo.transform, "DetailStats", out var dStatsRt);
SetRect(dStatsRt, C(0.5f, 1f), C(0.5f, 1f), C(0.5f, 1f), new Vector2(0f, -258f), new Vector2(384f, 34f));
var dStats = dStatsGo.AddComponent<TextMeshProUGUI>();
dStats.alignment = TextAlignmentOptions.Center; dStats.fontSize = 20f; dStats.raycastTarget = false;
SetEnum(dStatsGo.AddComponent<UIThemeRole>(), "_kind", (int)UIThemeRoleKind.Text_Secondary);
var dDescGo = NewUIChild(detailGo.transform, "DetailDesc", out var dDescRt);
SetRect(dDescRt, C(0.5f, 1f), C(0.5f, 1f), C(0.5f, 1f), new Vector2(0f, -310f), new Vector2(372f, 260f));
var dDesc = dDescGo.AddComponent<TextMeshProUGUI>();
dDesc.alignment = TextAlignmentOptions.TopLeft; dDesc.fontSize = 18f; dDesc.enableWordWrapping = true; dDesc.raycastTarget = false;
SetEnum(dDescGo.AddComponent<UIThemeRole>(), "_kind", (int)UIThemeRoleKind.Text_Secondary);
// 关闭
var closeGo = NewUIChild(boxGo.transform, "Btn_Close", out var closeRt);
SetRect(closeRt, C(0.5f, 0f), C(0.5f, 0f), C(0.5f, 0f), new Vector2(0f, 32f), new Vector2(240f, 56f));
var closeImg = closeGo.AddComponent<Image>(); closeImg.sprite = Std(); closeImg.type = Image.Type.Sliced;
closeImg.color = new Color(1f, 1f, 1f, 0.06f);
var closeBtn = closeGo.AddComponent<Button>(); closeBtn.targetGraphic = closeImg;
var clblGo = NewUIChild(closeGo.transform, "Label", out var clblRt);
Stretch(clblRt);
var clbl = clblGo.AddComponent<TextMeshProUGUI>();
clbl.alignment = TextAlignmentOptions.Center; clbl.fontSize = 26f;
clblGo.AddComponent<LocalizedText>();
SetString(clblGo.GetComponent<LocalizedText>(), "_key", "BTN_BACK");
SetEnum(clblGo.AddComponent<UIThemeRole>(), "_kind", (int)UIThemeRoleKind.Text_Primary);
// 绑定 BestiaryPanel
var so = new SerializedObject(panel);
so.FindProperty("_database").objectReferenceValue = db;
so.FindProperty("_container").objectReferenceValue = gridRt;
so.FindProperty("_cellPrefab").objectReferenceValue = cell;
so.FindProperty("_completionText").objectReferenceValue = comp;
so.FindProperty("_btnClose").objectReferenceValue = closeBtn;
so.FindProperty("_detailIcon").objectReferenceValue = dIcon;
so.FindProperty("_detailName").objectReferenceValue = dNameGo.GetComponent<LocalizedText>();
so.FindProperty("_detailDesc").objectReferenceValue = dDesc;
so.FindProperty("_detailStats").objectReferenceValue = dStats;
so.FindProperty("_onBestiaryUpdated").objectReferenceValue = FindAsset<StringEventChannelSO>("EVT_BestiaryUpdated");
so.ApplyModifiedPropertiesWithoutUndo();
root.SetActive(false);
PrefabUtility.SaveAsPrefabAsset(root, $"{PrefabDir}/{PanelName}.prefab");
Object.DestroyImmediate(root);
report.Add($"{PrefabDir}/{PanelName}.prefab");
}
// ── 助手(对照 UIAbilityOverviewScaffold──────────────────────────────
private static Vector2 C(float x = 0.5f, float y = 0.5f) => new Vector2(x, y);
private static GameObject NewUIChild(Transform parent, string name, out RectTransform rt)
{ var go = new GameObject(name, typeof(RectTransform)); rt = (RectTransform)go.transform; rt.SetParent(parent, false); return go; }
private static void Stretch(RectTransform rt) { rt.anchorMin = Vector2.zero; rt.anchorMax = Vector2.one; rt.offsetMin = Vector2.zero; rt.offsetMax = Vector2.zero; }
private static void SetRect(RectTransform rt, Vector2 aMin, Vector2 aMax, Vector2 pivot, Vector2 pos, Vector2 size)
{ rt.anchorMin = aMin; rt.anchorMax = aMax; rt.pivot = pivot; rt.anchoredPosition = pos; rt.sizeDelta = size; }
private static void SetEnum(Component c, string prop, int value) { var so = new SerializedObject(c); var p = so.FindProperty(prop); if (p != null) { p.enumValueIndex = value; so.ApplyModifiedPropertiesWithoutUndo(); } }
private static void SetString(Component c, string prop, string value) { if (c == null) return; var so = new SerializedObject(c); var p = so.FindProperty(prop); if (p != null) { p.stringValue = value; so.ApplyModifiedPropertiesWithoutUndo(); } }
private static void AssignRef(Object target, string prop, Object value) { var so = new SerializedObject(target); var p = so.FindProperty(prop); if (p != null) { p.objectReferenceValue = value; so.ApplyModifiedPropertiesWithoutUndo(); } }
private static T FindAsset<T>(string name) where T : Object
{ foreach (var g in AssetDatabase.FindAssets($"{name} t:{typeof(T).Name}")) { var pa = AssetDatabase.GUIDToAssetPath(g); var a = AssetDatabase.LoadAssetAtPath<T>(pa); if (a != null && a.name == name) return a; } return null; }
private static void SetupCanvas(GameObject go, int sortOrder)
{
var canvas = go.GetComponent<Canvas>();
canvas.renderMode = RenderMode.ScreenSpaceOverlay; canvas.sortingOrder = sortOrder;
var scaler = go.GetComponent<CanvasScaler>();
scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
scaler.referenceResolution = new Vector2(1920f, 1080f);
scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight;
scaler.matchWidthOrHeight = 0.5f;
}
private static Sprite Std() => AssetDatabase.GetBuiltinExtraResource<Sprite>("UI/Skin/UISprite.psd");
private static void EnsureFolder(string dir) { var parts = dir.Split('/'); string cur = parts[0]; for (int i = 1; i < parts.Length; i++) { string n = $"{cur}/{parts[i]}"; if (!AssetDatabase.IsValidFolder(n)) AssetDatabase.CreateFolder(cur, parts[i]); cur = n; } }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 643450ffe43a0124f9284b664b9f3e28
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,309 @@
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using BaseGames.UI;
using BaseGames.UI.Theme;
using BaseGames.Core.Events;
using BaseGames.Localization;
using BaseGames.Editor.Localization;
namespace BaseGames.Editor.UI
{
/// <summary>
/// 护符面板脚手架:生成 <c>UI_CharmPanel</c> 预制件CharmEquipPanel + 已装备区 + 收藏目录 + 凹槽进度条 + 卡片模板)。
/// 数据来源运行期 ServiceLocator → IEquipmentServiceEquipmentManager变更经 EVT_EquipmentChanged 反应式重建。
///
/// 该面板既可 standalone 打开PanelId.CharmPanel也由 InventoryHub 内嵌为「护符」Tab脚手架内嵌时中和 Canvas 链 + 隐藏 chrome
/// 美术 → 改 UI_CharmPanel / 卡片样式;策划 → 改护符数据(CharmSO/CharmCatalogSO)。
/// 菜单BaseGames/UI/控件库/生成护符面板(预制件)
/// </summary>
public static class UICharmScaffold
{
private const string PrefabDir = "Assets/_Game/Prefabs/UI";
private const string ThemePath = "Assets/_Game/Data/UI/Themes/UI_Theme_Default.asset";
private const string PrefabName = "UI_CharmPanel";
[MenuItem("BaseGames/UI/控件库/生成护符面板(预制件)")]
public static void GeneratePrefab()
{
EnsureFolder(PrefabDir);
var report = new List<string>();
var theme = AssetDatabase.LoadAssetAtPath<UIThemeSO>(ThemePath);
SeedLocalization(report);
BuildPrefab(theme, report);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
var sb = new System.Text.StringBuilder("[UICharm] 护符面板已生成:\n");
foreach (var r in report) sb.AppendLine(" • " + r);
sb.AppendLine("运行期读 IEquipmentServiceEquipmentManager重跑「Scaffold Inventory Hub」把它收编为护符 Tab。");
Debug.Log(sb.ToString());
}
private static void SeedLocalization(List<string> report)
{
var zh = new Dictionary<string, string>
{
{ "MENU_CHARM", "护符" }, { "CHARM_TITLE", "护符" },
{ "CHARM_EQUIPPED", "已装备" }, { "CHARM_CATALOG", "收藏" }, { "CHARM_NOTCHES", "凹槽" },
};
var en = new Dictionary<string, string>
{
{ "MENU_CHARM", "Charms" }, { "CHARM_TITLE", "Charms" },
{ "CHARM_EQUIPPED", "Equipped" }, { "CHARM_CATALOG", "Collected" }, { "CHARM_NOTCHES", "Notches" },
};
int added = MergeWriteUI(Language.ChineseSimplified, zh) + MergeWriteUI(Language.English, en);
report.Add($"本地化新增 {added} 条(已存在不覆盖)。");
}
private static int MergeWriteUI(Language lang, Dictionary<string, string> kv)
{
var dict = LocalizationFileIO.Read(lang, LocalizationTable.UI);
int added = 0;
foreach (var p in kv)
if (!dict.ContainsKey(p.Key)) { dict[p.Key] = p.Value; added++; }
if (added > 0) LocalizationFileIO.Write(lang, LocalizationTable.UI, dict);
return added;
}
// ── 预制件 ───────────────────────────────────────────────────────────
private static void BuildPrefab(UIThemeSO theme, List<string> report)
{
var root = new GameObject(PrefabName,
typeof(RectTransform), typeof(Canvas), typeof(CanvasScaler), typeof(GraphicRaycaster), typeof(CanvasGroup));
Stretch((RectTransform)root.transform);
SetupCanvas(root, 61);
var panel = root.AddComponent<CharmEquipPanel>();
var applier = root.AddComponent<UIThemeApplier>();
if (theme != null) AssignRef(applier, "_theme", theme);
// 全屏遮罩chrome内嵌时隐藏
var overlayGo = NewUIChild(root.transform, "Overlay", out var overlayRt);
Stretch(overlayRt);
var overlay = overlayGo.AddComponent<Image>(); overlay.color = new Color(0f, 0f, 0f, 0.6f);
// 主框
var boxGo = NewUIChild(root.transform, "DialogBox", out var boxRt);
SetRect(boxRt, C(0.5f), C(0.5f), C(0.5f), Vector2.zero, new Vector2(1280f, 720f));
var box = boxGo.AddComponent<Image>();
box.sprite = Std(); box.type = Image.Type.Sliced; box.color = new Color(0.10f, 0.11f, 0.15f, 0.98f);
SetEnum(boxGo.AddComponent<UIThemeRole>(), "_kind", (int)UIThemeRoleKind.Graphic_Background);
// 标题
var titleGo = NewUIChild(boxGo.transform, "Title", out var titleRt);
SetRect(titleRt, C(0.5f, 1f), C(0.5f, 1f), C(0.5f, 1f), new Vector2(0f, -50f), new Vector2(600f, 60f));
var title = titleGo.AddComponent<TextMeshProUGUI>();
title.alignment = TextAlignmentOptions.Center; title.fontSize = 40f; title.raycastTarget = false;
titleGo.AddComponent<LocalizedText>();
SetString(titleGo.GetComponent<LocalizedText>(), "_key", "CHARM_TITLE");
SetEnum(titleGo.AddComponent<UIThemeRole>(), "_kind", (int)UIThemeRoleKind.Text_Header);
// 凹槽进度条(已用/总数)
var notchGo = NewUIChild(boxGo.transform, "NotchBar", out var notchRt);
SetRect(notchRt, C(0.5f, 1f), C(0.5f, 1f), C(0.5f, 1f), new Vector2(0f, -110f), new Vector2(420f, 34f));
var notchBg = notchGo.AddComponent<Image>(); notchBg.color = new Color(1f, 1f, 1f, 0.08f);
notchBg.sprite = Std(); notchBg.type = Image.Type.Sliced;
var fillGo = NewUIChild(notchGo.transform, "Fill", out var fillRt);
Stretch(fillRt);
var notchFill = fillGo.AddComponent<Image>();
notchFill.color = new Color(0.85f, 0.80f, 0.55f, 0.85f);
notchFill.sprite = Std(); notchFill.type = Image.Type.Filled;
notchFill.fillMethod = Image.FillMethod.Horizontal; notchFill.fillOrigin = 0; notchFill.fillAmount = 0f;
var notchTextGo = NewUIChild(notchGo.transform, "NotchText", out var notchTextRt);
Stretch(notchTextRt);
var notchText = notchTextGo.AddComponent<TextMeshProUGUI>();
notchText.alignment = TextAlignmentOptions.Center; notchText.fontSize = 20f; notchText.raycastTarget = false;
SetEnum(notchTextGo.AddComponent<UIThemeRole>(), "_kind", (int)UIThemeRoleKind.Text_Primary);
// 已装备区(左)
var equippedLabel = MakeSectionLabel(boxGo.transform, "EquippedLabel", "CHARM_EQUIPPED",
C(0f, 1f), new Vector2(60f, -160f), new Vector2(420f, 34f));
var equippedGo = NewUIChild(boxGo.transform, "EquippedContainer", out var equippedRt);
SetRect(equippedRt, C(0f, 1f), C(0f, 1f), C(0f, 1f), new Vector2(40f, -200f), new Vector2(440f, 460f));
var eqGrid = equippedGo.AddComponent<GridLayoutGroup>();
eqGrid.cellSize = new Vector2(200f, 96f); eqGrid.spacing = new Vector2(8f, 8f);
eqGrid.childAlignment = TextAnchor.UpperLeft; eqGrid.constraint = GridLayoutGroup.Constraint.FixedColumnCount;
eqGrid.constraintCount = 2;
// 收藏目录(右,滚动)
var catalogLabel = MakeSectionLabel(boxGo.transform, "CatalogLabel", "CHARM_CATALOG",
C(1f, 1f), new Vector2(-490f, -160f), new Vector2(440f, 34f));
var scrollGo = NewUIChild(boxGo.transform, "CatalogScroll", out var scrollRt);
SetRect(scrollRt, C(1f, 1f), C(1f, 1f), C(1f, 1f), new Vector2(-40f, -200f), new Vector2(680f, 460f));
var scrollImg = scrollGo.AddComponent<Image>(); scrollImg.color = new Color(1f, 1f, 1f, 0.03f);
var scroll = scrollGo.AddComponent<ScrollRect>();
scroll.horizontal = false; scroll.vertical = true;
var viewportGo = NewUIChild(scrollGo.transform, "Viewport", out var viewportRt);
Stretch(viewportRt);
var vpImg = viewportGo.AddComponent<Image>(); vpImg.color = new Color(1f, 1f, 1f, 0.01f);
viewportGo.AddComponent<RectMask2D>();
var catalogGo = NewUIChild(viewportGo.transform, "CatalogContainer", out var catalogRt);
SetRect(catalogRt, C(0f, 1f), C(1f, 1f), C(0.5f, 1f), Vector2.zero, new Vector2(0f, 0f));
var catGrid = catalogGo.AddComponent<GridLayoutGroup>();
catGrid.cellSize = new Vector2(200f, 96f); catGrid.spacing = new Vector2(8f, 8f);
catGrid.childAlignment = TextAnchor.UpperLeft; catGrid.constraint = GridLayoutGroup.Constraint.FixedColumnCount;
catGrid.constraintCount = 3; catGrid.padding = new RectOffset(8, 8, 8, 8);
var catFitter = catalogGo.AddComponent<ContentSizeFitter>();
catFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
AssignRef(scroll, "m_Content", catalogRt);
AssignRef(scroll, "m_Viewport", viewportRt);
// 卡片模板CharmCardViewinactive
var cardGo = BuildCardTemplate(boxGo.transform);
// 关闭按钮chrome内嵌时隐藏
var closeGo = NewUIChild(boxGo.transform, "Btn_Close", out var closeRt);
SetRect(closeRt, C(0.5f, 0f), C(0.5f, 0f), C(0.5f, 0f), new Vector2(0f, 36f), new Vector2(240f, 56f));
var closeImg = closeGo.AddComponent<Image>(); closeImg.sprite = Std(); closeImg.type = Image.Type.Sliced;
closeImg.color = new Color(1f, 1f, 1f, 0.06f);
var closeBtn = closeGo.AddComponent<Button>(); closeBtn.targetGraphic = closeImg;
var closeLblGo = NewUIChild(closeGo.transform, "Label", out var closeLblRt);
Stretch(closeLblRt);
var closeLbl = closeLblGo.AddComponent<TextMeshProUGUI>();
closeLbl.alignment = TextAlignmentOptions.Center; closeLbl.fontSize = 26f;
closeLblGo.AddComponent<LocalizedText>();
SetString(closeLblGo.GetComponent<LocalizedText>(), "_key", "BTN_BACK");
SetEnum(closeLblGo.AddComponent<UIThemeRole>(), "_kind", (int)UIThemeRoleKind.Text_Primary);
// 绑定 CharmEquipPanel
AssignRef(panel, "_notchText", notchText);
AssignRef(panel, "_notchBarFill", notchFill);
AssignRef(panel, "_equippedContainer", equippedGo.transform);
AssignRef(panel, "_catalogContainer", catalogGo.transform);
AssignRef(panel, "_charmCardTemplate", cardGo);
AssignRef(panel, "_btnClose", closeBtn);
AssignRef(panel, "_onEquipmentChanged", FindAsset<VoidEventChannelSO>("EVT_EquipmentChanged"));
if (FindAsset<VoidEventChannelSO>("EVT_EquipmentChanged") == null)
report.Add("EVT_EquipmentChanged 未找到_onEquipmentChanged 留空(运行 BaseGames ▸ Events ▸ Create Event Channels。");
root.SetActive(false);
PrefabUtility.SaveAsPrefabAsset(root, $"{PrefabDir}/{PrefabName}.prefab");
Object.DestroyImmediate(root);
report.Add($"{PrefabDir}/{PrefabName}.prefab");
}
// 护符卡片模板CharmCardView + icon/name/notchCost/desc/badge/button整卡为按钮
private static GameObject BuildCardTemplate(Transform parent)
{
var cardGo = NewUIChild(parent, "CharmCardTemplate", out var cardRt);
cardRt.sizeDelta = new Vector2(200f, 96f);
var bg = cardGo.AddComponent<Image>(); bg.color = new Color(1f, 1f, 1f, 0.05f);
bg.sprite = Std(); bg.type = Image.Type.Sliced;
var btn = cardGo.AddComponent<Button>(); btn.targetGraphic = bg;
var view = cardGo.AddComponent<CharmCardView>();
var iconGo = NewUIChild(cardGo.transform, "Icon", out var iconRt);
SetRect(iconRt, C(0f, 0.5f), C(0f, 0.5f), C(0f, 0.5f), new Vector2(12f, 0f), new Vector2(64f, 64f));
var icon = iconGo.AddComponent<Image>(); icon.preserveAspect = true; icon.raycastTarget = false;
var nameGo = NewUIChild(cardGo.transform, "Name", out var nameRt);
SetRect(nameRt, C(0f, 1f), C(1f, 1f), C(0f, 1f), new Vector2(88f, -10f), new Vector2(-96f, 28f));
var nameTxt = nameGo.AddComponent<TextMeshProUGUI>();
nameTxt.fontSize = 20f; nameTxt.raycastTarget = false; nameTxt.alignment = TextAlignmentOptions.TopLeft;
SetEnum(nameGo.AddComponent<UIThemeRole>(), "_kind", (int)UIThemeRoleKind.Text_Header);
var costGo = NewUIChild(cardGo.transform, "NotchCost", out var costRt);
SetRect(costRt, C(1f, 1f), C(1f, 1f), C(1f, 1f), new Vector2(-10f, -10f), new Vector2(40f, 28f));
var costTxt = costGo.AddComponent<TextMeshProUGUI>();
costTxt.fontSize = 18f; costTxt.alignment = TextAlignmentOptions.TopRight; costTxt.raycastTarget = false;
SetEnum(costGo.AddComponent<UIThemeRole>(), "_kind", (int)UIThemeRoleKind.Text_Secondary);
var descGo = NewUIChild(cardGo.transform, "Desc", out var descRt);
SetRect(descRt, C(0f, 0f), C(1f, 0f), C(0f, 0f), new Vector2(88f, 8f), new Vector2(-96f, 44f));
var descTxt = descGo.AddComponent<TextMeshProUGUI>();
descTxt.fontSize = 15f; descTxt.alignment = TextAlignmentOptions.TopLeft; descTxt.raycastTarget = false;
descTxt.enableWordWrapping = true;
SetEnum(descGo.AddComponent<UIThemeRole>(), "_kind", (int)UIThemeRoleKind.Text_Secondary);
var badgeGo = NewUIChild(cardGo.transform, "Badge", out var badgeRt);
SetRect(badgeRt, C(1f, 0f), C(1f, 0f), C(1f, 0f), new Vector2(-12f, 10f), new Vector2(28f, 28f));
var badgeTxt = badgeGo.AddComponent<TextMeshProUGUI>();
badgeTxt.fontSize = 22f; badgeTxt.alignment = TextAlignmentOptions.Center; badgeTxt.raycastTarget = false;
SetEnum(badgeGo.AddComponent<UIThemeRole>(), "_kind", (int)UIThemeRoleKind.Graphic_Accent);
// 绑定 CharmCardView 字段
AssignRef(view, "_icon", icon);
AssignRef(view, "_iconRoot", iconGo);
AssignRef(view, "_nameText", nameTxt);
AssignRef(view, "_notchCostText", costTxt);
AssignRef(view, "_descriptionText", descTxt);
AssignRef(view, "_equipBadgeText", badgeTxt);
AssignRef(view, "_actionButton", btn);
cardGo.SetActive(false);
return cardGo;
}
private static TMP_Text MakeSectionLabel(Transform parent, string name, string locKey,
Vector2 anchor, Vector2 pos, Vector2 size)
{
var go = NewUIChild(parent, name, out var rt);
SetRect(rt, anchor, anchor, anchor, pos, size);
var t = go.AddComponent<TextMeshProUGUI>();
t.fontSize = 24f; t.alignment = TextAlignmentOptions.Left; t.raycastTarget = false;
go.AddComponent<LocalizedText>();
SetString(go.GetComponent<LocalizedText>(), "_key", locKey);
SetEnum(go.AddComponent<UIThemeRole>(), "_kind", (int)UIThemeRoleKind.Text_Header);
return t;
}
// ── 助手(对照 UIFormSkillScaffold────────────────────────────────────
private static Vector2 C(float x = 0.5f, float y = 0.5f) => new Vector2(x, y);
private static GameObject NewUIChild(Transform parent, string name, out RectTransform rt)
{
var go = new GameObject(name, typeof(RectTransform));
rt = (RectTransform)go.transform; rt.SetParent(parent, false);
return go;
}
private static void Stretch(RectTransform rt)
{ rt.anchorMin = Vector2.zero; rt.anchorMax = Vector2.one; rt.offsetMin = Vector2.zero; rt.offsetMax = Vector2.zero; }
private static void SetRect(RectTransform rt, Vector2 aMin, Vector2 aMax, Vector2 pivot, Vector2 pos, Vector2 size)
{ rt.anchorMin = aMin; rt.anchorMax = aMax; rt.pivot = pivot; rt.anchoredPosition = pos; rt.sizeDelta = size; }
private static void SetEnum(Component c, string prop, int value)
{ var so = new SerializedObject(c); var p = so.FindProperty(prop); if (p != null) { p.enumValueIndex = value; so.ApplyModifiedPropertiesWithoutUndo(); } }
private static void SetString(Component c, string prop, string value)
{ if (c == null) return; var so = new SerializedObject(c); var p = so.FindProperty(prop); if (p != null) { p.stringValue = value; so.ApplyModifiedPropertiesWithoutUndo(); } }
private static void AssignRef(Object target, string prop, Object value)
{ var so = new SerializedObject(target); var p = so.FindProperty(prop); if (p != null) { p.objectReferenceValue = value; so.ApplyModifiedPropertiesWithoutUndo(); } }
private static T FindAsset<T>(string name) where T : Object
{
foreach (var guid in AssetDatabase.FindAssets($"{name} t:{typeof(T).Name}"))
{
var path = AssetDatabase.GUIDToAssetPath(guid);
var a = AssetDatabase.LoadAssetAtPath<T>(path);
if (a != null && a.name == name) return a;
}
return null;
}
private static void SetupCanvas(GameObject go, int sortOrder)
{
var canvas = go.GetComponent<Canvas>();
canvas.renderMode = RenderMode.ScreenSpaceOverlay; canvas.sortingOrder = sortOrder;
var scaler = go.GetComponent<CanvasScaler>();
scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
scaler.referenceResolution = new Vector2(1920f, 1080f);
scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight;
scaler.matchWidthOrHeight = 0.5f;
}
private static Sprite Std() => AssetDatabase.GetBuiltinExtraResource<Sprite>("UI/Skin/UISprite.psd");
private static void EnsureFolder(string dir)
{
string[] parts = dir.Split('/'); string cur = parts[0];
for (int i = 1; i < parts.Length; i++) { string n = $"{cur}/{parts[i]}"; if (!AssetDatabase.IsValidFolder(n)) AssetDatabase.CreateFolder(cur, parts[i]); cur = n; }
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cc9108bb3994a074aa6a534640535f97
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,305 @@
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using BaseGames.UI;
using BaseGames.UI.Theme;
using BaseGames.Skills;
using BaseGames.Core.Events;
using BaseGames.Localization;
using BaseGames.Editor.Localization;
namespace BaseGames.Editor.UI
{
/// <summary>
/// 形态技能一览脚手架:生成 <c>UI_FormSkillPanel</c> 预制件,并为共享数据库 <c>FormSkillDatabase</c>
/// 补形态标签 key + 中英文案。面板只读展示「每形态 3 技能(名称/说明/消耗/冷却)」,按形态翻页。
/// 数据驱动:技能数据读 <see cref="FormSkillDatabaseSO"/>(与玩家 SkillManager 同一权威源)。
///
/// 美术 → 改 UI_FormSkillPanel 预制件样式;策划 → 改 FormSkillDatabase 的技能引用即全生效。
/// 菜单BaseGames/UI/控件库/生成形态技能一览(预制件)
/// </summary>
public static class UIFormSkillScaffold
{
private const string PrefabDir = "Assets/_Game/Prefabs/UI";
private const string ThemePath = "Assets/_Game/Data/UI/Themes/UI_Theme_Default.asset";
private const string DbPath = "Assets/_Game/Data/Skills/FormSkillDatabase.asset";
private const string PrefabName = "UI_FormSkillPanel";
[MenuItem("BaseGames/UI/控件库/生成形态技能一览(预制件)")]
public static void GeneratePrefab()
{
EnsureFolder(PrefabDir);
var report = new List<string>();
var theme = AssetDatabase.LoadAssetAtPath<UIThemeSO>(ThemePath);
var db = EnsureDatabaseLabels(report);
SeedLocalization(report);
BuildPrefab(theme, db, report);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
var sb = new System.Text.StringBuilder("[UIFormSkill] 形态技能一览已生成:\n");
foreach (var r in report) sb.AppendLine(" • " + r);
sb.AppendLine("技能数据读 FormSkillDatabase与玩家 SkillManager 共享);策划在该资产填各形态技能引用即全生效。");
Debug.Log(sb.ToString());
}
// 给数据库 3 条目补 formLabelKey仅空时填不覆盖
private static FormSkillDatabaseSO EnsureDatabaseLabels(List<string> report)
{
var db = AssetDatabase.LoadAssetAtPath<FormSkillDatabaseSO>(DbPath);
if (db == null) { report.Add($"缺少 {DbPath}(请先建 FormSkillDatabase 资产)。"); return null; }
var so = new SerializedObject(db);
var entries = so.FindProperty("_entries");
// formType 枚举序号 0/1/2 = TianHun/DiHun/MingHun
string[] keyByIndex = { "FORM_TIANHUN", "FORM_DIHUN", "FORM_MINGHUN" };
bool changed = false;
for (int i = 0; i < entries.arraySize; i++)
{
var el = entries.GetArrayElementAtIndex(i);
var labelProp = el.FindPropertyRelative("formLabelKey");
int ft = el.FindPropertyRelative("formType").enumValueIndex;
if (labelProp != null && string.IsNullOrEmpty(labelProp.stringValue) && ft >= 0 && ft < keyByIndex.Length)
{
labelProp.stringValue = keyByIndex[ft];
changed = true;
}
}
if (changed) { so.ApplyModifiedPropertiesWithoutUndo(); report.Add($"{DbPath}:已补形态标签 key"); }
return db;
}
private static void SeedLocalization(List<string> report)
{
var zh = new Dictionary<string, string>
{
{ "FORM_TIANHUN", "天魂" }, { "FORM_DIHUN", "地魂" }, { "FORM_MINGHUN", "命魂" },
{ "FORMSKILL_TITLE", "形态技能" },
};
var en = new Dictionary<string, string>
{
{ "FORM_TIANHUN", "Sky Soul" }, { "FORM_DIHUN", "Earth Soul" }, { "FORM_MINGHUN", "Death Soul" },
{ "FORMSKILL_TITLE", "Form Skills" },
};
int added = MergeWriteUI(Language.ChineseSimplified, zh) + MergeWriteUI(Language.English, en);
report.Add($"本地化新增 {added} 条(已存在不覆盖)。");
}
private static int MergeWriteUI(Language lang, Dictionary<string, string> kv)
{
var dict = LocalizationFileIO.Read(lang, LocalizationTable.UI);
int added = 0;
foreach (var p in kv)
if (!dict.ContainsKey(p.Key)) { dict[p.Key] = p.Value; added++; }
if (added > 0) LocalizationFileIO.Write(lang, LocalizationTable.UI, dict);
return added;
}
// ── 预制件 ───────────────────────────────────────────────────────────
private static void BuildPrefab(UIThemeSO theme, FormSkillDatabaseSO db, List<string> report)
{
var root = new GameObject(PrefabName,
typeof(RectTransform), typeof(Canvas), typeof(CanvasScaler), typeof(GraphicRaycaster), typeof(CanvasGroup));
var rootRt = (RectTransform)root.transform;
Stretch(rootRt);
SetupCanvas(root, 60);
var panel = root.AddComponent<FormSkillPanel>();
var applier = root.AddComponent<UIThemeApplier>();
if (theme != null) AssignRef(applier, "_theme", theme);
var overlayGo = NewUIChild(root.transform, "Overlay", out var overlayRt);
Stretch(overlayRt);
var overlay = overlayGo.AddComponent<Image>(); overlay.color = new Color(0f, 0f, 0f, 0.6f);
var boxGo = NewUIChild(root.transform, "DialogBox", out var boxRt);
SetRect(boxRt, C(0.5f), C(0.5f), C(0.5f), Vector2.zero, new Vector2(1040f, 660f));
var box = boxGo.AddComponent<Image>();
box.sprite = Std(); box.type = Image.Type.Sliced; box.color = new Color(0.10f, 0.11f, 0.15f, 0.98f);
SetEnum(boxGo.AddComponent<UIThemeRole>(), "_kind", (int)UIThemeRoleKind.Graphic_Background);
// 形态标题 + 翻页 + 当前形态指示点
var titleGo = NewUIChild(boxGo.transform, "FormTitle", out var titleRt);
SetRect(titleRt, C(0.5f, 1f), C(0.5f, 1f), C(0.5f, 1f), new Vector2(0f, -54f), new Vector2(560f, 64f));
var title = titleGo.AddComponent<TextMeshProUGUI>();
title.alignment = TextAlignmentOptions.Center; title.fontSize = 40f; title.raycastTarget = false;
SetEnum(titleGo.AddComponent<UIThemeRole>(), "_kind", (int)UIThemeRoleKind.Text_Header);
var dotGo = NewUIChild(titleGo.transform, "ActiveDot", out var dotRt);
SetRect(dotRt, C(0.5f, 0f), C(0.5f, 0f), C(0.5f, 1f), new Vector2(0f, -4f), new Vector2(16f, 16f));
var dot = dotGo.AddComponent<Image>(); dot.color = new Color(0.85f, 0.80f, 0.55f, 1f);
SetEnum(dotGo.AddComponent<UIThemeRole>(), "_kind", (int)UIThemeRoleKind.Graphic_Accent);
dotGo.SetActive(false);
var prevBtn = MakeArrowButton(boxGo.transform, "PrevBtn", "", new Vector2(-480f, 30f));
var nextBtn = MakeArrowButton(boxGo.transform, "NextBtn", "", new Vector2( 480f, 30f));
// 3 技能槽(横排)
var slotsGo = NewUIChild(boxGo.transform, "Slots", out var slotsRt);
SetRect(slotsRt, C(0.5f, 0.5f), C(0.5f, 0.5f), C(0.5f, 0.5f), new Vector2(0f, 10f), new Vector2(960f, 380f));
var hlg = slotsGo.AddComponent<HorizontalLayoutGroup>();
hlg.spacing = 16f; hlg.childAlignment = TextAnchor.MiddleCenter;
hlg.childControlWidth = true; hlg.childControlHeight = true;
hlg.childForceExpandWidth = true; hlg.childForceExpandHeight = true;
var soul = BuildSlot(slotsGo.transform, "SoulSlot");
var spirit1 = BuildSlot(slotsGo.transform, "SpiritSlot1");
var spirit2 = BuildSlot(slotsGo.transform, "SpiritSlot2");
// 关闭按钮
var closeGo = NewUIChild(boxGo.transform, "Btn_Close", out var closeRt);
SetRect(closeRt, C(0.5f, 0f), C(0.5f, 0f), C(0.5f, 0f), new Vector2(0f, 40f), new Vector2(240f, 56f));
var closeImg = closeGo.AddComponent<Image>(); closeImg.sprite = Std(); closeImg.type = Image.Type.Sliced;
closeImg.color = new Color(1f, 1f, 1f, 0.06f);
var closeBtn = closeGo.AddComponent<Button>(); closeBtn.targetGraphic = closeImg;
var closeLblGo = NewUIChild(closeGo.transform, "Label", out var closeLblRt);
Stretch(closeLblRt);
var closeLbl = closeLblGo.AddComponent<TextMeshProUGUI>();
closeLbl.alignment = TextAlignmentOptions.Center; closeLbl.fontSize = 26f;
closeLblGo.AddComponent<LocalizedText>();
SetString(closeLblGo.GetComponent<LocalizedText>(), "_key", "BTN_BACK");
SetEnum(closeLblGo.AddComponent<UIThemeRole>(), "_kind", (int)UIThemeRoleKind.Text_Primary);
// 绑定 FormSkillPanel
var so = new SerializedObject(panel);
so.FindProperty("_database").objectReferenceValue = db;
so.FindProperty("_formTitleText").objectReferenceValue = title;
so.FindProperty("_prevFormBtn").objectReferenceValue = prevBtn;
so.FindProperty("_nextFormBtn").objectReferenceValue = nextBtn;
so.FindProperty("_activeFormIndicator").objectReferenceValue = dotGo;
so.FindProperty("_btnClose").objectReferenceValue = closeBtn;
so.FindProperty("_onFormChanged").objectReferenceValue = FindAsset<IntEventChannelSO>("EVT_FormChanged");
BindSlot(so, "_soulSlot", soul);
BindSlot(so, "_spiritSlot1", spirit1);
BindSlot(so, "_spiritSlot2", spirit2);
so.ApplyModifiedPropertiesWithoutUndo();
root.SetActive(false); // 面板由 UIManager/导航激活
PrefabUtility.SaveAsPrefabAsset(root, $"{PrefabDir}/{PrefabName}.prefab");
Object.DestroyImmediate(root);
report.Add($"{PrefabDir}/{PrefabName}.prefab");
}
// 技能槽子树root + icon/name/desc/cost/cooldown
private struct SlotRefs { public GameObject root; public Image icon; public TMP_Text name, desc, cost, cd; }
private static SlotRefs BuildSlot(Transform parent, string name)
{
var r = new SlotRefs();
var slotGo = NewUIChild(parent, name, out var slotRt);
var bg = slotGo.AddComponent<Image>(); bg.color = new Color(1f, 1f, 1f, 0.04f);
bg.sprite = Std(); bg.type = Image.Type.Sliced;
r.root = slotGo;
var iconGo = NewUIChild(slotGo.transform, "Icon", out var iconRt);
SetRect(iconRt, C(0.5f, 1f), C(0.5f, 1f), C(0.5f, 1f), new Vector2(0f, -56f), new Vector2(88f, 88f));
r.icon = iconGo.AddComponent<Image>(); r.icon.preserveAspect = true; r.icon.raycastTarget = false;
r.name = MakeText(slotGo.transform, "Name", new Vector2(0f, -120f), new Vector2(-16f, 36f), 24f,
UIThemeRoleKind.Text_Header, TextAlignmentOptions.Center);
r.cost = MakeText(slotGo.transform, "Cost", new Vector2(0f, -158f), new Vector2(-16f, 28f), 18f,
UIThemeRoleKind.Text_Secondary, TextAlignmentOptions.Center);
r.cd = MakeText(slotGo.transform, "Cooldown", new Vector2(0f, -188f), new Vector2(-16f, 28f), 18f,
UIThemeRoleKind.Text_Secondary, TextAlignmentOptions.Center);
r.desc = MakeText(slotGo.transform, "Desc", new Vector2(0f, -260f), new Vector2(-24f, 110f), 18f,
UIThemeRoleKind.Text_Secondary, TextAlignmentOptions.Top);
r.desc.enableWordWrapping = true;
return r;
}
private static void BindSlot(SerializedObject so, string slotProp, SlotRefs r)
{
var p = so.FindProperty(slotProp);
p.FindPropertyRelative("root").objectReferenceValue = r.root;
p.FindPropertyRelative("icon").objectReferenceValue = r.icon;
p.FindPropertyRelative("nameText").objectReferenceValue = r.name;
p.FindPropertyRelative("descText").objectReferenceValue = r.desc;
p.FindPropertyRelative("costText").objectReferenceValue = r.cost;
p.FindPropertyRelative("cooldownText").objectReferenceValue = r.cd;
}
private static Button MakeArrowButton(Transform parent, string name, string glyph, Vector2 pos)
{
var go = NewUIChild(parent, name, out var rt);
SetRect(rt, C(0.5f, 0.5f), C(0.5f, 0.5f), C(0.5f, 0.5f), pos, new Vector2(64f, 64f));
var img = go.AddComponent<Image>(); img.color = new Color(1f, 1f, 1f, 0.06f);
img.sprite = Std(); img.type = Image.Type.Sliced;
var btn = go.AddComponent<Button>(); btn.targetGraphic = img;
var lblGo = NewUIChild(go.transform, "Label", out var lblRt);
Stretch(lblRt);
var lbl = lblGo.AddComponent<TextMeshProUGUI>();
lbl.text = glyph; lbl.alignment = TextAlignmentOptions.Center; lbl.fontSize = 40f; lbl.raycastTarget = false;
SetEnum(lblGo.AddComponent<UIThemeRole>(), "_kind", (int)UIThemeRoleKind.Text_Primary);
return btn;
}
private static TMP_Text MakeText(Transform parent, string name, Vector2 pos, Vector2 size, float fontSize,
UIThemeRoleKind role, TextAlignmentOptions align)
{
var go = NewUIChild(parent, name, out var rt);
SetRect(rt, C(0.5f, 1f), C(0.5f, 1f), C(0.5f, 1f), pos, size);
var t = go.AddComponent<TextMeshProUGUI>();
t.fontSize = fontSize; t.alignment = align; t.raycastTarget = false;
SetEnum(go.AddComponent<UIThemeRole>(), "_kind", (int)role);
return t;
}
// ── 助手 ─────────────────────────────────────────────────────────────
private static Vector2 C(float x = 0.5f, float y = 0.5f) => new Vector2(x, y);
private static GameObject NewUIChild(Transform parent, string name, out RectTransform rt)
{
var go = new GameObject(name, typeof(RectTransform));
rt = (RectTransform)go.transform; rt.SetParent(parent, false);
return go;
}
private static void Stretch(RectTransform rt)
{ rt.anchorMin = Vector2.zero; rt.anchorMax = Vector2.one; rt.offsetMin = Vector2.zero; rt.offsetMax = Vector2.zero; }
private static void SetRect(RectTransform rt, Vector2 aMin, Vector2 aMax, Vector2 pivot, Vector2 pos, Vector2 size)
{ rt.anchorMin = aMin; rt.anchorMax = aMax; rt.pivot = pivot; rt.anchoredPosition = pos; rt.sizeDelta = size; }
private static void SetEnum(Component c, string prop, int value)
{ var so = new SerializedObject(c); var p = so.FindProperty(prop); if (p != null) { p.enumValueIndex = value; so.ApplyModifiedPropertiesWithoutUndo(); } }
private static void SetString(Component c, string prop, string value)
{ if (c == null) return; var so = new SerializedObject(c); var p = so.FindProperty(prop); if (p != null) { p.stringValue = value; so.ApplyModifiedPropertiesWithoutUndo(); } }
private static void AssignRef(Object target, string prop, Object value)
{ var so = new SerializedObject(target); var p = so.FindProperty(prop); if (p != null) { p.objectReferenceValue = value; so.ApplyModifiedPropertiesWithoutUndo(); } }
private static T FindAsset<T>(string name) where T : Object
{
foreach (var guid in AssetDatabase.FindAssets($"{name} t:{typeof(T).Name}"))
{
var path = AssetDatabase.GUIDToAssetPath(guid);
var a = AssetDatabase.LoadAssetAtPath<T>(path);
if (a != null && a.name == name) return a;
}
return null;
}
private static void SetupCanvas(GameObject go, int sortOrder)
{
var canvas = go.GetComponent<Canvas>();
canvas.renderMode = RenderMode.ScreenSpaceOverlay; canvas.sortingOrder = sortOrder;
var scaler = go.GetComponent<CanvasScaler>();
scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
scaler.referenceResolution = new Vector2(1920f, 1080f);
scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight;
scaler.matchWidthOrHeight = 0.5f;
}
private static Sprite Std() => AssetDatabase.GetBuiltinExtraResource<Sprite>("UI/Skin/UISprite.psd");
private static void EnsureFolder(string dir)
{
string[] parts = dir.Split('/'); string cur = parts[0];
for (int i = 1; i < parts.Length; i++) { string n = $"{cur}/{parts[i]}"; if (!AssetDatabase.IsValidFolder(n)) AssetDatabase.CreateFolder(cur, parts[i]); cur = n; }
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0c6097f5ec7fd51489d7c90b5846043b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -131,12 +131,14 @@ namespace BaseGames.Editor.UI
if (created)
{
var items = new (string key, PauseMenuAction a)[]
// 暂停为薄覆盖层,仅系统级动作;查看/装备类(形态技能 / 能力 / 地图 / 护符 / 物品)
// 一律收敛进统一背包 Tab 屏PanelId.Inventory不再从暂停跳转。
var items = new (string key, PauseMenuAction a, PanelId panel)[]
{
("PAUSE_RESUME", PauseMenuAction.Resume),
("MENU_SETTINGS", PauseMenuAction.OpenSettings),
("PAUSE_MAIN_MENU", PauseMenuAction.ReturnToMainMenu),
("MENU_QUIT", PauseMenuAction.Quit),
("PAUSE_RESUME", PauseMenuAction.Resume, PanelId.Pause),
("MENU_SETTINGS", PauseMenuAction.OpenSettings, PanelId.Pause),
("PAUSE_MAIN_MENU", PauseMenuAction.ReturnToMainMenu, PanelId.Pause),
("MENU_QUIT", PauseMenuAction.Quit, PanelId.Pause),
};
var so = new SerializedObject(cfg);
var prop = so.FindProperty("_items");
@@ -144,9 +146,10 @@ namespace BaseGames.Editor.UI
for (int i = 0; i < items.Length; i++)
{
var el = prop.GetArrayElementAtIndex(i);
el.FindPropertyRelative("labelKey").stringValue = items[i].key;
el.FindPropertyRelative("action").enumValueIndex = (int)items[i].a;
el.FindPropertyRelative("sceneKey").stringValue = "";
el.FindPropertyRelative("labelKey").stringValue = items[i].key;
el.FindPropertyRelative("action").enumValueIndex = (int)items[i].a;
el.FindPropertyRelative("targetPanel").enumValueIndex = (int)items[i].panel;
el.FindPropertyRelative("sceneKey").stringValue = "";
}
so.ApplyModifiedPropertiesWithoutUndo();
report.Add($"{path}(默认 {items.Length} 项)");

View File

@@ -20,6 +20,10 @@ namespace BaseGames.Input
[Tooltip("背包 Tab上一页L/R 肩键)。对应 EVT_InventoryTabPrev。绑定 \"InventoryTabPrev\" Action可选。")]
[SerializeField] private VoidEventChannelSO _onInventoryTabPrev;
[Header("快速直达Gameplay/UI ActionQuickMap可选")]
[Tooltip("快速打开地图 Tab。对应 EVT_QuickOpenMap。绑定 \"QuickMap\" Action默认 M。")]
[SerializeField] private VoidEventChannelSO _onQuickMap;
[Header("UI 操作")]
[Tooltip("UI 取消操作ESC / 手柄 B·Circle。由 UIManager 全局订阅,关闭当前栈顶面板。对应 EVT_UICancelPressed。")]
[SerializeField] private VoidEventChannelSO _onUICancelPressed;
@@ -32,9 +36,9 @@ namespace BaseGames.Input
public event Action ParryEvent;
public event Action DashEvent;
public event Action UseSpringEvent;
public event Action SwitchSkyFormEvent;
public event Action SwitchEarthFormEvent;
public event Action SwitchDeathFormEvent;
public event Action SwitchTianHunFormEvent;
public event Action SwitchDiHunFormEvent;
public event Action SwitchMingHunFormEvent;
public event Action SoulSkillEvent;
public event Action SpiritSkill1StartedEvent;
public event Action SpiritSkill1CancelledEvent;
@@ -192,9 +196,9 @@ namespace BaseGames.Input
BindStarted(_gameplay, "Parry", () => ParryEvent?.Invoke());
BindStarted(_gameplay, "Dash", () => DashEvent?.Invoke());
BindStarted(_gameplay, "UseSpring", () => UseSpringEvent?.Invoke());
BindStarted(_gameplay, "SwitchSkyForm", () => SwitchSkyFormEvent?.Invoke());
BindStarted(_gameplay, "SwitchEarthForm", () => SwitchEarthFormEvent?.Invoke());
BindStarted(_gameplay, "SwitchDeathForm", () => SwitchDeathFormEvent?.Invoke());
BindStarted(_gameplay, "SwitchTianHunForm", () => SwitchTianHunFormEvent?.Invoke());
BindStarted(_gameplay, "SwitchDiHunForm", () => SwitchDiHunFormEvent?.Invoke());
BindStarted(_gameplay, "SwitchMingHunForm", () => SwitchMingHunFormEvent?.Invoke());
BindStarted(_gameplay, "SoulSkill", () => SoulSkillEvent?.Invoke());
BindStarted(_gameplay, "SpiritSkill1", () => SpiritSkill1StartedEvent?.Invoke());
BindCanceled(_gameplay, "SpiritSkill1", () => SpiritSkill1CancelledEvent?.Invoke());
@@ -208,6 +212,8 @@ namespace BaseGames.Input
BindStarted(_gameplay, "Pause", HandlePause);
// 背包菜单开关(可选 Action默认绑定如 I 键 / 手柄 Select。未在 Map 中定义则跳过。
BindStarted(_gameplay, "Inventory", () => _onInventoryOpen?.Raise());
// 快速直达地图(可选 ActionQuickMap默认 M。未定义则跳过。
BindStarted(_gameplay, "QuickMap", () => _onQuickMap?.Raise());
if (_ui != null)
{
@@ -224,6 +230,8 @@ namespace BaseGames.Input
// 背包 Tab 循环L/R 肩键Action 名称需在 InputActionAsset UI Map 中添加(可选)
BindStarted(_ui, "InventoryTabNext", () => _onInventoryTabNext?.Raise());
BindStarted(_ui, "InventoryTabPrev", () => _onInventoryTabPrev?.Raise());
// 快速直达UI Map 同名 ActionHub 已开时按 M 直接跳地图 Tab。共用 Gameplay 同一频道。
BindStarted(_ui, "QuickMap", () => _onQuickMap?.Raise());
}
_isBound = true;

View File

@@ -54,18 +54,18 @@ namespace BaseGames.Player
{
ServiceLocator.GetOrDefault<ISaveableRegistry>()?.Register(this);
if (_input == null) return;
_input.SwitchSkyFormEvent += OnSwitchSky;
_input.SwitchEarthFormEvent += OnSwitchEarth;
_input.SwitchDeathFormEvent += OnSwitchDeath;
_input.SwitchTianHunFormEvent += OnSwitchSky;
_input.SwitchDiHunFormEvent += OnSwitchEarth;
_input.SwitchMingHunFormEvent += OnSwitchDeath;
}
private void OnDisable()
{
ServiceLocator.GetOrDefault<ISaveableRegistry>()?.Unregister(this);
if (_input == null) return;
_input.SwitchSkyFormEvent -= OnSwitchSky;
_input.SwitchEarthFormEvent -= OnSwitchEarth;
_input.SwitchDeathFormEvent -= OnSwitchDeath;
_input.SwitchTianHunFormEvent -= OnSwitchSky;
_input.SwitchDiHunFormEvent -= OnSwitchEarth;
_input.SwitchMingHunFormEvent -= OnSwitchDeath;
}
private void Start()

View File

@@ -342,6 +342,9 @@ namespace BaseGames.Player
}
// ── Abilities ─────────────────────────────────────────────────────────
/// <summary>当前已解锁能力的位掩码快照(供能力总览 UI 遍历查询)。</summary>
public AbilityType UnlockedAbilities => _unlockedAbilities;
public bool HasAbility(AbilityType ability)
=> (_unlockedAbilities & ability) == ability;

View File

@@ -0,0 +1,83 @@
using System.Collections.Generic;
using UnityEngine;
using BaseGames.Core;
using BaseGames.Core.Events;
using BaseGames.Core.Save;
namespace BaseGames.Progression
{
/// <summary>
/// 图鉴追踪服务(仿 <see cref="BaseGames.Equipment.EquipmentManager"/> 的 ISaveable + ServiceLocator 模式)。
/// 订阅 EVT_EnemyDied(payload=enemyId),记录已发现敌人与击杀次数,持久化到 <see cref="SaveData.Journal"/>。
/// 仅依赖字符串 enemyId 与事件频道不引用敌人程序集asmdef 解耦);敌人代码零改动。
/// 挂在 Persistent 的 [GameManagers] 下OnEnable 注册 IBestiaryService 与 ISaveableRegistry。
/// </summary>
public class BestiaryService : MonoBehaviour, ISaveable, IBestiaryService
{
[Header("事件频道")]
[Tooltip("EVT_EnemyDiedpayload = enemyId。敌人 / Boss 死亡时由 EnemyBase 广播。")]
[SerializeField] private StringEventChannelSO _onEnemyDied;
[Tooltip("EVT_BestiaryUpdatedpayload = enemyId。新发现 / 击杀计数更新时广播,驱动图鉴 UI 实时刷新。")]
[SerializeField] private StringEventChannelSO _onBestiaryUpdated;
private readonly HashSet<string> _discovered = new();
private readonly Dictionary<string, int> _killCounts = new();
private readonly CompositeDisposable _subs = new();
// ── IBestiaryService ─────────────────────────────────────────────────
public int DiscoveredCount => _discovered.Count;
public bool IsDiscovered(string enemyId)
=> !string.IsNullOrEmpty(enemyId) && _discovered.Contains(enemyId);
public int GetKillCount(string enemyId)
=> !string.IsNullOrEmpty(enemyId) && _killCounts.TryGetValue(enemyId, out var n) ? n : 0;
// ── 生命周期 ──────────────────────────────────────────────────────────
private void OnEnable()
{
ServiceLocator.Register<IBestiaryService>(this);
ServiceLocator.GetOrDefault<ISaveableRegistry>()?.Register(this);
_onEnemyDied?.Subscribe(OnEnemyDied).AddTo(_subs);
}
private void OnDisable()
{
ServiceLocator.Unregister<IBestiaryService>(this);
ServiceLocator.GetOrDefault<ISaveableRegistry>()?.Unregister(this);
_subs.Clear();
}
// ── 解锁处理 ──────────────────────────────────────────────────────────
private void OnEnemyDied(string enemyId)
{
if (string.IsNullOrEmpty(enemyId)) return;
_discovered.Add(enemyId);
_killCounts.TryGetValue(enemyId, out var n);
_killCounts[enemyId] = n + 1;
_onBestiaryUpdated?.Raise(enemyId);
}
// ── ISaveable ─────────────────────────────────────────────────────────
public void OnSave(SaveData data)
{
var j = data.Journal;
j.DiscoveredEnemyIds.Clear();
foreach (var id in _discovered) j.DiscoveredEnemyIds.Add(id);
j.EnemyKillCounts.Clear();
foreach (var kv in _killCounts) j.EnemyKillCounts[kv.Key] = kv.Value;
}
public void OnLoad(SaveData data)
{
_discovered.Clear();
_killCounts.Clear();
var j = data.Journal;
if (j == null) return;
if (j.DiscoveredEnemyIds != null)
foreach (var id in j.DiscoveredEnemyIds) _discovered.Add(id);
if (j.EnemyKillCounts != null)
foreach (var kv in j.EnemyKillCounts) _killCounts[kv.Key] = kv.Value;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 98b6746a3664fba43a4aad88a2b650ac
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,46 @@
using UnityEngine;
using BaseGames.Player;
namespace BaseGames.Skills
{
/// <summary>
/// 形态技能数据库(<b>权威源</b>FormType → 该形态的 3 个技能1 魂技 + 2 魄技)。
/// <para>
/// <see cref="SkillManager"/>(执行)与 FormSkillPanel展示读<b>同一份</b>资产,消除数据重复。
/// 放在 Skills 程序集而非 FormSO因 BaseGames.Player 不能反向引用 BaseGames.Skills
/// Skills→Player 已有依赖,反向会循环),故技能引用不挂 FormSO见 DesignSpec §06 与 asmdef 约束)。
/// </para>
/// 资产Assets/_Game/Data/Skills/FormSkillDatabase.asset
/// </summary>
[CreateAssetMenu(menuName = "BaseGames/Skills/Form Skill Database", fileName = "FormSkillDatabase")]
public class FormSkillDatabaseSO : ScriptableObject
{
[System.Serializable]
public struct Entry
{
[Tooltip("此条目对应的形态。")]
public FormType formType;
[Tooltip("形态标题的本地化 KeyUI 表,如 FORM_TIANHUN。供 FormSkillPanel 显示形态名。")]
public string formLabelKey;
[Tooltip("魂技(消耗灵力 / SoulPower。")]
public FormSkillSO soulSkill;
[Tooltip("魄技 1消耗魄元 / SpiritPower。")]
public FormSkillSO spiritSkill1;
[Tooltip("魄技 2。")]
public FormSkillSO spiritSkill2;
}
[SerializeField] private Entry[] _entries;
public Entry[] Entries => _entries;
/// <summary>取指定形态的技能条目;找不到返回 default三技能均 null。</summary>
public Entry GetByType(FormType type)
{
if (_entries != null)
foreach (var e in _entries)
if (e.formType == type) return e;
return default;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 812ef8f0ed1f58c469c7c35ace58b10f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -26,17 +26,8 @@ namespace BaseGames.Skills
[Header("技能挂载点")]
[SerializeField] private Transform _skillSocket; // [SkillSocket] 子节点
[Header("形态技能映射")]
[SerializeField] private FormSkillSet[] _formSkillSets; // FormType 配置,与 FormConfigSO.forms[] 对应
[System.Serializable]
private struct FormSkillSet
{
public FormType formType;
public FormSkillSO soulSkill;
public FormSkillSO spiritSkill1;
public FormSkillSO spiritSkill2;
}
[Header("形态技能数据库(权威源,与 FormSkillPanel 共享同一资产)")]
[SerializeField] private FormSkillDatabaseSO _skillDatabase; // FormType → 魂技/魄技1/魄技2
// 当前形态技能集(绑定到对应输入槽)
private FormSkillSO _soulSkill;
@@ -94,16 +85,9 @@ namespace BaseGames.Skills
private void ApplyFormSkills(FormSO form)
{
if (form == null || _formSkillSets == null) { UpdateSkillSet(null, null, null); return; }
foreach (var s in _formSkillSets)
{
if (s.formType == form.formType)
{
UpdateSkillSet(s.soulSkill, s.spiritSkill1, s.spiritSkill2);
return;
}
}
UpdateSkillSet(null, null, null);
if (form == null || _skillDatabase == null) { UpdateSkillSet(null, null, null); return; }
var e = _skillDatabase.GetByType(form.formType);
UpdateSkillSet(e.soulSkill, e.spiritSkill1, e.spiritSkill2);
}
private void Update()

View File

@@ -0,0 +1,35 @@
using UnityEngine;
using UnityEngine.UI;
using BaseGames.Localization;
namespace BaseGames.UI
{
/// <summary>
/// 能力总览单元格视图:图标 + 名称 + 已解锁/未解锁视觉(未解锁时暗化 + 显示锁定遮罩)。
/// 由 <see cref="DataDrivenAbilityPanel"/> 据 AbilityMetaSO 实例化并 Bind。
/// </summary>
[DisallowMultipleComponent]
public class AbilityCellView : MonoBehaviour
{
[SerializeField] private Image _icon;
[SerializeField] private LocalizedText _label;
[Tooltip("未解锁时显示(锁图标 / 暗罩,可空)。")]
[SerializeField] private GameObject _lockedOverlay;
[Tooltip("整格暗化用(可空)。")]
[SerializeField] private CanvasGroup _group;
public void Bind(string labelKey, Sprite icon, bool unlocked)
{
if (_label != null) _label.SetKey(labelKey);
if (_icon != null) { _icon.sprite = icon; _icon.enabled = icon != null; }
SetUnlocked(unlocked);
}
/// <summary>只更新解锁态(保留图标/名称)。设备/解锁事件刷新时调用。</summary>
public void SetUnlocked(bool unlocked)
{
if (_lockedOverlay != null) _lockedOverlay.SetActive(!unlocked);
if (_group != null) _group.alpha = unlocked ? 1f : 0.4f;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 759137176b2cfdd47b53d655d10b170f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,31 @@
using UnityEngine;
using BaseGames.Player;
namespace BaseGames.UI
{
/// <summary>
/// 能力总览数据表(策划编辑):每个 <see cref="AbilityType"/> → 名称/说明/图标。
/// <see cref="DataDrivenAbilityPanel"/> 据此列出全部能力 + 已解锁/未解锁态。
/// 改本表即增删/重排能力项、改标签/图标,零代码。
/// </summary>
[CreateAssetMenu(menuName = "BaseGames/UI/Ability Meta", fileName = "UI_AbilityMeta")]
public class AbilityMetaSO : ScriptableObject
{
[System.Serializable]
public struct Item
{
[Tooltip("此条目对应的能力位。")]
public AbilityType type;
[Tooltip("能力名标签本地化 KeyUI 表,如 ABL_DASH。")]
public string labelKey;
[Tooltip("能力说明本地化 Key可空。")]
public string descKey;
[Tooltip("能力图标(可空)。")]
public Sprite icon;
}
[SerializeField] private Item[] _items;
public Item[] Items => _items;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 381fcefcad0b4544c88188bf7e8d695e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -21,6 +21,7 @@
"BaseGames.Spells",
"BaseGames.Quest",
"BaseGames.Skills",
"BaseGames.Player",
"BaseGames.Inventory",
"Unity.Addressables",
"Unity.ResourceManager",

View File

@@ -0,0 +1,46 @@
using UnityEngine;
using UnityEngine.UI;
using BaseGames.Localization;
namespace BaseGames.UI
{
/// <summary>
/// 图鉴单元格视图(仿 <see cref="AbilityCellView"/>):肖像 + 名称 + 已发现/未发现视觉。
/// 未发现时:名称显示 "???"BESTIARY_LOCKED 文案)、肖像剪影化、暗罩、整格暗化。
/// 由 <see cref="BestiaryPanel"/> 据 <see cref="BestiaryDatabaseSO"/> 实例化并 Bind。
/// </summary>
[DisallowMultipleComponent]
public class BestiaryCellView : MonoBehaviour
{
[SerializeField] private Image _icon;
[SerializeField] private LocalizedText _label;
[Tooltip("未发现时显示的暗罩 / 锁图标(可空)。")]
[SerializeField] private GameObject _lockedOverlay;
[Tooltip("整格暗化用(可空)。")]
[SerializeField] private CanvasGroup _group;
[Tooltip("点击选中此格以在详情区展示(可空)。")]
[SerializeField] private Button _selectButton;
private const string LockedKey = "BESTIARY_LOCKED";
private string _nameKey;
public Button SelectButton => _selectButton;
public void Bind(string nameKey, Sprite icon, bool discovered)
{
_nameKey = nameKey;
if (_icon != null) { _icon.sprite = icon; _icon.enabled = icon != null; }
SetDiscovered(discovered);
}
/// <summary>只更新发现态(保留图标/名称。EVT_BestiaryUpdated 刷新时调用。</summary>
public void SetDiscovered(bool discovered)
{
if (_label != null) _label.SetKey(discovered ? _nameKey : LockedKey);
if (_lockedOverlay != null) _lockedOverlay.SetActive(!discovered);
// 未发现:肖像剪影化(压暗);已发现:原色
if (_icon != null) _icon.color = discovered ? Color.white : new Color(0.04f, 0.04f, 0.06f, 1f);
if (_group != null) _group.alpha = discovered ? 1f : 0.55f;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7734d0120f3b75b41905933b325a823e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,41 @@
using UnityEngine;
namespace BaseGames.UI
{
/// <summary>
/// 图鉴数据表(策划单表编辑,仿 <see cref="AbilityMetaSO"/>)。每条目对应一个敌人,
/// 以 <c>enemyId</c> 与 <c>EnemyBase._enemyId</c> 关联。自包含显示数据(名/图标/描述),
/// 不引用敌人程序集BaseGames.UI 不依赖 BaseGames.Enemies故显示数据放此处
/// 改本表即增删 / 重排敌人条目、改名/图标,零代码。
/// </summary>
[CreateAssetMenu(menuName = "BaseGames/UI/Bestiary Database", fileName = "UI_BestiaryDatabase")]
public class BestiaryDatabaseSO : ScriptableObject
{
public enum Tier { Normal, Elite, Boss }
[System.Serializable]
public struct Entry
{
[Tooltip("敌人唯一 ID须与 EnemyBase._enemyId 一致(如 Enemy_SpiderGuard。解锁靠此 id 匹配。")]
public string enemyId;
[Tooltip("敌人名本地化 KeyUI 表,如 ENM_E001_NAME。")]
public string displayNameKey;
[Tooltip("敌人描述 / 背景本地化 Key可空。")]
public string descKey;
[Tooltip("敌人肖像(可空)。")]
public Sprite icon;
[Tooltip("分级(普通 / 精英 / Boss用于分类与排序。")]
public Tier tier;
[Tooltip("所属区域 ID可空用于筛选。")]
public string region;
[Tooltip("解锁完整词条所需累计击杀数(<=1 即首杀全解锁)。")]
public int fullLoreKillCount;
[Tooltip("展示用最大生命策划手填0 = 不显示)。")]
public int displayMaxHP;
}
[SerializeField] private Entry[] _entries;
public Entry[] Entries => _entries;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6d7e33770928593459417c4dab65ced5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,168 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using TMPro;
using BaseGames.Core;
using BaseGames.Core.Events;
using BaseGames.Localization;
namespace BaseGames.UI
{
/// <summary>
/// 图鉴面板(数据驱动,仿 <see cref="DataDrivenAbilityPanel"/>)。据 <see cref="BestiaryDatabaseSO"/> 列出全部敌人,
/// 经 <see cref="IBestiaryService"/>(ServiceLocator) 读已发现态:已发现亮显,未发现 "???"+剪影+锁。
/// 订阅 EVT_BestiaryUpdated 实时刷新;点击格子在右侧详情区展示名/描述/数值/击杀数;显示完成度 X/Y。
/// 菜单态无游戏service=null下全部显示未发现。
/// </summary>
public class BestiaryPanel : MonoBehaviour, IFocusable
{
[Header("数据 / 单元格")]
[SerializeField] private BestiaryDatabaseSO _database;
[Tooltip("敌人格的父节点(通常挂 GridLayoutGroup。")]
[SerializeField] private Transform _container;
[SerializeField] private BestiaryCellView _cellPrefab;
[Header("头部 / 关闭")]
[Tooltip("完成度文本X / Y。")]
[SerializeField] private TMP_Text _completionText;
[SerializeField] private Button _btnClose;
[Header("详情区")]
[SerializeField] private Image _detailIcon;
[SerializeField] private LocalizedText _detailName;
[SerializeField] private TMP_Text _detailDesc;
[SerializeField] private TMP_Text _detailStats;
[Header("Event Channels")]
[Tooltip("图鉴更新广播payload=enemyId用于实时刷新。对应 EVT_BestiaryUpdated。")]
[SerializeField] private StringEventChannelSO _onBestiaryUpdated;
private readonly List<(BestiaryCellView view, BestiaryDatabaseSO.Entry entry)> _cells = new();
private readonly CompositeDisposable _subs = new();
private IBestiaryService _service;
private void Awake() => _btnClose?.onClick.AddListener(OnClose);
private void OnEnable()
{
_onBestiaryUpdated?.Subscribe(_ => RefreshStates()).AddTo(_subs);
_service = ServiceLocator.GetOrDefault<IBestiaryService>(); // 菜单态为 null → 全部未发现
BuildList();
ShowDetail(-1);
}
private void OnDisable() => _subs.Clear();
// ── 列表构建 ──────────────────────────────────────────────────────────
public void BuildList()
{
ClearList();
if (_database == null || _container == null || _cellPrefab == null) return;
var entries = _database.Entries;
if (entries == null) return;
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
var cell = Instantiate(_cellPrefab, _container);
cell.gameObject.SetActive(true);
cell.Bind(entry.displayNameKey, entry.icon, IsDiscovered(entry));
int idx = i;
if (cell.SelectButton != null)
cell.SelectButton.onClick.AddListener(() => ShowDetail(idx));
_cells.Add((cell, entry));
}
UpdateCompletion();
}
private void RefreshStates()
{
if (_service == null) _service = ServiceLocator.GetOrDefault<IBestiaryService>();
foreach (var (view, entry) in _cells)
if (view != null) view.SetDiscovered(IsDiscovered(entry));
UpdateCompletion();
}
private bool IsDiscovered(BestiaryDatabaseSO.Entry entry)
=> _service != null && _service.IsDiscovered(entry.enemyId);
private void UpdateCompletion()
{
if (_completionText == null) return;
int total = _database != null && _database.Entries != null ? _database.Entries.Length : 0;
int found = 0;
foreach (var (_, entry) in _cells) if (IsDiscovered(entry)) found++;
_completionText.text = $"{found} / {total}";
}
// ── 详情 ──────────────────────────────────────────────────────────────
private void ShowDetail(int index)
{
bool valid = index >= 0 && index < _cells.Count;
var entry = valid ? _cells[index].entry : default;
bool discovered = valid && IsDiscovered(entry);
if (_detailIcon != null)
{
_detailIcon.sprite = discovered ? entry.icon : null;
_detailIcon.enabled = discovered && entry.icon != null;
}
if (_detailName != null)
_detailName.SetKey(!valid ? "" : (discovered ? entry.displayNameKey : "BESTIARY_LOCKED"));
if (_detailDesc != null)
{
if (!valid) _detailDesc.text = "";
else if (!discovered) _detailDesc.text = LocalizationManager.Get("BESTIARY_LOCKED_DESC", LocalizationTable.UI);
else
{
string d = LocalizationManager.Get(entry.descKey, LocalizationTable.UI);
_detailDesc.text = string.IsNullOrEmpty(d) || d == entry.descKey ? "" : d;
}
}
if (_detailStats != null)
{
if (!valid || !discovered) { _detailStats.text = ""; }
else
{
int kills = _service != null ? _service.GetKillCount(entry.enemyId) : 0;
string hpLabel = LocalizationManager.Get("BESTIARY_HP", LocalizationTable.UI);
string killLabel = LocalizationManager.Get("BESTIARY_KILLS", LocalizationTable.UI);
var sb = new System.Text.StringBuilder();
if (entry.displayMaxHP > 0) sb.Append(hpLabel).Append(' ').Append(entry.displayMaxHP).Append(" ");
sb.Append(killLabel).Append(' ').Append(kills);
_detailStats.text = sb.ToString();
}
}
}
private void ClearList()
{
_cells.Clear();
if (_container == null) return;
for (int i = _container.childCount - 1; i >= 0; i--)
{
var c = _container.GetChild(i).gameObject;
if (Application.isPlaying) Destroy(c); else DestroyImmediate(c);
}
}
private void OnClose()
{
var uiMgr = ServiceLocator.GetOrDefault<UIManager>();
if (uiMgr != null) uiMgr.CloseTopPanel();
else gameObject.SetActive(false);
}
// ── IFocusable ────────────────────────────────────────────────────────
public void OnFocusRestored()
{
GameObject target = _cells.Count > 0 && _cells[0].view != null && _cells[0].view.SelectButton != null
? _cells[0].view.SelectButton.gameObject
: _btnClose != null ? _btnClose.gameObject : null;
if (target != null) EventSystem.current?.SetSelectedGameObject(target);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0fbb26cf6309a0749b96d6137a9b1b61
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,87 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using BaseGames.Core;
using BaseGames.Core.Events;
using BaseGames.Player;
namespace BaseGames.UI
{
/// <summary>
/// 能力解锁总览面板(数据驱动)。据 <see cref="AbilityMetaSO"/> 列出全部能力 + 已解锁/未解锁态。
/// 在场景中找 <see cref="PlayerStats"/> 读 <see cref="PlayerStats.UnlockedAbilities"/>
/// 订阅 <see cref="AbilityTypeEventChannelSO"/>(EVT_AbilityUnlocked) 实时刷新解锁态。
/// 策划改 UI_AbilityMeta 即增删/重排能力、改标签图标;美术改 UI_AbilityCell / 面板预制件改样式。
/// </summary>
public class DataDrivenAbilityPanel : MonoBehaviour
{
[Header("数据 / 单元格")]
[SerializeField] private AbilityMetaSO _meta;
[Tooltip("能力格的父节点(通常挂 GridLayoutGroup。")]
[SerializeField] private Transform _container;
[SerializeField] private AbilityCellView _cellPrefab;
[Header("引用")]
[SerializeField] private Button _btnClose;
[Header("Event Channels")]
[Tooltip("能力解锁广播AbilityType payload用于实时刷新。对应 EVT_AbilityUnlocked。")]
[SerializeField] private AbilityTypeEventChannelSO _onAbilityUnlocked;
private readonly List<(AbilityCellView view, AbilityType type)> _cells = new();
private readonly CompositeDisposable _subs = new();
private PlayerStats _stats;
private void Awake() => _btnClose?.onClick.AddListener(OnClose);
private void OnEnable()
{
_onAbilityUnlocked?.Subscribe(_ => RefreshStates()).AddTo(_subs);
_stats = FindObjectOfType<PlayerStats>(true); // 游戏内有玩家;菜单态为 null全部显示未解锁
BuildList();
}
private void OnDisable() => _subs.Clear();
/// <summary>据 AbilityMetaSO 重建能力格public 以便编辑器/测试)。</summary>
public void BuildList()
{
ClearList();
if (_meta == null || _container == null || _cellPrefab == null) return;
foreach (var item in _meta.Items)
{
var cell = Instantiate(_cellPrefab, _container);
cell.gameObject.SetActive(true);
cell.Bind(item.labelKey, item.icon, IsUnlocked(item.type));
_cells.Add((cell, item.type));
}
}
private void RefreshStates()
{
if (_stats == null) _stats = FindObjectOfType<PlayerStats>(true);
foreach (var (view, type) in _cells)
if (view != null) view.SetUnlocked(IsUnlocked(type));
}
private bool IsUnlocked(AbilityType type) => _stats != null && _stats.HasAbility(type);
private void ClearList()
{
_cells.Clear();
if (_container == null) return;
for (int i = _container.childCount - 1; i >= 0; i--)
{
var c = _container.GetChild(i).gameObject;
if (Application.isPlaying) Destroy(c); else DestroyImmediate(c);
}
}
private void OnClose()
{
var uiMgr = ServiceLocator.GetOrDefault<UIManager>();
if (uiMgr != null) uiMgr.CloseTopPanel();
else gameObject.SetActive(false);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ba7e35964864d7d44b021a24a7213c52
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -14,8 +14,9 @@ namespace BaseGames.UI
/// 只读面板:按形态展示各技能槽的技能资料(名称、描述、消耗、冷却),不含任何解锁/技能点交互。
/// 支持左右翻页浏览各形态,并高亮当前实际使用的形态。
///
/// 数据驱动:技能数据读 <see cref="FormSkillDatabaseSO"/>(与 SkillManager 共享的权威源),不再复制配置。
/// Inspector 必填:
/// _formSkillSets每个形态对应一条配置soulSkill + spirit1 + spirit2
/// _database FormSkillDatabaseSO与玩家 SkillManager 同一资产
/// _formTitleText — 显示当前形态标签名的文本
/// _prevFormBtn / _nextFormBtn — 翻页按钮
/// _activeFormIndicator — 高亮"当前形态"的标志(可选,如小圆点)
@@ -26,19 +27,6 @@ namespace BaseGames.UI
{
// ── 子数据结构 ────────────────────────────────────────────────────────
[System.Serializable]
public struct FormSkillConfig
{
[Tooltip("形态标题的本地化 Key格式如 \"Form_SkyWarden_Label\",由 LocalizationManager.Get(…, LocalizationTable.UI) 查找。")]
public string formLabelKey;
[Tooltip("天魂/地魂/命魂的「魂技」")]
public FormSkillSO soulSkill;
[Tooltip("灵技 1Y / Triangle / 手柄按钮)")]
public FormSkillSO spiritSkill1;
[Tooltip("灵技 2Shift+Y / L2+Triangle 等)")]
public FormSkillSO spiritSkill2;
}
[System.Serializable]
public struct SkillSlotView
{
@@ -58,9 +46,8 @@ namespace BaseGames.UI
// ── Inspector 字段 ────────────────────────────────────────────────────
[Header("形态技能配置")]
[Tooltip("每个元素对应一种形态的三项技能,顺序应与 FormType 枚举序号一致。")]
[SerializeField] private FormSkillConfig[] _formSkillSets;
[Header("形态技能数据库(权威源,与玩家 SkillManager 共享同一资产)")]
[SerializeField] private FormSkillDatabaseSO _database;
[Header("UI 导航")]
[SerializeField] private TMP_Text _formTitleText;
@@ -87,6 +74,8 @@ namespace BaseGames.UI
private int _activeIndex = 0; // 玩家当前实际使用的形态
private readonly CompositeDisposable _subs = new();
private FormSkillDatabaseSO.Entry[] Entries => _database != null ? _database.Entries : null;
// ── 生命周期 ──────────────────────────────────────────────────────────
private void Awake()
@@ -122,15 +111,17 @@ namespace BaseGames.UI
private void PrevForm()
{
if (_formSkillSets == null || _formSkillSets.Length == 0) return;
_viewIndex = (_viewIndex - 1 + _formSkillSets.Length) % _formSkillSets.Length;
var entries = Entries;
if (entries == null || entries.Length == 0) return;
_viewIndex = (_viewIndex - 1 + entries.Length) % entries.Length;
Refresh();
}
private void NextForm()
{
if (_formSkillSets == null || _formSkillSets.Length == 0) return;
_viewIndex = (_viewIndex + 1) % _formSkillSets.Length;
var entries = Entries;
if (entries == null || entries.Length == 0) return;
_viewIndex = (_viewIndex + 1) % entries.Length;
Refresh();
}
@@ -138,10 +129,11 @@ namespace BaseGames.UI
private void Refresh()
{
if (_formSkillSets == null || _formSkillSets.Length == 0) return;
_viewIndex = Mathf.Clamp(_viewIndex, 0, _formSkillSets.Length - 1);
var entries = Entries;
if (entries == null || entries.Length == 0) return;
_viewIndex = Mathf.Clamp(_viewIndex, 0, entries.Length - 1);
var cfg = _formSkillSets[_viewIndex];
var cfg = entries[_viewIndex];
// 标题走本地化管道fallback 为 key 本身)
if (_formTitleText != null)
@@ -159,7 +151,7 @@ namespace BaseGames.UI
_activeFormIndicator.SetActive(_viewIndex == _activeIndex);
// 翻页按钮可见性(只有一种形态时隐藏)
bool multiForm = _formSkillSets.Length > 1;
bool multiForm = entries.Length > 1;
if (_prevFormBtn != null) _prevFormBtn.gameObject.SetActive(multiForm);
if (_nextFormBtn != null) _nextFormBtn.gameObject.SetActive(multiForm);

View File

@@ -118,6 +118,17 @@ namespace BaseGames.UI.Inventory
/// <summary>切换到指定 Tab。无效索引或与当前相同则忽略。</summary>
public void SelectTab(int index) => SelectTab(index, raise: true, animateEntry: false);
/// <summary>
/// 按内容根名(如 "Content_Map" / "Content_Inventory" / "Content_Quests")选中对应 Tab找不到则忽略。
/// 供"快速直达键"用与数字索引解耦Tab 重排后仍正确。
/// </summary>
public void SelectTabByContentName(string contentName)
{
if (_tabs == null || string.IsNullOrEmpty(contentName)) return;
for (int i = 0; i < _tabs.Length; i++)
if (_tabs[i].content != null && _tabs[i].content.name == contentName) { SelectTab(i); return; }
}
private void SelectTab(int index, bool raise, bool animateEntry)
{
if (_tabs == null || _tabs.Length == 0) return;

View File

@@ -0,0 +1,43 @@
using UnityEngine;
using BaseGames.Input;
namespace BaseGames.UI
{
/// <summary>
/// 挂在"游戏内全屏菜单"根节点(如 InventoryHubRoot
/// 打开OnEnable时冻结游戏Time.timeScale=0并切到 UI 输入关闭OnDisable时恢复时间并切回 Gameplay 输入。
///
/// 解决的 bug游戏内菜单统一背包屏打开时本不改 GameState导致 Gameplay 输入仍激活、
/// 按 Esc 触发的是"暂停"而非"关闭菜单",且关闭后状态错乱使 Esc 不再暂停。
/// 切到 UI 输入后:菜单内 Esc=关闭UINavigator Cancel关闭后 Esc=暂停Gameplay
/// 同时冻结时间符合"打开背包暂停游戏"的常规手感。
///
/// 仅作用于本菜单的开/关与暂停菜单PausedState的真实暂停相互独立、互不冲突。
/// </summary>
[DisallowMultipleComponent]
public class MenuPauseScope : MonoBehaviour
{
[SerializeField] private InputReaderSO _inputReader;
[Tooltip("打开时是否冻结游戏时间Time.timeScale=0。菜单动画须用 unscaledDeltaTime。")]
[SerializeField] private bool _freezeTime = true;
private float _prevTimeScale = 1f;
private void OnEnable()
{
if (_freezeTime)
{
_prevTimeScale = Time.timeScale;
Time.timeScale = 0f;
}
_inputReader?.EnableUIInput();
}
private void OnDisable()
{
if (_freezeTime)
Time.timeScale = _prevTimeScale; // 恢复打开前的时间倍率(若打开前已是 0 则维持暂停,正确)
_inputReader?.EnableGameplayInput();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 09d80c6e088f83c4f8a1edadbf5455cb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -82,6 +82,9 @@ namespace BaseGames.UI
case PauseMenuAction.OpenSettings:
_uiManager?.OpenPanel(PanelId.Settings);
break;
case PauseMenuAction.OpenPanel:
_uiManager?.OpenPanel(item.targetPanel);
break;
case PauseMenuAction.ReturnToMainMenu:
_uiManager?.CloseTopPanel();
_onSceneLoadRequest?.Raise(new SceneLoadRequest

View File

@@ -9,6 +9,7 @@ namespace BaseGames.UI
{
Resume, // 继续游戏(关闭暂停面板)
OpenSettings, // 打开设置面板
OpenPanel, // 打开任意已注册面板(用 targetPanel 指定,如 FormSkills/Abilities
ReturnToMainMenu, // 返回主菜单(场景加载)
Quit, // 退出游戏
RaiseEvent, // 触发 eventChannel万能扩展
@@ -34,6 +35,9 @@ namespace BaseGames.UI
[Tooltip("点击动作。")]
public PauseMenuAction action;
[Tooltip("OpenPanel 动作要打开的面板 ID如 FormSkills / Abilities / Map。")]
public PanelId targetPanel;
[Tooltip("ReturnToMainMenu 的目标场景 Addressable Key留空用默认主菜单。")]
public string sceneKey;

View File

@@ -21,6 +21,8 @@ namespace BaseGames.UI
CharmPanel,
SpellSelect,
Inventory,
FormSkills, // 形态技能一览FormSkillPanel
Abilities, // 能力解锁总览DataDrivenAbilityPanel
}
[DefaultExecutionOrder(+50)]
@@ -53,6 +55,8 @@ namespace BaseGames.UI
[SerializeField] private VoidEventChannelSO _onSpellSelectOpen;
[Tooltip("打开统一背包菜单InventoryHub。对应 EVT_InventoryOpen。")]
[SerializeField] private VoidEventChannelSO _onInventoryOpen;
[Tooltip("快速直达:打开统一屏并定位到地图 Tab。对应 EVT_QuickOpenMap。")]
[SerializeField] private VoidEventChannelSO _onQuickOpenMap;
// ── 面板栈:委托给统一的 UINavigator不再自管栈─────────────────────
private IUINavigator _navigator;
@@ -119,6 +123,7 @@ namespace BaseGames.UI
_onCharmPanelOpen?.Subscribe(OpenCharmPanel).AddTo(_subs);
_onSpellSelectOpen?.Subscribe(OpenSpellSelect).AddTo(_subs);
_onInventoryOpen?.Subscribe(OpenInventory).AddTo(_subs);
_onQuickOpenMap?.Subscribe(() => OpenInventoryAt("Content_Map")).AddTo(_subs);
// 取消键ESC / 手柄 B由 UINavigator 统一消费UIManager 不再订阅。
}
@@ -278,7 +283,32 @@ namespace BaseGames.UI
private void OpenMap() => OpenPanel(PanelId.Map);
private void OpenCharmPanel() => OpenPanel(PanelId.CharmPanel);
private void OpenSpellSelect() => OpenPanel(PanelId.SpellSelect);
private void OpenInventory() => OpenPanel(PanelId.Inventory);
/// <summary>背包键 toggle若统一背包屏正位于栈顶则关闭否则打开同键开/关)。</summary>
private void OpenInventory()
{
if (_panelRegistry.TryGetValue(PanelId.Inventory, out var inv)
&& Navigator?.Top != null && Navigator.Top.gameObject == inv)
Navigator.Pop();
else
OpenPanel(PanelId.Inventory);
}
/// <summary>
/// 快速直达:确保统一背包屏打开,并定位到指定内容根名对应的 Tab如 "Content_Map")。
/// 已打开则只切 Tab不关闭未打开则打开后切。按名定位与 Tab 顺序解耦。
/// </summary>
private void OpenInventoryAt(string contentName)
{
if (!_panelRegistry.TryGetValue(PanelId.Inventory, out var inv) || inv == null)
{
Debug.LogWarning("[UIManager] 统一背包屏PanelId.Inventory未注册快速直达失败。", this);
return;
}
bool hubTop = Navigator?.Top != null && Navigator.Top.gameObject == inv;
if (!hubTop) OpenPanel(PanelId.Inventory); // 激活时 OnEnable 同步运行
inv.GetComponent<Inventory.InventoryHubPanel>()?.SelectTabByContentName(contentName);
}
// ── 编辑器工具 ────────────────────────────────────────────────────────
[ContextMenu("验证面板注册表")]

View File

@@ -165,28 +165,28 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable
""initialStateCheck"": false
},
{
""name"": ""SwitchSkyForm"",
""name"": ""SwitchTianHunForm"",
""type"": ""Button"",
""id"": ""288ba219-3999-4951-95a5-7f59de67e9c2"",
""expectedControlType"": ""Button"",
""expectedControlType"": """",
""processors"": """",
""interactions"": """",
""initialStateCheck"": false
},
{
""name"": ""SwitchEarthForm"",
""name"": ""SwitchDiHunForm"",
""type"": ""Button"",
""id"": ""1ebc4d85-1cd6-4730-abac-6020f74787e1"",
""expectedControlType"": ""Button"",
""expectedControlType"": """",
""processors"": """",
""interactions"": """",
""initialStateCheck"": false
},
{
""name"": ""SwitchDeathForm"",
""name"": ""SwitchMingHunForm"",
""type"": ""Button"",
""id"": ""1d80c36d-a347-44ac-9498-f3bb262f5643"",
""expectedControlType"": ""Button"",
""expectedControlType"": """",
""processors"": """",
""interactions"": """",
""initialStateCheck"": false
@@ -253,6 +253,15 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable
""processors"": """",
""interactions"": """",
""initialStateCheck"": false
},
{
""name"": ""QuickMap"",
""type"": ""Button"",
""id"": ""b7f46b82-62e8-43ad-955f-0a91cd9b3f57"",
""expectedControlType"": """",
""processors"": """",
""interactions"": """",
""initialStateCheck"": false
}
],
""bindings"": [
@@ -472,7 +481,7 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable
""interactions"": """",
""processors"": """",
""groups"": ""Keyboard&Mouse"",
""action"": ""SwitchSkyForm"",
""action"": ""SwitchTianHunForm"",
""isComposite"": false,
""isPartOfComposite"": false
},
@@ -483,7 +492,7 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable
""interactions"": """",
""processors"": """",
""groups"": ""Keyboard&Mouse"",
""action"": ""SwitchEarthForm"",
""action"": ""SwitchDiHunForm"",
""isComposite"": false,
""isPartOfComposite"": false
},
@@ -494,7 +503,7 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable
""interactions"": """",
""processors"": """",
""groups"": ""Keyboard&Mouse"",
""action"": ""SwitchDeathForm"",
""action"": ""SwitchMingHunForm"",
""isComposite"": false,
""isPartOfComposite"": false
},
@@ -607,6 +616,17 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable
""action"": ""Inventory"",
""isComposite"": false,
""isPartOfComposite"": false
},
{
""name"": """",
""id"": ""6e531471-28cc-47a5-9550-0e7a32471eb3"",
""path"": ""<Keyboard>/m"",
""interactions"": """",
""processors"": """",
""groups"": """",
""action"": ""QuickMap"",
""isComposite"": false,
""isPartOfComposite"": false
}
]
},
@@ -739,6 +759,15 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable
""processors"": """",
""interactions"": """",
""initialStateCheck"": false
},
{
""name"": ""QuickMap"",
""type"": ""Button"",
""id"": ""65742438-4d43-4c79-8499-5781ad34dcb0"",
""expectedControlType"": """",
""processors"": """",
""interactions"": """",
""initialStateCheck"": false
}
],
""bindings"": [
@@ -1258,6 +1287,17 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable
""action"": ""InventoryTabPrev"",
""isComposite"": false,
""isPartOfComposite"": false
},
{
""name"": """",
""id"": ""d1d954e4-fccd-49e9-ac07-b0c4a476fcf3"",
""path"": ""<Keyboard>/m"",
""interactions"": """",
""processors"": """",
""groups"": """",
""action"": ""QuickMap"",
""isComposite"": false,
""isPartOfComposite"": false
}
]
}
@@ -1302,9 +1342,9 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable
m_Gameplay_Parry = m_Gameplay.FindAction("Parry", throwIfNotFound: true);
m_Gameplay_Dash = m_Gameplay.FindAction("Dash", throwIfNotFound: true);
m_Gameplay_UseSpring = m_Gameplay.FindAction("UseSpring", throwIfNotFound: true);
m_Gameplay_SwitchSkyForm = m_Gameplay.FindAction("SwitchSkyForm", throwIfNotFound: true);
m_Gameplay_SwitchEarthForm = m_Gameplay.FindAction("SwitchEarthForm", throwIfNotFound: true);
m_Gameplay_SwitchDeathForm = m_Gameplay.FindAction("SwitchDeathForm", throwIfNotFound: true);
m_Gameplay_SwitchTianHunForm = m_Gameplay.FindAction("SwitchTianHunForm", throwIfNotFound: true);
m_Gameplay_SwitchDiHunForm = m_Gameplay.FindAction("SwitchDiHunForm", throwIfNotFound: true);
m_Gameplay_SwitchMingHunForm = m_Gameplay.FindAction("SwitchMingHunForm", throwIfNotFound: true);
m_Gameplay_SoulSkill = m_Gameplay.FindAction("SoulSkill", throwIfNotFound: true);
m_Gameplay_SpiritSkill1 = m_Gameplay.FindAction("SpiritSkill1", throwIfNotFound: true);
m_Gameplay_SpiritSkill2 = m_Gameplay.FindAction("SpiritSkill2", throwIfNotFound: true);
@@ -1312,6 +1352,7 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable
m_Gameplay_Pause = m_Gameplay.FindAction("Pause", throwIfNotFound: true);
m_Gameplay_Spell = m_Gameplay.FindAction("Spell", throwIfNotFound: true);
m_Gameplay_Inventory = m_Gameplay.FindAction("Inventory", throwIfNotFound: true);
m_Gameplay_QuickMap = m_Gameplay.FindAction("QuickMap", throwIfNotFound: true);
// UI
m_UI = asset.FindActionMap("UI", throwIfNotFound: true);
m_UI_Navigate = m_UI.FindAction("Navigate", throwIfNotFound: true);
@@ -1328,6 +1369,7 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable
m_UI_MapCenter = m_UI.FindAction("MapCenter", throwIfNotFound: true);
m_UI_InventoryTabNext = m_UI.FindAction("InventoryTabNext", throwIfNotFound: true);
m_UI_InventoryTabPrev = m_UI.FindAction("InventoryTabPrev", throwIfNotFound: true);
m_UI_QuickMap = m_UI.FindAction("QuickMap", throwIfNotFound: true);
}
~@PlayerInputActions()
@@ -1417,9 +1459,9 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable
private readonly InputAction m_Gameplay_Parry;
private readonly InputAction m_Gameplay_Dash;
private readonly InputAction m_Gameplay_UseSpring;
private readonly InputAction m_Gameplay_SwitchSkyForm;
private readonly InputAction m_Gameplay_SwitchEarthForm;
private readonly InputAction m_Gameplay_SwitchDeathForm;
private readonly InputAction m_Gameplay_SwitchTianHunForm;
private readonly InputAction m_Gameplay_SwitchDiHunForm;
private readonly InputAction m_Gameplay_SwitchMingHunForm;
private readonly InputAction m_Gameplay_SoulSkill;
private readonly InputAction m_Gameplay_SpiritSkill1;
private readonly InputAction m_Gameplay_SpiritSkill2;
@@ -1427,6 +1469,7 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable
private readonly InputAction m_Gameplay_Pause;
private readonly InputAction m_Gameplay_Spell;
private readonly InputAction m_Gameplay_Inventory;
private readonly InputAction m_Gameplay_QuickMap;
/// <summary>
/// Provides access to input actions defined in input action map "Gameplay".
/// </summary>
@@ -1471,17 +1514,17 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable
/// </summary>
public InputAction @UseSpring => m_Wrapper.m_Gameplay_UseSpring;
/// <summary>
/// Provides access to the underlying input action "Gameplay/SwitchSkyForm".
/// Provides access to the underlying input action "Gameplay/SwitchTianHunForm".
/// </summary>
public InputAction @SwitchSkyForm => m_Wrapper.m_Gameplay_SwitchSkyForm;
public InputAction @SwitchTianHunForm => m_Wrapper.m_Gameplay_SwitchTianHunForm;
/// <summary>
/// Provides access to the underlying input action "Gameplay/SwitchEarthForm".
/// Provides access to the underlying input action "Gameplay/SwitchDiHunForm".
/// </summary>
public InputAction @SwitchEarthForm => m_Wrapper.m_Gameplay_SwitchEarthForm;
public InputAction @SwitchDiHunForm => m_Wrapper.m_Gameplay_SwitchDiHunForm;
/// <summary>
/// Provides access to the underlying input action "Gameplay/SwitchDeathForm".
/// Provides access to the underlying input action "Gameplay/SwitchMingHunForm".
/// </summary>
public InputAction @SwitchDeathForm => m_Wrapper.m_Gameplay_SwitchDeathForm;
public InputAction @SwitchMingHunForm => m_Wrapper.m_Gameplay_SwitchMingHunForm;
/// <summary>
/// Provides access to the underlying input action "Gameplay/SoulSkill".
/// </summary>
@@ -1511,6 +1554,10 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable
/// </summary>
public InputAction @Inventory => m_Wrapper.m_Gameplay_Inventory;
/// <summary>
/// Provides access to the underlying input action "Gameplay/QuickMap".
/// </summary>
public InputAction @QuickMap => m_Wrapper.m_Gameplay_QuickMap;
/// <summary>
/// Provides access to the underlying input action map instance.
/// </summary>
public InputActionMap Get() { return m_Wrapper.m_Gameplay; }
@@ -1560,15 +1607,15 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable
@UseSpring.started += instance.OnUseSpring;
@UseSpring.performed += instance.OnUseSpring;
@UseSpring.canceled += instance.OnUseSpring;
@SwitchSkyForm.started += instance.OnSwitchSkyForm;
@SwitchSkyForm.performed += instance.OnSwitchSkyForm;
@SwitchSkyForm.canceled += instance.OnSwitchSkyForm;
@SwitchEarthForm.started += instance.OnSwitchEarthForm;
@SwitchEarthForm.performed += instance.OnSwitchEarthForm;
@SwitchEarthForm.canceled += instance.OnSwitchEarthForm;
@SwitchDeathForm.started += instance.OnSwitchDeathForm;
@SwitchDeathForm.performed += instance.OnSwitchDeathForm;
@SwitchDeathForm.canceled += instance.OnSwitchDeathForm;
@SwitchTianHunForm.started += instance.OnSwitchTianHunForm;
@SwitchTianHunForm.performed += instance.OnSwitchTianHunForm;
@SwitchTianHunForm.canceled += instance.OnSwitchTianHunForm;
@SwitchDiHunForm.started += instance.OnSwitchDiHunForm;
@SwitchDiHunForm.performed += instance.OnSwitchDiHunForm;
@SwitchDiHunForm.canceled += instance.OnSwitchDiHunForm;
@SwitchMingHunForm.started += instance.OnSwitchMingHunForm;
@SwitchMingHunForm.performed += instance.OnSwitchMingHunForm;
@SwitchMingHunForm.canceled += instance.OnSwitchMingHunForm;
@SoulSkill.started += instance.OnSoulSkill;
@SoulSkill.performed += instance.OnSoulSkill;
@SoulSkill.canceled += instance.OnSoulSkill;
@@ -1590,6 +1637,9 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable
@Inventory.started += instance.OnInventory;
@Inventory.performed += instance.OnInventory;
@Inventory.canceled += instance.OnInventory;
@QuickMap.started += instance.OnQuickMap;
@QuickMap.performed += instance.OnQuickMap;
@QuickMap.canceled += instance.OnQuickMap;
}
/// <summary>
@@ -1625,15 +1675,15 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable
@UseSpring.started -= instance.OnUseSpring;
@UseSpring.performed -= instance.OnUseSpring;
@UseSpring.canceled -= instance.OnUseSpring;
@SwitchSkyForm.started -= instance.OnSwitchSkyForm;
@SwitchSkyForm.performed -= instance.OnSwitchSkyForm;
@SwitchSkyForm.canceled -= instance.OnSwitchSkyForm;
@SwitchEarthForm.started -= instance.OnSwitchEarthForm;
@SwitchEarthForm.performed -= instance.OnSwitchEarthForm;
@SwitchEarthForm.canceled -= instance.OnSwitchEarthForm;
@SwitchDeathForm.started -= instance.OnSwitchDeathForm;
@SwitchDeathForm.performed -= instance.OnSwitchDeathForm;
@SwitchDeathForm.canceled -= instance.OnSwitchDeathForm;
@SwitchTianHunForm.started -= instance.OnSwitchTianHunForm;
@SwitchTianHunForm.performed -= instance.OnSwitchTianHunForm;
@SwitchTianHunForm.canceled -= instance.OnSwitchTianHunForm;
@SwitchDiHunForm.started -= instance.OnSwitchDiHunForm;
@SwitchDiHunForm.performed -= instance.OnSwitchDiHunForm;
@SwitchDiHunForm.canceled -= instance.OnSwitchDiHunForm;
@SwitchMingHunForm.started -= instance.OnSwitchMingHunForm;
@SwitchMingHunForm.performed -= instance.OnSwitchMingHunForm;
@SwitchMingHunForm.canceled -= instance.OnSwitchMingHunForm;
@SoulSkill.started -= instance.OnSoulSkill;
@SoulSkill.performed -= instance.OnSoulSkill;
@SoulSkill.canceled -= instance.OnSoulSkill;
@@ -1655,6 +1705,9 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable
@Inventory.started -= instance.OnInventory;
@Inventory.performed -= instance.OnInventory;
@Inventory.canceled -= instance.OnInventory;
@QuickMap.started -= instance.OnQuickMap;
@QuickMap.performed -= instance.OnQuickMap;
@QuickMap.canceled -= instance.OnQuickMap;
}
/// <summary>
@@ -1706,6 +1759,7 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable
private readonly InputAction m_UI_MapCenter;
private readonly InputAction m_UI_InventoryTabNext;
private readonly InputAction m_UI_InventoryTabPrev;
private readonly InputAction m_UI_QuickMap;
/// <summary>
/// Provides access to input actions defined in input action map "UI".
/// </summary>
@@ -1774,6 +1828,10 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable
/// </summary>
public InputAction @InventoryTabPrev => m_Wrapper.m_UI_InventoryTabPrev;
/// <summary>
/// Provides access to the underlying input action "UI/QuickMap".
/// </summary>
public InputAction @QuickMap => m_Wrapper.m_UI_QuickMap;
/// <summary>
/// Provides access to the underlying input action map instance.
/// </summary>
public InputActionMap Get() { return m_Wrapper.m_UI; }
@@ -1841,6 +1899,9 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable
@InventoryTabPrev.started += instance.OnInventoryTabPrev;
@InventoryTabPrev.performed += instance.OnInventoryTabPrev;
@InventoryTabPrev.canceled += instance.OnInventoryTabPrev;
@QuickMap.started += instance.OnQuickMap;
@QuickMap.performed += instance.OnQuickMap;
@QuickMap.canceled += instance.OnQuickMap;
}
/// <summary>
@@ -1894,6 +1955,9 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable
@InventoryTabPrev.started -= instance.OnInventoryTabPrev;
@InventoryTabPrev.performed -= instance.OnInventoryTabPrev;
@InventoryTabPrev.canceled -= instance.OnInventoryTabPrev;
@QuickMap.started -= instance.OnQuickMap;
@QuickMap.performed -= instance.OnQuickMap;
@QuickMap.canceled -= instance.OnQuickMap;
}
/// <summary>
@@ -2017,26 +2081,26 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable
/// <seealso cref="UnityEngine.InputSystem.InputAction.canceled" />
void OnUseSpring(InputAction.CallbackContext context);
/// <summary>
/// Method invoked when associated input action "SwitchSkyForm" is either <see cref="UnityEngine.InputSystem.InputAction.started" />, <see cref="UnityEngine.InputSystem.InputAction.performed" /> or <see cref="UnityEngine.InputSystem.InputAction.canceled" />.
/// Method invoked when associated input action "SwitchTianHunForm" is either <see cref="UnityEngine.InputSystem.InputAction.started" />, <see cref="UnityEngine.InputSystem.InputAction.performed" /> or <see cref="UnityEngine.InputSystem.InputAction.canceled" />.
/// </summary>
/// <seealso cref="UnityEngine.InputSystem.InputAction.started" />
/// <seealso cref="UnityEngine.InputSystem.InputAction.performed" />
/// <seealso cref="UnityEngine.InputSystem.InputAction.canceled" />
void OnSwitchSkyForm(InputAction.CallbackContext context);
void OnSwitchTianHunForm(InputAction.CallbackContext context);
/// <summary>
/// Method invoked when associated input action "SwitchEarthForm" is either <see cref="UnityEngine.InputSystem.InputAction.started" />, <see cref="UnityEngine.InputSystem.InputAction.performed" /> or <see cref="UnityEngine.InputSystem.InputAction.canceled" />.
/// Method invoked when associated input action "SwitchDiHunForm" is either <see cref="UnityEngine.InputSystem.InputAction.started" />, <see cref="UnityEngine.InputSystem.InputAction.performed" /> or <see cref="UnityEngine.InputSystem.InputAction.canceled" />.
/// </summary>
/// <seealso cref="UnityEngine.InputSystem.InputAction.started" />
/// <seealso cref="UnityEngine.InputSystem.InputAction.performed" />
/// <seealso cref="UnityEngine.InputSystem.InputAction.canceled" />
void OnSwitchEarthForm(InputAction.CallbackContext context);
void OnSwitchDiHunForm(InputAction.CallbackContext context);
/// <summary>
/// Method invoked when associated input action "SwitchDeathForm" is either <see cref="UnityEngine.InputSystem.InputAction.started" />, <see cref="UnityEngine.InputSystem.InputAction.performed" /> or <see cref="UnityEngine.InputSystem.InputAction.canceled" />.
/// Method invoked when associated input action "SwitchMingHunForm" is either <see cref="UnityEngine.InputSystem.InputAction.started" />, <see cref="UnityEngine.InputSystem.InputAction.performed" /> or <see cref="UnityEngine.InputSystem.InputAction.canceled" />.
/// </summary>
/// <seealso cref="UnityEngine.InputSystem.InputAction.started" />
/// <seealso cref="UnityEngine.InputSystem.InputAction.performed" />
/// <seealso cref="UnityEngine.InputSystem.InputAction.canceled" />
void OnSwitchDeathForm(InputAction.CallbackContext context);
void OnSwitchMingHunForm(InputAction.CallbackContext context);
/// <summary>
/// Method invoked when associated input action "SoulSkill" is either <see cref="UnityEngine.InputSystem.InputAction.started" />, <see cref="UnityEngine.InputSystem.InputAction.performed" /> or <see cref="UnityEngine.InputSystem.InputAction.canceled" />.
/// </summary>
@@ -2086,6 +2150,13 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable
/// <seealso cref="UnityEngine.InputSystem.InputAction.performed" />
/// <seealso cref="UnityEngine.InputSystem.InputAction.canceled" />
void OnInventory(InputAction.CallbackContext context);
/// <summary>
/// Method invoked when associated input action "QuickMap" is either <see cref="UnityEngine.InputSystem.InputAction.started" />, <see cref="UnityEngine.InputSystem.InputAction.performed" /> or <see cref="UnityEngine.InputSystem.InputAction.canceled" />.
/// </summary>
/// <seealso cref="UnityEngine.InputSystem.InputAction.started" />
/// <seealso cref="UnityEngine.InputSystem.InputAction.performed" />
/// <seealso cref="UnityEngine.InputSystem.InputAction.canceled" />
void OnQuickMap(InputAction.CallbackContext context);
}
/// <summary>
/// Interface to implement callback methods for all input action callbacks associated with input actions defined by "UI" which allows adding and removing callbacks.
@@ -2192,5 +2263,12 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable
/// <seealso cref="UnityEngine.InputSystem.InputAction.performed" />
/// <seealso cref="UnityEngine.InputSystem.InputAction.canceled" />
void OnInventoryTabPrev(InputAction.CallbackContext context);
/// <summary>
/// Method invoked when associated input action "QuickMap" is either <see cref="UnityEngine.InputSystem.InputAction.started" />, <see cref="UnityEngine.InputSystem.InputAction.performed" /> or <see cref="UnityEngine.InputSystem.InputAction.canceled" />.
/// </summary>
/// <seealso cref="UnityEngine.InputSystem.InputAction.started" />
/// <seealso cref="UnityEngine.InputSystem.InputAction.performed" />
/// <seealso cref="UnityEngine.InputSystem.InputAction.canceled" />
void OnQuickMap(InputAction.CallbackContext context);
}
}

View File

@@ -79,28 +79,28 @@
"initialStateCheck": false
},
{
"name": "SwitchSkyForm",
"name": "SwitchTianHunForm",
"type": "Button",
"id": "288ba219-3999-4951-95a5-7f59de67e9c2",
"expectedControlType": "Button",
"expectedControlType": "",
"processors": "",
"interactions": "",
"initialStateCheck": false
},
{
"name": "SwitchEarthForm",
"name": "SwitchDiHunForm",
"type": "Button",
"id": "1ebc4d85-1cd6-4730-abac-6020f74787e1",
"expectedControlType": "Button",
"expectedControlType": "",
"processors": "",
"interactions": "",
"initialStateCheck": false
},
{
"name": "SwitchDeathForm",
"name": "SwitchMingHunForm",
"type": "Button",
"id": "1d80c36d-a347-44ac-9498-f3bb262f5643",
"expectedControlType": "Button",
"expectedControlType": "",
"processors": "",
"interactions": "",
"initialStateCheck": false
@@ -167,6 +167,15 @@
"processors": "",
"interactions": "",
"initialStateCheck": false
},
{
"name": "QuickMap",
"type": "Button",
"id": "b7f46b82-62e8-43ad-955f-0a91cd9b3f57",
"expectedControlType": "",
"processors": "",
"interactions": "",
"initialStateCheck": false
}
],
"bindings": [
@@ -386,7 +395,7 @@
"interactions": "",
"processors": "",
"groups": "Keyboard&Mouse",
"action": "SwitchSkyForm",
"action": "SwitchTianHunForm",
"isComposite": false,
"isPartOfComposite": false
},
@@ -397,7 +406,7 @@
"interactions": "",
"processors": "",
"groups": "Keyboard&Mouse",
"action": "SwitchEarthForm",
"action": "SwitchDiHunForm",
"isComposite": false,
"isPartOfComposite": false
},
@@ -408,7 +417,7 @@
"interactions": "",
"processors": "",
"groups": "Keyboard&Mouse",
"action": "SwitchDeathForm",
"action": "SwitchMingHunForm",
"isComposite": false,
"isPartOfComposite": false
},
@@ -521,6 +530,17 @@
"action": "Inventory",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "6e531471-28cc-47a5-9550-0e7a32471eb3",
"path": "<Keyboard>/m",
"interactions": "",
"processors": "",
"groups": "",
"action": "QuickMap",
"isComposite": false,
"isPartOfComposite": false
}
]
},
@@ -653,6 +673,15 @@
"processors": "",
"interactions": "",
"initialStateCheck": false
},
{
"name": "QuickMap",
"type": "Button",
"id": "65742438-4d43-4c79-8499-5781ad34dcb0",
"expectedControlType": "",
"processors": "",
"interactions": "",
"initialStateCheck": false
}
],
"bindings": [
@@ -1172,6 +1201,17 @@
"action": "InventoryTabPrev",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "",
"id": "d1d954e4-fccd-49e9-ac07-b0c4a476fcf3",
"path": "<Keyboard>/m",
"interactions": "",
"processors": "",
"groups": "",
"action": "QuickMap",
"isComposite": false,
"isPartOfComposite": false
}
]
}