From f43e38880a7255d07cccfc313146c3f397fcf505 Mon Sep 17 00:00:00 2001
From: yyl <yyl>
Date: 星期三, 07 五月 2025 09:34:27 +0800
Subject: [PATCH] UI配置等

---
 Main/Config/ConfigBase.cs.meta                       |   11 
 Main/Manager/ManagerBase.cs                          |   13 
 Main/Character/Motion.meta                           |    8 
 Main/UI/Login.meta                                   |    8 
 Main/Place/PlaceUnit.cs                              |  516 ++++++++
 Main/UI/UIBase.cs                                    |  175 +-
 Main/Config/ConfigParse.cs.meta                      |   11 
 Main/UI/Login/LoginWin.cs                            |   62 +
 Main/Manager/IManager.cs                             |    7 
 Main/Manager/LoginManager.cs.meta                    |   11 
 Main/Character/Motion/MotionBase.cs                  |   58 +
 Main/Character/Motion/MotionBase.cs.meta             |   11 
 Main/UI/Main.meta                                    |    8 
 Main/Manager/IManager.cs.meta                        |   11 
 Main/Character/CharacterBase.cs                      |    9 
 Main/Config/ConfigBase.cs                            |  141 ++
 Main/Manager/GameSystemManager.meta                  |    8 
 Main/UI/Place/PlaceWin.cs.meta                       |   11 
 Main/Manager/GameSystemManager/PlaceManager.cs.meta  |   11 
 Main/UI/Place.meta                                   |    8 
 Main/Manager/ConfigManager.cs                        |   84 +
 Main/UI/Place/PlaceWin.cs                            |   62 +
 Main/Place/PlaceDrop.cs                              |  143 ++
 Main/Manager/ManagerBase.cs.meta                     |   11 
 Main/Place/PlaceDataStructs.cs.meta                  |   11 
 Main/Character.meta                                  |    8 
 Main/Manager.meta                                    |    8 
 Main/Battle.meta                                     |    8 
 Main/UI/Login/LoginWin.cs.meta                       |   11 
 Main/Place/PlaceUnit.cs.meta                         |   11 
 Main/UI/LoadingWin.cs                                |   73 +
 Main/UI/Main/MainWin.cs                              |  206 +++
 Main/UI/UIManager.cs                                 |   80 
 Main/UI/LoadingWin.cs.meta                           |   11 
 Main/Place/PlaceField.cs.meta                        |   11 
 Main/Manager/GameSystemManager/BattleManager.cs      |   14 
 Main/Place/PlaceDrop.cs.meta                         |   11 
 Main/Main.cs                                         |  103 +
 Main/UI/Main/MainWin.cs.meta                         |   11 
 Main/Character/CharacterBase.cs.meta                 |   11 
 Main/Place/PlaceField.cs                             |  406 +++++++
 Main/Config/ConfigParse.cs                           |  305 +++++
 Main/Manager/LoginManager.cs                         |   16 
 Main/Config/Configs.meta                             |    8 
 Main/Manager/StageManager.cs                         |  119 ++
 Main/Main.asmdef                                     |    7 
 Main/Manager/ConfigManager.cs.meta                   |   11 
 Main/Manager/GameSystemManager/BattleManager.cs.meta |   11 
 Utility/DontDestroyOnLoad.cs.meta                    |   11 
 Utility/DontDestroyOnLoad.cs                         |   11 
 Main/Manager/GameSystemManager.cs.meta               |   11 
 Main/Manager/GameSystemManager/PlaceManager.cs       |   21 
 Main/Manager/GameSystemManager/TeamManager.cs.meta   |   11 
 Main/Manager/GameSystemManager.cs                    |   33 
 Main/Manager/StageManager.cs.meta                    |   11 
 Main/Place.meta                                      |    8 
 Main/Manager/GameSystemManager/TeamManager.cs        |  400 ++++++
 Main/Place/PlaceDataStructs.cs                       |   83 +
 Main/Config.meta                                     |    8 
 59 files changed, 3,301 insertions(+), 176 deletions(-)

diff --git a/Main/Battle.meta b/Main/Battle.meta
new file mode 100644
index 0000000..14bf21e
--- /dev/null
+++ b/Main/Battle.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: f97380ec7fe308f4fb5bb6658c9b2604
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Character.meta b/Main/Character.meta
new file mode 100644
index 0000000..f91e1b0
--- /dev/null
+++ b/Main/Character.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 236e2b98d9a024546a3d5b0ee59c257e
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Character/CharacterBase.cs b/Main/Character/CharacterBase.cs
new file mode 100644
index 0000000..e86b197
--- /dev/null
+++ b/Main/Character/CharacterBase.cs
@@ -0,0 +1,9 @@
+
+
+public class CharacterBase
+{
+
+    
+
+
+}
\ No newline at end of file
diff --git a/Main/Character/CharacterBase.cs.meta b/Main/Character/CharacterBase.cs.meta
new file mode 100644
index 0000000..21f5255
--- /dev/null
+++ b/Main/Character/CharacterBase.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 446cfdee2e270e2459fa4dbb2c33b152
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Character/Motion.meta b/Main/Character/Motion.meta
new file mode 100644
index 0000000..8ab6d6e
--- /dev/null
+++ b/Main/Character/Motion.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 613ebae9f200e9d43b75a053fd050971
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Character/Motion/MotionBase.cs b/Main/Character/Motion/MotionBase.cs
new file mode 100644
index 0000000..bdf26d3
--- /dev/null
+++ b/Main/Character/Motion/MotionBase.cs
@@ -0,0 +1,58 @@
+using Spine.Unity;
+using Spine;
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+
+
+//  鍔ㄤ綔鎺у埗
+public class MotionBase
+{
+    protected SkeletonAnimation skeletonAnimation;
+
+    public virtual void Init(SkeletonAnimation _skeletonAnimation)
+    {
+        skeletonAnimation = _skeletonAnimation;
+    }
+
+    public virtual void Play(string _motionName, bool _isLoop = false)
+    {
+        skeletonAnimation.AnimationState.SetAnimation(0, _motionName, _isLoop);
+    }
+
+    public virtual void Pause()
+    {
+        skeletonAnimation.AnimationState.TimeScale = 0;
+    }
+
+    public virtual void Resume()
+    {
+        skeletonAnimation.AnimationState.TimeScale = 1;
+    }
+
+    public virtual void MixBlend(string _motionName, float _duration)
+    {
+        // 鑾峰彇褰撳墠杞ㄩ亾涓婄殑鍔ㄧ敾
+        TrackEntry currentTrack = skeletonAnimation.AnimationState.GetCurrent(0);
+        
+        if (currentTrack != null)
+        {
+            // 娣诲姞涓�涓柊鐨勫姩鐢诲埌杞ㄩ亾0锛屽苟璁剧疆娣峰悎鏃堕棿
+            TrackEntry newTrack = skeletonAnimation.AnimationState.SetAnimation(0, _motionName, true);
+            
+            // 璁剧疆娣峰悎鎸佺画鏃堕棿
+            newTrack.MixDuration = _duration;
+            
+            // 鍙�夛細璁剧疆娣峰悎绫诲瀷
+            // newTrack.MixBlend = MixBlend.Replace; // 榛樿鍊�
+            
+            // 鍙�夛細濡傛灉闇�瑕佸湪娣峰悎瀹屾垚鍚庢墽琛屾煇浜涙搷浣�
+            // newTrack.Complete += OnMixComplete;
+        }
+        else
+        {
+            // 濡傛灉褰撳墠娌℃湁鍔ㄧ敾鍦ㄦ挱鏀撅紝鐩存帴鎾斁鏂板姩鐢�
+            skeletonAnimation.AnimationState.SetAnimation(0, _motionName, true);
+        }
+    }
+}
\ No newline at end of file
diff --git a/Main/Character/Motion/MotionBase.cs.meta b/Main/Character/Motion/MotionBase.cs.meta
new file mode 100644
index 0000000..7979b1c
--- /dev/null
+++ b/Main/Character/Motion/MotionBase.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 7d0ffbc3831c9564481db79412785ff9
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Config.meta b/Main/Config.meta
new file mode 100644
index 0000000..ba72ecf
--- /dev/null
+++ b/Main/Config.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: da9ffef894f7c304c8f0de2f85657112
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Config/ConfigBase.cs b/Main/Config/ConfigBase.cs
new file mode 100644
index 0000000..3e371da
--- /dev/null
+++ b/Main/Config/ConfigBase.cs
@@ -0,0 +1,141 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+
+public class ConfigBase<U, T> where T : ConfigBase<U, T>, new()
+{
+    public static Dictionary<U, T> dic = new Dictionary<U, T>();
+
+    protected static bool isInit = false;
+
+    public static T Get(U id)
+    {
+        if (!isInit)
+        {
+            Debug.LogError("ConfigBase 娌℃湁鍒濆鍖�");
+            return null; // 鎴栬�呮姏鍑哄紓甯革紝瑙嗘儏鍐佃�屽畾
+        }
+
+        if (dic.ContainsKey(id))
+        {
+            return dic[id];
+        }
+
+        return null;
+    }
+
+    public List<T> GetValues()
+    {
+        if (!isInit)
+        {
+            Debug.LogError(typeof(T).Name + " 娌℃湁鍒濆鍖� GetValues");
+            return null; // 鎴栬�呮姏鍑哄紓甯革紝瑙嗘儏鍐佃�屽畾
+        }
+        List<T> result = new List<T>();
+        result.AddRange(dic.Values);
+        return result;
+    }
+
+    public static bool HasKey(U key)
+    {
+        if (!isInit)
+        {
+            Debug.LogError(typeof(T).Name + " 娌℃湁鍒濆鍖� HasKey");
+            return false; // 鎴栬�呮姏鍑哄紓甯革紝瑙嗘儏鍐佃�屽畾
+        }
+
+        return dic.ContainsKey(key);
+    }
+
+    public static void Init(string[] lines)
+    {
+        Dictionary<string, string> rawDatas = new Dictionary<string, string>();
+
+        for (int i = 3; i < lines.Length; i++)
+        {
+            string line = lines[i];
+            var index = line.IndexOf("\t");
+            if (index == -1)
+            {
+                continue;
+            }
+
+            string strKey = line.Substring(0, index);
+            T config = new T();
+            U key = config.LoadKey(strKey);
+            config.LoadConfig(line);
+            dic.Add(key, config);
+        }
+
+        isInit = true;
+    }
+
+    public virtual U LoadKey(string line)
+    {
+        return default(U);
+    }
+
+    public virtual void LoadConfig(string line)
+    {
+        
+    }
+    
+    protected int ParseInt(string str)
+    {
+        int result = 0;
+        int.TryParse(str, out result);
+        return result;
+    }
+
+    protected float ParseFloat(string str)
+    {
+        float result = 0f;
+        float.TryParse(str, out result);
+        return result;
+    }
+
+    protected string[] Split(string str, char split)
+    {
+        return str.Split(split);
+    }
+
+    protected List<string> ParseStrList(string str, char split)
+    {
+        List<string> result = new List<string>();
+        string[] strs = Split(str, split);
+        for (int i = 0; i < strs.Length; i++)
+        {
+            result.Add(strs[i]);
+        }
+
+        return result;
+    }
+
+    protected List<int> ParseIntList(string str, char split)
+    {
+        List<int> result = new List<int>();
+        string[] strs = Split(str, split);
+        for (int i = 0; i < strs.Length; i++)
+        {
+            result.Add(ParseInt(strs[i]));
+        }
+        return result;
+    }
+
+    protected U GetKey(string key)
+    {
+        if (typeof(U) == typeof(string))
+        {
+            return (U)(object)key;
+        }
+        else if (typeof(U) == typeof(int))
+        {
+            return (U)(object)ParseInt(key);
+        }
+        else
+        {
+            Debug.LogError("GetKey 绫诲瀷閿欒");
+            return default(U);
+        }
+    }
+}
\ No newline at end of file
diff --git a/Main/Config/ConfigBase.cs.meta b/Main/Config/ConfigBase.cs.meta
new file mode 100644
index 0000000..6e3b278
--- /dev/null
+++ b/Main/Config/ConfigBase.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: beeab167082007f42b3eedbb8a3c19e8
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Config/ConfigParse.cs b/Main/Config/ConfigParse.cs
new file mode 100644
index 0000000..4ad01b1
--- /dev/null
+++ b/Main/Config/ConfigParse.cs
@@ -0,0 +1,305 @@
+锘縰sing LitJson;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using UnityEngine;
+
+public class ConfigParse
+{
+    public enum SegStrType
+    {
+        Multiple,
+        KeyValue,
+    }
+
+    public static T? GetSegValue<T>(string msg, string key, SegStrType type) where T : struct
+    {
+        T? result = null;
+        switch (type)
+        {
+            case SegStrType.Multiple:
+                {
+                    uint index = 0;
+                    uint.TryParse(key, out index);
+                    result = (T)Convert.ChangeType(GetMultipleStr(msg, index), typeof(T));
+                }
+                break;
+            case SegStrType.KeyValue:
+                {
+                    result = (T)Convert.ChangeType(GetKeyValue(msg, key), typeof(T));
+                }
+                break;
+        }
+        return result;
+    }
+
+    public static string GetSegValue(string msg, string key, SegStrType type)
+    {
+        switch (type)
+        {
+            case SegStrType.Multiple:
+                {
+                    uint index = 0;
+                    uint.TryParse(key, out index);
+                    return GetMultipleStr(msg, index);
+                }
+            case SegStrType.KeyValue:
+                {
+                    return GetKeyValue(msg, key);
+                }
+        }
+        return string.Empty;
+    }
+
+    private static string GetMultipleStr(string msg, uint index)
+    {
+        string[] segs = GetMultipleStr(msg);
+        if (segs != null && index < segs.Length)
+        {
+            return segs[index];
+        }
+        return string.Empty;
+    }
+
+    public static T[] GetMultipleStr<T>(string msg) where T : struct
+    {
+        string[] segs = GetMultipleStr(msg);
+        if (segs != null && segs.Length > 0)
+        {
+            T[] array = new T[segs.Length];
+            for (int i = 0; i < segs.Length; i++)
+            {
+                array[i] = (T)Convert.ChangeType(segs[i], typeof(T));
+            }
+            return array;
+        }
+        return null;
+    }
+
+    public static string[] GetMultipleStr(string msg)
+    {
+        string[] segs = msg.Split('|');
+        if (segs.Length == 1 && segs[0].Equals(string.Empty)) return null;
+        return segs;
+    }
+
+    private static string GetKeyValue(string msg, string key)
+    {
+        string[] segs = GetMultipleStr(msg);
+        for (int i = 0; i < segs.Length; i++)
+        {
+            string[] pair = GetKeyValue(segs[i]);
+            if (pair.Length > 1)
+            {
+                if (!pair[0].Equals(key)) continue;
+                else return pair[1];
+            }
+            else continue;
+        }
+        return string.Empty;
+    }
+
+    private static string[] GetKeyValue(string msg)
+    {
+        return msg.Split('_');
+    }
+
+    public static T[] GetKeyValueKeys<T>(string msg) where T : struct
+    {
+        string[] segs = GetMultipleStr(msg);
+        if (segs != null && segs.Length > 0)
+        {
+            T[] array = new T[segs.Length];
+            for (int i = 0; i < segs.Length; i++)
+            {
+                string[] pair = GetKeyValue(segs[i]);
+                if (pair.Length > 1)
+                {
+                    array[i] = (T)Convert.ChangeType(pair[0], typeof(T));
+                }
+            }
+            return array;
+        }
+        return null;
+    }
+
+    public static T[] GetKeyValueValues<T>(string msg) where T : struct
+    {
+        string[] segs = GetMultipleStr(msg);
+        if (segs != null && segs.Length > 0)
+        {
+            T[] array = new T[segs.Length];
+            for (int i = 0; i < segs.Length; i++)
+            {
+                string[] pair = GetKeyValue(segs[i]);
+                if (pair.Length > 1)
+                {
+                    array[i] = (T)Convert.ChangeType(pair[1], typeof(T));
+                }
+            }
+            return array;
+        }
+        return null;
+    }
+
+    public static Dictionary<T, P> GetDic<T, P>(string msg)
+    {
+        Dictionary<T, P> dic = null;
+        string[] segs = GetMultipleStr(msg);
+        if (segs != null && segs.Length > 0)
+        {
+            dic = new Dictionary<T, P>();
+            for (int i = 0; i < segs.Length; i++)
+            {
+                string[] pair = GetKeyValue(segs[i]);
+                if (pair.Length > 1)
+                {
+                    dic.Add((T)Convert.ChangeType(pair[0], typeof(T)), (P)Convert.ChangeType(pair[1], typeof(P)));
+                }
+            }
+        }
+        return dic;
+    }
+
+    public static string ServerStringTrim(string str)
+    {
+        if (!string.IsNullOrEmpty(str))
+        {
+            str = str.Replace("\0", "");
+            str = str.Replace("\x00", "");
+            return str;
+        }
+        else
+        {
+            return string.Empty;
+        }
+    }
+
+    //{'17':['63','6','27'],'65':['800'],'55':['139'],'19':['1000','2600','130']}
+    public static Regex userDataRegex = new Regex(@"'([0-9]+)':\[(.*?)\]", RegexOptions.Singleline);
+    public static Dictionary<int, List<int>> Analysis(string val)//姝e垯琛ㄨ揪寮忕殑瀛楃涓插垎鍓�
+    {
+        string s = ServerStringTrim(val);
+        if (string.IsNullOrEmpty(s))
+        {
+            return null;
+        }
+
+        s = s.Replace(" ", string.Empty);
+        if (!userDataRegex.IsMatch(s))
+        {
+            return null;
+        }
+        else
+        {
+            Dictionary<int, List<int>> dics = new Dictionary<int, List<int>>();
+            foreach (Match match in userDataRegex.Matches(s))
+            {
+                int id = int.Parse(match.Groups[1].Value);
+                string str = match.Groups[2].Value;
+                string[] vals = str.Split(',');
+                List<int> list = new List<int>();
+                for (int i = 0; i < vals.Length; i++)
+                {
+                    int intval = int.Parse(vals[i].Replace('\'', ' '));
+                    list.Add(intval);
+                }
+                if (!dics.ContainsKey(id))
+                {
+                    dics.Add(id, list);
+                }
+            }
+            return dics;
+        }
+    }
+
+    public static Dictionary<int, List<int>> ParseJsonDict(string jsonStr)
+    {
+        if (jsonStr == "{}" || string.IsNullOrEmpty(jsonStr))
+        {
+            return new Dictionary<int, List<int>>();
+        }
+        var dict = JsonMapper.ToObject<Dictionary<string, List<int>>>(jsonStr);
+        Dictionary<int, List<int>> result = new Dictionary<int, List<int>>();
+
+        foreach (var item in dict)
+        {
+            result[int.Parse(item.Key)] = item.Value;
+        }
+
+        return result;
+    }
+
+    public static Dictionary<int, int> ParseIntDict(string jsonStr)
+    {
+        if (jsonStr == "{}" || string.IsNullOrEmpty(jsonStr))
+        {
+            return new Dictionary<int, int>();
+        }
+        var dict = JsonMapper.ToObject<Dictionary<string, int>>(jsonStr);
+        Dictionary<int, int> result = new Dictionary<int, int>();
+
+        foreach (var item in dict)
+        {
+            result[int.Parse(item.Key)] = item.Value;
+        }
+
+        return result;
+    }
+
+    public static Dictionary<int, int[]> ParseIntArrayDict(string jsonStr)
+    {
+        if (jsonStr == "{}" || string.IsNullOrEmpty(jsonStr))
+        {
+            return new Dictionary<int, int[]>();
+        }
+        var dict = JsonMapper.ToObject<Dictionary<string, int[]>>(jsonStr);
+        Dictionary<int, int[]> result = new Dictionary<int, int[]>();
+
+        foreach (var item in dict)
+        {
+            result[int.Parse(item.Key)] = item.Value;
+        }
+
+        return result;
+    }
+
+    public static Dictionary<int, int[][]> ParseIntArray2Dict(string jsonStr)
+    {
+        if (jsonStr == "{}" || string.IsNullOrEmpty(jsonStr))
+        {
+            return new Dictionary<int, int[][]>();
+        }
+        var dict = JsonMapper.ToObject<Dictionary<string, int[][]>>(jsonStr);
+        Dictionary<int, int[][]> result = new Dictionary<int, int[][]>();
+
+        foreach (var item in dict)
+        {
+            result[int.Parse(item.Key)] = item.Value;
+        }
+
+        return result;
+    }
+
+
+    //涓囧垎鐜囪浆涓烘瘡涓猧d瀵瑰簲鐨勬鐜� [[涓囧垎姒傜巼锛宨d1],[涓囧垎姒傜巼锛宨d2]]
+    public static Dictionary<int, int> GetRateDict(int[][] rateArray)
+    {
+        Dictionary<int, int> dic = new Dictionary<int, int>();
+        //姒傜巼涓� 鍑忓幓涓婁竴涓鐜囩殑鍊煎嵆涓哄綋鍓岻D姒傜巼
+        for (int i = 0;i< rateArray.Length; i++)
+        {
+            if (i > 0)
+            {
+                dic[rateArray[i][1]] = rateArray[i][0] - rateArray[i - 1][0];
+            }
+            else
+            {
+                dic[rateArray[i][1]] = rateArray[i][0];
+            }
+        }
+
+        return dic;
+    }
+}
diff --git a/Main/Config/ConfigParse.cs.meta b/Main/Config/ConfigParse.cs.meta
new file mode 100644
index 0000000..17a769b
--- /dev/null
+++ b/Main/Config/ConfigParse.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 6f9144568a1b6674da727f6a1a88aed9
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Config/Configs.meta b/Main/Config/Configs.meta
new file mode 100644
index 0000000..4e5884e
--- /dev/null
+++ b/Main/Config/Configs.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 776d1c99148d30f4799a606e5cd0f5de
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Main.asmdef b/Main/Main.asmdef
index bc3c97a..a5d805b 100644
--- a/Main/Main.asmdef
+++ b/Main/Main.asmdef
@@ -4,7 +4,12 @@
     "references": [
         "GUID:3ffa07c58a98b0445a7a34376b165fd1",
         "GUID:4129704b5a1a13841ba16f230bf24a57",
-        "GUID:f51ebe6a0ceec4240a699833d6309b23"
+        "GUID:f51ebe6a0ceec4240a699833d6309b23",
+        "GUID:e34a5702dd353724aa315fb8011f08c3",
+        "GUID:4d1926c9df5b052469a1c63448b7609a",
+        "GUID:68765d262e2128e4ab49c983f3411946",
+        "GUID:173464ddf4cdb6640a4dfa8a9281ad69",
+        "GUID:72d1fea872bd7a449bf3818f2b0a6708"
     ],
     "includePlatforms": [],
     "excludePlatforms": [],
diff --git a/Main/Main.cs b/Main/Main.cs
index 981ab79..15d0d7e 100644
--- a/Main/Main.cs
+++ b/Main/Main.cs
@@ -4,49 +4,81 @@
 using UnityEngine;
 using Cysharp.Threading;
 using Cysharp.Threading.Tasks;
+using System.Threading.Tasks;
 
 /// <summary>
 /// Main绫伙紝浣滀负鐑洿鏂扮▼搴忛泦鐨勫叆鍙g偣
 /// </summary>
 public class Main
 {
+    public static List<IGameSystemManager> managers = new List<IGameSystemManager>();
+
     /// <summary>
     /// 鍒濆鍖栧嚱鏁帮紝鐢盠aunch绫昏皟鐢�
     /// </summary>
-    public static void Init()
+    public static async UniTask Init()
     {
         Debug.Log("Main.Init() 琚皟鐢�");
-        // 1. 鍒濆鍖栨父鎴忕郴缁�
-        InitializeGameSystems();
-        
-        // 2. 鍔犺浇閰嶇疆
-        LoadConfigurations();
-        
-        // 3. 鎵撳紑鐧诲綍鐣岄潰
-        OpenLoginUI();
+        await InitSystems();
+
+        Debug.Log("鍏抽棴鍔犺浇鐣岄潰");
+        LaunchLoadingWin.Instance.CloseWindow();
+
+        SwitchToLoginScene();
     }
-    
-    
+
     /// <summary>
     /// 鍒濆鍖栨父鎴忕郴缁�
     /// </summary>
-    private static void InitializeGameSystems()
+    private static async UniTask InitSystems()
     {
-        Debug.Log("鍒濆鍖栨父鎴忕郴缁�");
-        
-        // 杩欓噷鍙互鍒濆鍖栧悇绉嶆父鎴忕郴缁燂紝濡傝祫婧愮鐞嗐�乁I绠$悊銆侀煶棰戠鐞嗙瓑
-        
+        // 杩欓噷鍙互鍒濆鍖栧ぇ鍨嬬郴缁� 璐┛鏁翠釜娓告垙鐨勭郴缁�
+        await ResManager.Instance.Init();
+        UIManager.Instance.Init();
+        StageManager.Instance.Init();
+        LoginManager.Instance.Init();
+
     }
-    
-    /// <summary>
-    /// 鍔犺浇閰嶇疆
-    /// </summary>
-    private static void LoadConfigurations()
+
+    private static void SwitchToLoginScene()
     {
-        Debug.Log("鍔犺浇娓告垙閰嶇疆");
-        
-        // 杩欓噷鍙互鍔犺浇娓告垙閰嶇疆锛屽娓告垙鍙傛暟銆佽〃鏍兼暟鎹瓑
-        
+        // Debug.Log("鎵撳紑鐧诲綍鐣岄潰");
+        // UIManager.Instance.OpenWindow<LoginWin>();
+        Debug.Log("鍒囨崲鍒扮櫥褰曞満鏅�");
+        ConfigManager.Instance.Init();
+        StageManager.Instance.ToLoginScene();
+    }
+
+    public static void OnEnterGameScene()
+    {
+        // 鍒濆鍖栨父鎴忓満鏅�
+        Debug.Log("鍒濆鍖栨父鎴忓満鏅�");
+
+        // 鍒濆鍖栨父鎴忕郴缁�
+        managers.Add(PlaceManager.Instance);
+        managers.Add(BattleManager.Instance);
+        managers.Add(TeamManager.Instance);
+
+        foreach (var manager in managers)
+        {
+            manager.Init();
+        }
+
+        foreach (var manager in managers)
+        {
+            manager.RequestNessaryData();
+        }
+
+    }
+
+    public static void OnSwitchToLoginScene()
+    {
+        foreach (var manager in managers)
+        {
+            manager.Release();
+        }
+
+        managers.Clear();
     }
     
     /// <summary>
@@ -54,27 +86,8 @@
     /// </summary>
     private static void OpenLoginUI()
     {
-        Debug.Log("鍏抽棴鍔犺浇鐣岄潰");
 
-        LaunchLoadingWin.Instance.CloseWindow();
 
-        Debug.Log("鎵撳紑鐧诲綍鐣岄潰");
-        
-        // 鑾峰彇Launch涓殑IsUseSDK鏍囧織
-        bool isUseSDK = Launch.Instance.IsUseSDK;
-        
-        // 鏍规嵁IsUseSDK鏍囧織鏄剧ず涓嶅悓鐨勭櫥褰曠晫闈�
-        if (isUseSDK)
-        {
-            Debug.Log("鏄剧ずSDK鐧诲綍鐣岄潰");
-            // 鍦ㄨ繖閲屽疄鐜癝DK鐧诲綍鐣岄潰鐨勬樉绀洪�昏緫
-            // 渚嬪锛歎IManager.Instance.OpenUI("SDKLoginUI");
-        }
-        else
-        {
-            Debug.Log("鏄剧ず鏅�氱櫥褰曠晫闈�");
-            // 鍦ㄨ繖閲屽疄鐜版櫘閫氱櫥褰曠晫闈㈢殑鏄剧ず閫昏緫
-            // 渚嬪锛歎IManager.Instance.OpenUI("NormalLoginUI");
-        }
+
     }
 }
\ No newline at end of file
diff --git a/Main/Manager.meta b/Main/Manager.meta
new file mode 100644
index 0000000..b55776f
--- /dev/null
+++ b/Main/Manager.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: d17f7001c7a25da4b8f7c0051a479e37
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Manager/ConfigManager.cs b/Main/Manager/ConfigManager.cs
new file mode 100644
index 0000000..4af4662
--- /dev/null
+++ b/Main/Manager/ConfigManager.cs
@@ -0,0 +1,84 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+using Cysharp.Threading.Tasks;
+using System.Reflection;
+
+
+public class ConfigManager : ManagerBase<ConfigManager>
+{
+    public bool isLoadFinished
+    {
+        get;
+        private set;
+    }
+
+    public virtual async UniTask InitConfigs()
+    {
+        // 鍔犺浇閰嶇疆鏂囦欢
+        await LoadConfigs();
+    }
+
+    protected async UniTask LoadConfigs()
+    {
+        isLoadFinished = false;
+
+        // 鍔犺浇閰嶇疆鏂囦欢
+
+        // 鍔犺浇瀹屾垚鍚庤缃甶sLoadFinished涓簍rue
+        isLoadFinished = true;
+    }
+
+
+
+
+
+    private async UniTask LoadConfig<T>() where T : class
+    {
+        string configName = typeof(T).Name;
+
+        TextAsset textAsset = await ResManager.Instance.LoadAsset<TextAsset>("Config", configName);
+        if (textAsset != null)
+        {
+            string[] lines = textAsset.text.Split('\n');
+            var methodInfo = typeof(T).GetMethod("Init", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
+            if (methodInfo != null)
+            {
+                methodInfo.Invoke(null, new object[] { lines });
+                // 璁剧疆鍒濆鍖栨爣蹇�
+                var isInitField = typeof(T).GetField("isInit", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
+                if (isInitField != null)
+                {
+                    isInitField.SetValue(null, true);
+                }
+                Debug.Log($"鍔犺浇閰嶇疆: {typeof(T).Name} 鎴愬姛");
+            }
+            else
+            {
+                Debug.LogError($"閰嶇疆绫� {typeof(T).Name} 娌℃湁闈欐�両nit鏂规硶");
+            }
+        }
+        else
+        {
+            Debug.LogError($"鎵句笉鍒伴厤缃枃浠�: {configName}");
+        }
+    }
+
+    private void ClearConfigDictionary<T>() where T : class
+    {
+        // 閲嶇疆 T 鍒濆鍖栫姸鎬�
+        var isInitField = typeof(T).GetField("isInit", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
+        if (isInitField != null)
+        {
+            isInitField.SetValue(null, false);
+        }
+    }
+
+    public override void Release()
+    {
+    }
+
+
+
+
+}
\ No newline at end of file
diff --git a/Main/Manager/ConfigManager.cs.meta b/Main/Manager/ConfigManager.cs.meta
new file mode 100644
index 0000000..38522f1
--- /dev/null
+++ b/Main/Manager/ConfigManager.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 899d505772a98b44ba61e2e0d0a00072
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Manager/GameSystemManager.cs b/Main/Manager/GameSystemManager.cs
new file mode 100644
index 0000000..fc2bc39
--- /dev/null
+++ b/Main/Manager/GameSystemManager.cs
@@ -0,0 +1,33 @@
+// 娓告垙绯荤粺鐨勭鐞嗗熀绫�
+
+// 娣诲姞涓�涓潪娉涘瀷鐨勫熀绫绘垨鎺ュ彛
+public interface IGameSystemManager
+{
+    public void Init();
+    public void Release();
+    public void RequestNessaryData();
+    public bool IsNessaryDataReady();
+}
+
+// 璁╂硾鍨嬬被缁ф壙鑷潪娉涘瀷鍩虹被
+public class GameSystemManager<T> : Singleton<T>, IGameSystemManager where T : GameSystemManager<T>, new()
+{
+    public virtual void Init()
+    {
+    }
+
+    public virtual void Release()
+    {
+
+    }
+
+    public virtual void RequestNessaryData()
+    {
+
+    }
+
+    public virtual bool IsNessaryDataReady()
+    {
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/Main/Manager/GameSystemManager.cs.meta b/Main/Manager/GameSystemManager.cs.meta
new file mode 100644
index 0000000..0c35ad1
--- /dev/null
+++ b/Main/Manager/GameSystemManager.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 05ef44209a69865458086694ce7d6f67
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Manager/GameSystemManager.meta b/Main/Manager/GameSystemManager.meta
new file mode 100644
index 0000000..c3d55d3
--- /dev/null
+++ b/Main/Manager/GameSystemManager.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 7b0931f43ab92084b8a1e5faa7fbfda2
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Manager/GameSystemManager/BattleManager.cs b/Main/Manager/GameSystemManager/BattleManager.cs
new file mode 100644
index 0000000..a52f3c3
--- /dev/null
+++ b/Main/Manager/GameSystemManager/BattleManager.cs
@@ -0,0 +1,14 @@
+public class BattleManager : GameSystemManager<BattleManager>
+{
+    public override void Init()
+    {
+        base.Init();
+        
+    }
+
+    public override void Release()
+    {
+        base.Release();
+    }
+
+}
\ No newline at end of file
diff --git a/Main/Manager/GameSystemManager/BattleManager.cs.meta b/Main/Manager/GameSystemManager/BattleManager.cs.meta
new file mode 100644
index 0000000..9cbbbb1
--- /dev/null
+++ b/Main/Manager/GameSystemManager/BattleManager.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e2eea1200b9fe6644a6907b4e042f222
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Manager/GameSystemManager/PlaceManager.cs b/Main/Manager/GameSystemManager/PlaceManager.cs
new file mode 100644
index 0000000..2573e84
--- /dev/null
+++ b/Main/Manager/GameSystemManager/PlaceManager.cs
@@ -0,0 +1,21 @@
+public class PlaceManager : GameSystemManager<PlaceManager>
+{
+    public PlaceField placeField;
+
+    public override void Init()
+    {
+        base.Init();
+        
+    }
+
+    public override void Release()
+    {
+        base.Release();
+    }
+
+    //  褰撻槦浼嶈窡绔犺妭淇℃伅鏁版嵁閮芥湁涔嬪悗灏卞彲浠ュ垱寤哄満鏅簡
+    public void CreatePlaceField()
+    {   
+
+    }
+}
\ No newline at end of file
diff --git a/Main/Manager/GameSystemManager/PlaceManager.cs.meta b/Main/Manager/GameSystemManager/PlaceManager.cs.meta
new file mode 100644
index 0000000..6c82cce
--- /dev/null
+++ b/Main/Manager/GameSystemManager/PlaceManager.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: dc73049956fa1a241a3aeac4d7fdd7af
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Manager/GameSystemManager/TeamManager.cs b/Main/Manager/GameSystemManager/TeamManager.cs
new file mode 100644
index 0000000..128ccf9
--- /dev/null
+++ b/Main/Manager/GameSystemManager/TeamManager.cs
@@ -0,0 +1,400 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+
+/// <summary>
+/// 闃靛瀷绫诲瀷
+/// </summary>
+public enum FormationType
+{
+    None = 0,
+    Type1 = 1,
+    Type2 = 2,
+    Type3 = 3,
+    Type4 = 4,
+    Type5 = 5
+}
+
+/// <summary>
+/// 鍗$墝淇℃伅
+/// </summary>
+[Serializable]
+public class CardInfo
+{
+    public int cardId;         // 鍗$墝ID
+    public int level;          // 鍗$墝绛夌骇
+    public int star;           // 鍗$墝鏄熺骇
+    public int quality;        // 鍗$墝鍝佽川
+    
+    // 鍏朵粬鍗$墝灞炴��...
+    
+    public CardInfo()
+    {
+        cardId = 0;
+        level = 1;
+        star = 1;
+        quality = 1;
+    }
+    
+    public CardInfo(int _cardId, int _level = 1, int _star = 1, int _quality = 1)
+    {
+        cardId = _cardId;
+        level = _level;
+        star = _star;
+        quality = _quality;
+    }
+}
+
+/// <summary>
+/// 闃熶紞鍗$墝淇℃伅
+/// </summary>
+[Serializable]
+public class SlotInfo
+{
+    public CardInfo cardInfo;      // 鍗$墝淇℃伅
+    public int teamIndex;      // 鍦ㄩ槦浼嶄腑鐨勭储寮曚綅缃�
+    
+    public SlotInfo()
+    {
+        cardInfo = new CardInfo();
+        teamIndex = -1;
+    }
+    
+    public SlotInfo(CardInfo _card, int _teamIndex)
+    {
+        cardInfo = _card;
+        teamIndex = _teamIndex;
+    }
+
+    public bool IsEmptySlot()
+    {
+        return cardInfo == null || cardInfo.cardId == 0;
+    }
+}
+
+/// <summary>
+/// 闃熶紞淇℃伅
+/// </summary>
+[Serializable]
+public class TeamInfo
+{
+    public int teamId;                     // 闃熶紞ID
+    public FormationType formation;        // 闃靛瀷绫诲瀷
+    public List<SlotInfo> teamCards;       // 闃熶紞鍗$墝鍒楄〃
+    
+    public TeamInfo()
+    {
+        teamId = 0;
+        formation = FormationType.Type1;
+        teamCards = new List<SlotInfo>();
+    }
+    
+    public TeamInfo(int _teamId, string _teamName, FormationType _formation)
+    {
+        teamId = _teamId;
+        formation = _formation;
+        teamCards = new List<SlotInfo>();
+    }
+    
+    /// <summary>
+    /// 娣诲姞鍗$墝鍒伴槦浼�
+    /// </summary>
+    public bool AddCard(CardInfo _card, int _teamIndex, bool _isLeader = false)
+    {
+        // 妫�鏌ヤ綅缃槸鍚﹀凡琚崰鐢�
+        foreach (var teamCard in teamCards)
+        {
+            if (teamCard.teamIndex == _teamIndex)
+            {
+                Debug.LogWarning($"闃熶紞浣嶇疆 {_teamIndex} 宸茶鍗犵敤");
+                return false;
+            }
+        }
+        
+        SlotInfo newTeamCard = new SlotInfo(_card, _teamIndex);
+        teamCards.Add(newTeamCard);
+        return true;
+    }
+    
+    /// <summary>
+    /// 绉婚櫎闃熶紞涓殑鍗$墝
+    /// </summary>
+    public bool RemoveCard(int _teamIndex)
+    {
+        for (int i = 0; i < teamCards.Count; i++)
+        {
+            if (teamCards[i].teamIndex == _teamIndex)
+            {
+                teamCards.RemoveAt(i);
+                return true;
+            }
+        }
+        
+        Debug.LogWarning($"鏈壘鍒颁綅缃� {_teamIndex} 鐨勫崱鐗�");
+        return false;
+    }
+    
+}
+
+/// <summary>
+/// 闃熶紞绠$悊鍣�
+/// </summary>
+public class TeamManager : GameSystemManager<TeamManager>
+{
+    // 鎵�鏈夐槦浼嶄俊鎭�
+    private List<TeamInfo> teamInfos = new List<TeamInfo>();
+    
+    // 褰撳墠閫変腑鐨勯槦浼嶇储寮�
+    private int currentTeamIndex = 0;
+    
+    // 鏈�澶ч槦浼嶆暟閲�
+    private const int MAX_TEAM_COUNT = 5;
+    
+    // 姣忎釜闃熶紞鐨勬渶澶у崱鐗屾暟閲�
+    private const int MAX_CARD_PER_TEAM = 6;
+    
+    public override void Init()
+    {
+        base.Init();
+        Debug.Log("TeamManager 鍒濆鍖�");
+        
+        // 鍒濆鍖栭粯璁ら槦浼�
+        if (teamInfos.Count == 0)
+        {
+            CreateDefaultTeam();
+        }
+    }
+    
+    public override void Release()
+    {
+        base.Release();
+        Debug.Log("TeamManager 閲婃斁");
+        
+        // 娓呯悊鏁版嵁
+        teamInfos.Clear();
+    }
+    
+    /// <summary>
+    /// 鍒涘缓榛樿闃熶紞
+    /// </summary>
+    private void CreateDefaultTeam()
+    {
+        TeamInfo defaultTeam = new TeamInfo(1, "闃熶紞1", FormationType.Type1);
+        teamInfos.Add(defaultTeam);
+    }
+    
+    /// <summary>
+    /// 鑾峰彇鎵�鏈夐槦浼嶄俊鎭�
+    /// </summary>
+    public List<TeamInfo> GetAllTeams()
+    {
+        return teamInfos;
+    }
+    
+    /// <summary>
+    /// 鑾峰彇鎸囧畾ID鐨勯槦浼�
+    /// </summary>
+    public TeamInfo GetTeam(int _teamId)
+    {
+        return teamInfos.Find(team => team.teamId == _teamId);
+    }
+    
+    /// <summary>
+    /// 鑾峰彇褰撳墠閫変腑鐨勯槦浼�
+    /// </summary>
+    public TeamInfo GetCurrentTeam()
+    {
+        if (currentTeamIndex >= 0 && currentTeamIndex < teamInfos.Count)
+        {
+            return teamInfos[currentTeamIndex];
+        }
+        return null;
+    }
+    
+    /// <summary>
+    /// 璁剧疆褰撳墠閫変腑鐨勯槦浼�
+    /// </summary>
+    public bool SetCurrentTeam(int _teamId)
+    {
+        for (int i = 0; i < teamInfos.Count; i++)
+        {
+            if (teamInfos[i].teamId == _teamId)
+            {
+                currentTeamIndex = i;
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    /// <summary>
+    /// 鍒涘缓鏂伴槦浼�
+    /// </summary>
+    public TeamInfo CreateTeam(string _teamName, FormationType _formation)
+    {
+        if (teamInfos.Count >= MAX_TEAM_COUNT)
+        {
+            Debug.LogWarning("宸茶揪鍒版渶澶ч槦浼嶆暟閲忛檺鍒�");
+            return null;
+        }
+        
+        // 鐢熸垚鏂扮殑闃熶紞ID
+        int newTeamId = 1;
+        if (teamInfos.Count > 0)
+        {
+            newTeamId = teamInfos[teamInfos.Count - 1].teamId + 1;
+        }
+        
+        TeamInfo newTeam = new TeamInfo(newTeamId, _teamName, _formation);
+        teamInfos.Add(newTeam);
+        
+        return newTeam;
+    }
+    
+    /// <summary>
+    /// 鍒犻櫎闃熶紞
+    /// </summary>
+    public bool DeleteTeam(int _teamId)
+    {
+        if (teamInfos.Count <= 1)
+        {
+            Debug.LogWarning("鑷冲皯淇濈暀涓�涓槦浼�");
+            return false;
+        }
+        
+        for (int i = 0; i < teamInfos.Count; i++)
+        {
+            if (teamInfos[i].teamId == _teamId)
+            {
+                teamInfos.RemoveAt(i);
+                
+                // 濡傛灉鍒犻櫎鐨勬槸褰撳墠閫変腑鐨勯槦浼嶏紝鍒欓噸鏂拌缃綋鍓嶉槦浼�
+                if (currentTeamIndex >= teamInfos.Count)
+                {
+                    currentTeamIndex = teamInfos.Count - 1;
+                }
+                
+                return true;
+            }
+        }
+        
+        return false;
+    }
+    
+    /// <summary>
+    /// 淇敼闃熶紞闃靛瀷
+    /// </summary>
+    public bool ChangeFormation(int _teamId, FormationType _newFormation)
+    {
+        TeamInfo team = GetTeam(_teamId);
+        if (team != null)
+        {
+            team.formation = _newFormation;
+            return true;
+        }
+        return false;
+    }
+    
+    /// <summary>
+    /// 鍚戦槦浼嶆坊鍔犲崱鐗�
+    /// </summary>
+    public bool AddCardToTeam(int _teamId, CardInfo _card, int _teamIndex, bool _isLeader = false)
+    {
+        TeamInfo team = GetTeam(_teamId);
+        if (team == null)
+        {
+            Debug.LogWarning($"鏈壘鍒癐D涓� {_teamId} 鐨勯槦浼�");
+            return false;
+        }
+        
+        if (team.teamCards.Count >= MAX_CARD_PER_TEAM)
+        {
+            Debug.LogWarning("闃熶紞鍗$墝宸茶揪鍒版渶澶ф暟閲�");
+            return false;
+        }
+        
+        return team.AddCard(_card, _teamIndex, _isLeader);
+    }
+    
+    /// <summary>
+    /// 浠庨槦浼嶇Щ闄ゅ崱鐗�
+    /// </summary>
+    public bool RemoveCardFromTeam(int _teamId, int _teamIndex)
+    {
+        TeamInfo team = GetTeam(_teamId);
+        if (team == null)
+        {
+            Debug.LogWarning($"鏈壘鍒癐D涓� {_teamId} 鐨勯槦浼�");
+            return false;
+        }
+        
+        return team.RemoveCard(_teamIndex);
+    }
+    
+    /// <summary>
+    /// 浜ゆ崲闃熶紞涓袱寮犲崱鐗岀殑浣嶇疆
+    /// </summary>
+    public bool SwapTeamCards(int _teamId, int _fromIndex, int _toIndex)
+    {
+        TeamInfo team = GetTeam(_teamId);
+        if (team == null)
+        {
+            Debug.LogWarning($"鏈壘鍒癐D涓� {_teamId} 鐨勯槦浼�");
+            return false;
+        }
+        
+        SlotInfo fromCard = null;
+        SlotInfo toCard = null;
+        
+        foreach (var card in team.teamCards)
+        {
+            if (card.teamIndex == _fromIndex)
+            {
+                fromCard = card;
+            }
+            else if (card.teamIndex == _toIndex)
+            {
+                toCard = card;
+            }
+        }
+        
+        if (fromCard == null)
+        {
+            Debug.LogWarning($"鏈壘鍒颁綅缃� {_fromIndex} 鐨勫崱鐗�");
+            return false;
+        }
+        
+        if (toCard == null)
+        {
+            // 濡傛灉鐩爣浣嶇疆娌℃湁鍗$墝锛岀洿鎺ョЩ鍔�
+            fromCard.teamIndex = _toIndex;
+        }
+        else
+        {
+            // 浜ゆ崲涓ゅ紶鍗$墝鐨勪綅缃�
+            fromCard.teamIndex = _toIndex;
+            toCard.teamIndex = _fromIndex;
+        }
+        
+        return true;
+    }
+    
+    /// <summary>
+    /// 淇濆瓨闃熶紞鏁版嵁
+    /// </summary>
+    public void SaveTeamData()
+    {
+        // 瀹炵幇闃熶紞鏁版嵁鐨勪繚瀛橀�昏緫
+        // 鍙互浣跨敤 PlayerPrefs銆丣SON 搴忓垪鍖栨垨鍏朵粬鏂瑰紡
+        Debug.Log("淇濆瓨闃熶紞鏁版嵁");
+    }
+    
+    /// <summary>
+    /// 鍔犺浇闃熶紞鏁版嵁
+    /// </summary>
+    public void LoadTeamData()
+    {
+        // 瀹炵幇闃熶紞鏁版嵁鐨勫姞杞介�昏緫
+        Debug.Log("鍔犺浇闃熶紞鏁版嵁");
+    }
+}
\ No newline at end of file
diff --git a/Main/Manager/GameSystemManager/TeamManager.cs.meta b/Main/Manager/GameSystemManager/TeamManager.cs.meta
new file mode 100644
index 0000000..739b68c
--- /dev/null
+++ b/Main/Manager/GameSystemManager/TeamManager.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8ac01de78a793cf4fb759dddc21c0bbe
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Manager/IManager.cs b/Main/Manager/IManager.cs
new file mode 100644
index 0000000..b7fef68
--- /dev/null
+++ b/Main/Manager/IManager.cs
@@ -0,0 +1,7 @@
+
+
+public interface IManager
+{
+    void Init();
+    void Release();
+}
diff --git a/Main/Manager/IManager.cs.meta b/Main/Manager/IManager.cs.meta
new file mode 100644
index 0000000..c921773
--- /dev/null
+++ b/Main/Manager/IManager.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 15be84dd6a98de14cb553ac421b17fb9
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Manager/LoginManager.cs b/Main/Manager/LoginManager.cs
new file mode 100644
index 0000000..176e289
--- /dev/null
+++ b/Main/Manager/LoginManager.cs
@@ -0,0 +1,16 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+public class LoginManager : ManagerBase<LoginManager>
+{
+    public override void Init()
+    {
+
+    }
+
+    public override void Release()
+    {
+        
+    }   
+}
diff --git a/Main/Manager/LoginManager.cs.meta b/Main/Manager/LoginManager.cs.meta
new file mode 100644
index 0000000..660e708
--- /dev/null
+++ b/Main/Manager/LoginManager.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 344e28aa3edcfbd4f863a019c2cbaaac
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Manager/ManagerBase.cs b/Main/Manager/ManagerBase.cs
new file mode 100644
index 0000000..b28427b
--- /dev/null
+++ b/Main/Manager/ManagerBase.cs
@@ -0,0 +1,13 @@
+
+public class ManagerBase<T> : Singleton<T>, IManager where T : ManagerBase<T>, new()
+{
+    public virtual void Init()
+    {
+
+    }
+
+    public virtual void Release()
+    {
+
+    }
+}
\ No newline at end of file
diff --git a/Main/Manager/ManagerBase.cs.meta b/Main/Manager/ManagerBase.cs.meta
new file mode 100644
index 0000000..9587db4
--- /dev/null
+++ b/Main/Manager/ManagerBase.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8c651c6b070b83d48b0f07117ed43058
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Manager/StageManager.cs b/Main/Manager/StageManager.cs
new file mode 100644
index 0000000..55bfdc8
--- /dev/null
+++ b/Main/Manager/StageManager.cs
@@ -0,0 +1,119 @@
+using System;
+using Cysharp.Threading.Tasks;
+using UnityEngine;
+using UnityEngine.SceneManagement;
+
+public enum StageName
+{
+    Login,
+    Game,
+}
+
+public class StageManager : Singleton<StageManager>, IManager
+{
+    public StageName currentStage;
+
+    public void Init()
+    {
+
+    }
+
+    public void Release()
+    {
+
+    }
+
+    public async UniTaskVoid ToLoginScene()
+    {
+        UIManager.Instance.DestroyAllUI();
+
+        AsyncOperation asyncOperation = SceneManager.LoadSceneAsync("Login");
+
+        await OnLoading(asyncOperation, () => 1f);
+
+        Main.OnSwitchToLoginScene();
+
+        currentStage = StageName.Login;
+
+        UIManager.Instance.OpenWindow<LoginWin>();
+    }
+
+    protected float GetManagerRequestDataProgress()
+    {
+        if (Main.managers.Count == 0)
+        {
+            return 1f;
+        }
+
+        int count = 0;
+
+        for (int i = 0; i < Main.managers.Count; i++)
+        {
+            var manager = Main.managers[i];
+
+            if (manager.IsNessaryDataReady())
+            {
+                count++;
+            }
+        }
+
+        return ((float)count) / ((float)Main.managers.Count);
+    }
+
+    public async UniTaskVoid ToGameScene()
+    {
+        UIManager.Instance.DestroyAllUI();
+
+        ResManager.Instance.PrewarmResources();
+
+        AsyncOperation asyncOperation = SceneManager.LoadSceneAsync("Game");
+
+        await OnLoading(asyncOperation, GetManagerRequestDataProgress);
+
+        //  鍔犺浇鍒濆鍖栨暟鎹畬鎴�
+        currentStage = StageName.Game;
+
+        UIManager.Instance.OpenWindow<MainWin>();
+    }
+
+    protected async UniTask OnLoading(AsyncOperation asyncOperation, Func<float> getLoadingProgress, Func<UniTask> anthorTask = null)
+    {
+        asyncOperation.allowSceneActivation = false;
+
+        LoadingWin loadingWin = UIManager.Instance.OpenWindow<LoadingWin>();
+
+        while (!asyncOperation.isDone)
+        {
+            if (asyncOperation.progress >= 0.9f)
+            {
+                asyncOperation.allowSceneActivation = true;
+            }
+
+            loadingWin.SetProgress(asyncOperation.progress * 0.5f + getLoadingProgress() * 0.5f);
+
+            await UniTask.Yield();
+        }
+
+        float managerProgress = getLoadingProgress();
+
+        while (managerProgress < 1f)
+        {
+            loadingWin.SetProgress(asyncOperation.progress * 0.5f + managerProgress * 0.5f);
+
+            await UniTask.Yield();
+
+            managerProgress = getLoadingProgress();
+        }
+
+        if (anthorTask != null)
+        {
+            await anthorTask();
+        }
+
+        loadingWin.SetProgress(1f, true);
+
+        await UniTask.Delay(TimeSpan.FromSeconds(0.5f));
+
+        loadingWin.CloseWindow();
+    }
+}
\ No newline at end of file
diff --git a/Main/Manager/StageManager.cs.meta b/Main/Manager/StageManager.cs.meta
new file mode 100644
index 0000000..cd53cbe
--- /dev/null
+++ b/Main/Manager/StageManager.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: aac79594075c0524080fb21a459c7264
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Place.meta b/Main/Place.meta
new file mode 100644
index 0000000..cce66df
--- /dev/null
+++ b/Main/Place.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 1244e95cb51b1cb42a8adaba3a5dff53
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Place/PlaceDataStructs.cs b/Main/Place/PlaceDataStructs.cs
new file mode 100644
index 0000000..19f5af1
--- /dev/null
+++ b/Main/Place/PlaceDataStructs.cs
@@ -0,0 +1,83 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+/// <summary>
+/// 鍗曚綅鏁版嵁
+/// </summary>
+public class UnitData
+{
+    public int ID { get; set; }
+    public string Name { get; set; }
+    public int HP { get; set; }
+    public int Attack { get; set; }
+    public float AttackSpeed { get; set; }
+    public float MoveSpeed { get; set; }
+    public string PrefabPath { get; set; }
+}
+
+/// <summary>
+/// 绔犺妭鏁版嵁
+/// </summary>
+public class ChapterData
+{
+    public int ID { get; set; }
+    public string Name { get; set; }
+    public int MapId { get; set; }
+    public List<WaveData> Waves { get; set; }
+    
+    /// <summary>
+    /// 鑾峰彇鎸囧畾娉㈡鐨勬晫浜哄垪琛�
+    /// </summary>
+    public List<int> GetEnemiesForWave(int wave)
+    {
+        if (wave <= 0 || wave > Waves.Count)
+            return new List<int>();
+            
+        return Waves[wave - 1].EnemyIds;
+    }
+    
+    /// <summary>
+    /// 鑾峰彇鎸囧畾娉㈡鐨勬帀钀界墿鍝�
+    /// </summary>
+    public List<DropItemData> GetDropsForWave(int wave)
+    {
+        if (wave <= 0 || wave > Waves.Count)
+            return new List<DropItemData>();
+            
+        return Waves[wave - 1].DropItems;
+    }
+}
+
+/// <summary>
+/// 娉㈡鏁版嵁
+/// </summary>
+public class WaveData
+{
+    public int WaveIndex { get; set; }
+    public List<int> EnemyIds { get; set; }
+    public List<DropItemData> DropItems { get; set; }
+}
+
+/// <summary>
+/// 鐗╁搧绫诲瀷
+/// </summary>
+public enum ItemType
+{
+    Gold,
+    Diamond,
+    Item
+}
+
+/// <summary>
+/// 鎺夎惤鐗╁搧鏁版嵁
+/// </summary>
+public class DropItemData
+{
+    public int ID { get; set; }
+    public ItemType ItemType { get; set; }
+    public int ItemId { get; set; }
+    public int Amount { get; set; }
+    public float DropRate { get; set; }
+    public string IconPath { get; set; }
+}
\ No newline at end of file
diff --git a/Main/Place/PlaceDataStructs.cs.meta b/Main/Place/PlaceDataStructs.cs.meta
new file mode 100644
index 0000000..2064cc8
--- /dev/null
+++ b/Main/Place/PlaceDataStructs.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4541140280fac3541b7ec64b9acd2f20
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Place/PlaceDrop.cs b/Main/Place/PlaceDrop.cs
new file mode 100644
index 0000000..3abd5e0
--- /dev/null
+++ b/Main/Place/PlaceDrop.cs
@@ -0,0 +1,143 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+/// <summary>
+/// 鏀剧疆鎴樻枟鎺夎惤鐗╁搧绫�
+/// </summary>
+public class PlaceDrop
+{
+    // 鎺夎惤鐗╁搧鏁版嵁
+    public DropItemData DropData { get; private set; }
+    
+    // 浣嶇疆
+    public Vector2 Position { get; private set; }
+    
+    // 鐘舵��
+    private enum DropState
+    {
+        Dropping,   // 鎺夎惤涓�
+        Waiting,    // 绛夊緟鏀堕泦
+        Flying      // 椋炲悜UI
+    }
+    
+    private DropState currentState = DropState.Dropping;
+    
+    // 璁℃椂鍣�
+    private float waitTimer = 0f;
+    private float waitDuration = 1.5f; // 绛夊緟1.5绉掑悗鑷姩鏀堕泦
+    
+    // 椋炶鐩稿叧
+    private Vector2 targetPosition;
+    private float flySpeed = 10f;
+    
+    // 鏄惁搴旇琚敹闆�
+    public bool ShouldCollect { get; private set; } = false;
+    
+    // 鎺夎惤鍔ㄧ敾璁℃椂鍣�
+    private float dropAnimTimer = 0f;
+    private float dropAnimDuration = 0.5f;
+    private Vector2 startPosition;
+    private Vector2 endPosition;
+    
+    /// <summary>
+    /// 鏋勯�犲嚱鏁�
+    /// </summary>
+    public PlaceDrop(DropItemData dropData)
+    {
+        DropData = dropData;
+        
+        // 闅忔満鎺夎惤浣嶇疆锛堝湪鍦烘櫙涓績闄勮繎锛�
+        startPosition = new Vector2(Random.Range(-2f, 2f), 5f);
+        endPosition = new Vector2(
+            startPosition.x + Random.Range(-1f, 1f),
+            Random.Range(-1f, 1f)
+        );
+        
+        Position = startPosition;
+        
+        // 璁剧疆椋炲悜鐨勭洰鏍囦綅缃紙UI涓婄殑璐у竵鏍忎綅缃級
+        targetPosition = new Vector2(8f, 4f); // 绀轰緥浣嶇疆锛屽疄闄呭簲璇ユ槸UI涓揣甯佹爮鐨勪笘鐣屽潗鏍�
+    }
+    
+    /// <summary>
+    /// 鏇存柊鎺夎惤鐗╁搧鐘舵��
+    /// </summary>
+    public void Update(float deltaTime)
+    {
+        switch (currentState)
+        {
+            case DropState.Dropping:
+                UpdateDropping(deltaTime);
+                break;
+                
+            case DropState.Waiting:
+                UpdateWaiting(deltaTime);
+                break;
+                
+            case DropState.Flying:
+                UpdateFlying(deltaTime);
+                break;
+        }
+    }
+    
+    /// <summary>
+    /// 鏇存柊鎺夎惤鍔ㄧ敾
+    /// </summary>
+    private void UpdateDropping(float deltaTime)
+    {
+        dropAnimTimer += deltaTime;
+        float t = Mathf.Clamp01(dropAnimTimer / dropAnimDuration);
+        
+        // 浣跨敤浜屾璐濆灏旀洸绾挎ā鎷熸帀钀芥晥鏋�
+        Position = Vector2.Lerp(startPosition, endPosition, t);
+        
+        // 鎺夎惤鍔ㄧ敾瀹屾垚鍚庡垏鎹㈠埌绛夊緟鐘舵��
+        if (t >= 1.0f)
+        {
+            currentState = DropState.Waiting;
+            waitTimer = 0f;
+        }
+    }
+    
+    /// <summary>
+    /// 鏇存柊绛夊緟鐘舵��
+    /// </summary>
+    private void UpdateWaiting(float deltaTime)
+    {
+        // 绛夊緟涓�娈垫椂闂村悗鑷姩鏀堕泦
+        waitTimer += deltaTime;
+        if (waitTimer >= waitDuration)
+        {
+            currentState = DropState.Flying;
+        }
+    }
+    
+    /// <summary>
+    /// 鏇存柊椋炶鐘舵��
+    /// </summary>
+    private void UpdateFlying(float deltaTime)
+    {
+        // 璁$畻椋炶鏂瑰悜
+        Vector2 direction = (targetPosition - Position).normalized;
+        
+        // 鏇存柊浣嶇疆
+        Position += direction * flySpeed * deltaTime;
+        
+        // 妫�鏌ユ槸鍚﹀埌杈剧洰鏍�
+        float distanceToTarget = Vector2.Distance(Position, targetPosition);
+        if (distanceToTarget < 0.1f)
+        {
+            // 鍒拌揪鐩爣锛屾爣璁颁负搴旇琚敹闆�
+            ShouldCollect = true;
+        }
+    }
+    
+    /// <summary>
+    /// 鎵嬪姩鏀堕泦鐗╁搧
+    /// </summary>
+    public void Collect()
+    {
+        currentState = DropState.Flying;
+    }
+}
\ No newline at end of file
diff --git a/Main/Place/PlaceDrop.cs.meta b/Main/Place/PlaceDrop.cs.meta
new file mode 100644
index 0000000..a1ee1ad
--- /dev/null
+++ b/Main/Place/PlaceDrop.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 070f25c487448bb44ac2134e1290d5f0
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Place/PlaceField.cs b/Main/Place/PlaceField.cs
new file mode 100644
index 0000000..bf2ab03
--- /dev/null
+++ b/Main/Place/PlaceField.cs
@@ -0,0 +1,406 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using System;
+
+/// <summary>
+/// 鏀剧疆鎴樻枟鍦哄湴绫伙紝绠$悊鎴樻枟鍦烘櫙涓殑鎵�鏈夊厓绱�
+/// </summary>
+public class PlaceField
+{
+
+    // 褰撳墠绔犺妭淇℃伅
+    private ChapterData currentChapter;
+    
+    // 鍦烘櫙涓殑鎵�鏈夊崟浣�
+    private List<PlaceUnit> allUnits = new List<PlaceUnit>();
+    
+    // 鐜╁鍗曚綅鍒楄〃
+    private List<PlaceUnit> playerUnits = new List<PlaceUnit>();
+    
+    // 鏁屼汉鍗曚綅鍒楄〃
+    private List<PlaceUnit> enemyUnits = new List<PlaceUnit>();
+    
+    // 鍦烘櫙涓殑鎺夎惤鐗╁搧
+    private List<PlaceDrop> dropItems = new List<PlaceDrop>();
+    
+    // 鎴樻枟鐘舵��
+    public enum BattleState
+    {
+        Preparing,  // 鍑嗗涓�
+        Fighting,   // 鎴樻枟涓�
+        Completed,  // 鎴樻枟瀹屾垚
+        Waiting     // 绛夊緟涓嬩竴鍦�
+    }
+    
+    public BattleState CurrentState { get; private set; } = BattleState.Preparing;
+    
+    // 鎴樻枟瀹屾垚浜嬩欢
+    public event Action OnBattleCompleted;
+    
+    // 鎺夎惤鐗╁搧鏀堕泦浜嬩欢
+    public event Action<DropItemData> OnItemCollected;
+    
+    // 绛夊緟璁℃椂鍣�
+    private float waitTimer = 0f;
+    private const float WAIT_DURATION = 2f; // 鎴樻枟缁撴潫鍚庣瓑寰�2绉�
+    
+    /// <summary>
+    /// 鍒濆鍖栨垬鏂楀満鏅�
+    /// </summary>
+    /// <param name="chapterId">绔犺妭ID</param>
+    public void InitBattleField(int chapterId)
+    {
+        Debug.Log($"鍒濆鍖栨垬鏂楀満鍦�: 绔犺妭{chapterId}");
+        
+        // 娓呯┖鍦烘櫙
+        ClearField();
+        
+        // 鍔犺浇绔犺妭鏁版嵁
+        LoadChapterData(chapterId);
+        
+        // 鍔犺浇鍦板浘鑳屾櫙
+        LoadMapBackground();
+        
+        // 鐢熸垚鐜╁闃靛
+        SpawnPlayerUnits();
+        
+        // 鐢熸垚鏁屾柟鍗曚綅
+        SpawnEnemyUnits();
+        
+        // 璁剧疆鎴樻枟鐘舵�佷负鍑嗗涓�
+        CurrentState = BattleState.Preparing;
+    }
+    
+    /// <summary>
+    /// 寮�濮嬫垬鏂�
+    /// </summary>
+    public void StartBattle()
+    {
+        if (CurrentState != BattleState.Preparing && CurrentState != BattleState.Waiting)
+            return;
+            
+        Debug.Log("寮�濮嬫垬鏂�");
+        CurrentState = BattleState.Fighting;
+        
+        // 閫氱煡鎵�鏈夊崟浣嶅紑濮嬫垬鏂�
+        foreach (var unit in allUnits)
+        {
+            unit.StartBattle();
+        }
+    }
+    
+    /// <summary>
+    /// 鏇存柊鎴樺満鐘舵��
+    /// </summary>
+    public void UpdateField(float deltaTime)
+    {
+        switch (CurrentState)
+        {
+            case BattleState.Fighting:
+                UpdateFighting(deltaTime);
+                break;
+                
+            case BattleState.Completed:
+                UpdateCompleted(deltaTime);
+                break;
+                
+            case BattleState.Waiting:
+                UpdateWaiting(deltaTime);
+                break;
+        }
+    }
+    
+    /// <summary>
+    /// 鏇存柊鎴樻枟鐘舵��
+    /// </summary>
+    private void UpdateFighting(float deltaTime)
+    {
+        // 鏇存柊鎵�鏈夊崟浣�
+        for (int i = allUnits.Count - 1; i >= 0; i--)
+        {
+            if (i < allUnits.Count)
+            {
+                allUnits[i].UpdateUnit(deltaTime);
+            }
+        }
+        
+        // 妫�鏌ユ垬鏂楁槸鍚︾粨鏉�
+        CheckBattleEnd();
+        
+        // 鏇存柊鎺夎惤鐗╁搧
+        UpdateDropItems(deltaTime);
+    }
+    
+    /// <summary>
+    /// 鏇存柊鎴樻枟瀹屾垚鐘舵��
+    /// </summary>
+    private void UpdateCompleted(float deltaTime)
+    {
+        // 鏇存柊鎺夎惤鐗╁搧
+        UpdateDropItems(deltaTime);
+        
+        // 妫�鏌ユ槸鍚︽墍鏈夋帀钀界墿鍝侀兘宸叉敹闆�
+        bool allItemsCollected = true;
+        foreach (var item in dropItems)
+        {
+            if (!item.ShouldCollect)
+            {
+                allItemsCollected = false;
+                break;
+            }
+        }
+        
+        // 濡傛灉鎵�鏈夌墿鍝侀兘宸叉敹闆嗭紝杩涘叆绛夊緟鐘舵��
+        if (allItemsCollected && dropItems.Count > 0)
+        {
+            CurrentState = BattleState.Waiting;
+            waitTimer = 0f;
+        }
+        // 濡傛灉娌℃湁鎺夎惤鐗╁搧锛岀洿鎺ヨ繘鍏ョ瓑寰呯姸鎬�
+        else if (dropItems.Count == 0)
+        {
+            CurrentState = BattleState.Waiting;
+            waitTimer = 0f;
+        }
+    }
+    
+    /// <summary>
+    /// 鏇存柊绛夊緟鐘舵��
+    /// </summary>
+    private void UpdateWaiting(float deltaTime)
+    {
+        waitTimer += deltaTime;
+        
+        // 绛夊緟鏃堕棿缁撴潫鍚庯紝寮�濮嬩笅涓�鍦烘垬鏂�
+        if (waitTimer >= WAIT_DURATION)
+        {
+            // 娓呯悊鎴樺満
+            ClearField();
+            
+            // 閲嶆柊鍒濆鍖栨垬鍦�
+            InitBattleField(currentChapter.ID);
+            
+            // 寮�濮嬫柊鐨勬垬鏂�
+            StartBattle();
+        }
+    }
+    
+    /// <summary>
+    /// 鍔犺浇绔犺妭鏁版嵁
+    /// </summary>
+    private void LoadChapterData(int chapterId)
+    {
+        // 浠庨厤缃鐞嗗櫒鍔犺浇绔犺妭鏁版嵁
+        // currentChapter = ConfigManager.Instance.GetChapterData(chapterId);
+        
+        // 涓存椂浠g爜锛屽垱寤轰竴涓祴璇曠珷鑺�
+        currentChapter = new ChapterData
+        {
+            ID = chapterId,
+            Name = $"娴嬭瘯绔犺妭 {chapterId}",
+            MapId = chapterId
+        };
+        
+        Debug.Log($"鍔犺浇绔犺妭鏁版嵁: {currentChapter.Name}");
+    }
+    
+    /// <summary>
+    /// 鍔犺浇鍦板浘鑳屾櫙
+    /// </summary>
+    private void LoadMapBackground()
+    {
+        // 鏍规嵁绔犺妭鏁版嵁鍔犺浇瀵瑰簲鐨勫湴鍥捐儗鏅�
+        // MapManager.Instance.LoadMap(currentChapter.MapId);
+        Debug.Log($"鍔犺浇鍦板浘鑳屾櫙: MapID={currentChapter.MapId}");
+    }
+    
+    /// <summary>
+    /// 鐢熸垚鐜╁闃靛
+    /// </summary>
+    private void SpawnPlayerUnits()
+    {
+        Debug.Log("鐢熸垚鐜╁闃靛");
+        
+        // 浠庣帺瀹舵暟鎹腑鑾峰彇褰撳墠闃靛
+        // var formation = PlayerManager.Instance.CurrentFormation;
+        
+        // 涓存椂浠g爜锛屽垱寤烘祴璇曠帺瀹跺崟浣�
+        for (int i = 0; i < 3; i++)
+        {
+            UnitData unitData = new UnitData
+            {
+                ID = 1000 + i,
+                Name = $"鐜╁瑙掕壊 {i+1}",
+                HP = 100,
+                Attack = 10,
+                AttackSpeed = 1.0f,
+                MoveSpeed = 2.0f,
+                PrefabPath = $"Characters/Player_{i+1}"
+            };
+            
+            PlaceUnit unit = new PlaceUnit(unitData, true);
+            playerUnits.Add(unit);
+            allUnits.Add(unit);
+            
+            Debug.Log($"鐢熸垚鐜╁鍗曚綅: {unit.UnitData.Name}");
+        }
+    }
+    
+    /// <summary>
+    /// 鐢熸垚鏁屾柟鍗曚綅
+    /// </summary>
+    private void SpawnEnemyUnits()
+    {
+        Debug.Log("鐢熸垚鏁屾柟鍗曚綅");
+        
+        // 鏍规嵁绔犺妭鏁版嵁鐢熸垚鏁屾柟鍗曚綅
+        // var enemyIds = currentChapter.GetEnemiesForWave(1);
+        
+        // 涓存椂浠g爜锛屽垱寤烘祴璇曟晫鏂瑰崟浣�
+        for (int i = 0; i < 5; i++)
+        {
+            UnitData unitData = new UnitData
+            {
+                ID = 2000 + i,
+                Name = $"鏁屾柟鍗曚綅 {i+1}",
+                HP = 50,
+                Attack = 5,
+                AttackSpeed = 0.8f,
+                MoveSpeed = 1.5f,
+                PrefabPath = $"Characters/Enemy_{i+1}"
+            };
+            
+            PlaceUnit unit = new PlaceUnit(unitData, false);
+            enemyUnits.Add(unit);
+            allUnits.Add(unit);
+            
+            Debug.Log($"鐢熸垚鏁屾柟鍗曚綅: {unit.UnitData.Name}");
+        }
+    }
+    
+    /// <summary>
+    /// 妫�鏌ユ垬鏂楁槸鍚︾粨鏉�
+    /// </summary>
+    private void CheckBattleEnd()
+    {
+        // 妫�鏌ユ晫鏂瑰崟浣嶆槸鍚﹀叏閮ㄩ樀浜�
+        bool allEnemyDead = true;
+        foreach (var unit in enemyUnits)
+        {
+            if (!unit.IsDead)
+            {
+                allEnemyDead = false;
+                break;
+            }
+        }
+        
+        // 濡傛灉鎵�鏈夋晫浜洪兘宸查樀浜★紝鎴樻枟缁撴潫
+        if (allEnemyDead)
+        {
+            CompleteBattle();
+        }
+    }
+    
+    /// <summary>
+    /// 瀹屾垚鎴樻枟
+    /// </summary>
+    private void CompleteBattle()
+    {
+        Debug.Log("鎴樻枟瀹屾垚");
+        CurrentState = BattleState.Completed;
+        
+        // 鍋滄鎵�鏈夊崟浣嶈鍔�
+        foreach (var unit in allUnits)
+        {
+            unit.StopBattle();
+        }
+        
+        // 鐢熸垚鎺夎惤鐗╁搧
+        GenerateDropItems();
+        
+        // 瑙﹀彂鎴樻枟瀹屾垚浜嬩欢
+        OnBattleCompleted?.Invoke();
+    }
+    
+    /// <summary>
+    /// 鐢熸垚鎺夎惤鐗╁搧
+    /// </summary>
+    private void GenerateDropItems()
+    {
+        Debug.Log("鐢熸垚鎺夎惤鐗╁搧");
+        
+        // 鏍规嵁绔犺妭鎺夎惤琛ㄧ敓鎴愭帀钀界墿鍝�
+        // var dropList = currentChapter.GetDropsForWave(1);
+        
+        // 涓存椂浠g爜锛屽垱寤烘祴璇曟帀钀界墿鍝�
+        for (int i = 0; i < 5; i++)
+        {
+            DropItemData dropData = new DropItemData
+            {
+                ID = i,
+                ItemType = (i % 3 == 0) ? ItemType.Gold : (i % 3 == 1) ? ItemType.Diamond : ItemType.Item,
+                ItemId = i,
+                Amount = UnityEngine.Random.Range(10, 100),
+                DropRate = 1.0f,
+                IconPath = $"Icons/Item_{i}"
+            };
+            
+            // 鍒涘缓鎺夎惤鐗╁搧
+            PlaceDrop drop = new PlaceDrop(dropData);
+            dropItems.Add(drop);
+            
+            Debug.Log($"鐢熸垚鎺夎惤鐗╁搧: 绫诲瀷={dropData.ItemType}, 鏁伴噺={dropData.Amount}");
+        }
+    }
+    
+    /// <summary>
+    /// 鏇存柊鎺夎惤鐗╁搧
+    /// </summary>
+    private void UpdateDropItems(float deltaTime)
+    {
+        for (int i = dropItems.Count - 1; i >= 0; i--)
+        {
+            dropItems[i].Update(deltaTime);
+            
+            // 妫�鏌ユ槸鍚﹂渶瑕佹敹闆嗙墿鍝�
+            if (dropItems[i].ShouldCollect)
+            {
+                // 瑙﹀彂鐗╁搧鏀堕泦浜嬩欢
+                OnItemCollected?.Invoke(dropItems[i].DropData);
+                
+                // 绉婚櫎鐗╁搧
+                dropItems.RemoveAt(i);
+            }
+        }
+    }
+    
+    /// <summary>
+    /// 娓呯┖鎴樺満
+    /// </summary>
+    public void ClearField()
+    {
+        Debug.Log("娓呯┖鎴樺満");
+        allUnits.Clear();
+        playerUnits.Clear();
+        enemyUnits.Clear();
+        dropItems.Clear();
+        CurrentState = BattleState.Preparing;
+    }
+    
+    /// <summary>
+    /// 鑾峰彇鐜╁鍗曚綅鍒楄〃
+    /// </summary>
+    public List<PlaceUnit> GetPlayerUnits()
+    {
+        return new List<PlaceUnit>(playerUnits);
+    }
+    
+    /// <summary>
+    /// 鑾峰彇鏁屾柟鍗曚綅鍒楄〃
+    /// </summary>
+    public List<PlaceUnit> GetEnemyUnits()
+    {
+        return new List<PlaceUnit>(enemyUnits);
+    }
+}
diff --git a/Main/Place/PlaceField.cs.meta b/Main/Place/PlaceField.cs.meta
new file mode 100644
index 0000000..875ca33
--- /dev/null
+++ b/Main/Place/PlaceField.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b82dee68a4dcad54780acf1dad335d8c
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Place/PlaceUnit.cs b/Main/Place/PlaceUnit.cs
new file mode 100644
index 0000000..fe4eca5
--- /dev/null
+++ b/Main/Place/PlaceUnit.cs
@@ -0,0 +1,516 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+/// <summary>
+/// 鏀剧疆鎴樻枟鍗曚綅绫伙紝浠h〃鎴樺満涓婄殑涓�涓鑹�
+/// </summary>
+public class PlaceUnit
+{
+    // 鍗曚綅鏁版嵁
+    public UnitData UnitData { get; private set; }
+    
+    // 鍗曚綅灞炴��
+    public int HP { get; private set; }
+    public int MaxHP { get; private set; }
+    public int Attack { get; private set; }
+    public float AttackSpeed { get; private set; }
+    public float MoveSpeed { get; private set; }
+    
+    // 鍗曚綅鐘舵��
+    public bool IsPlayer { get; private set; }
+    public bool IsDead { get; private set; }
+    
+    // 浣嶇疆鍜屾湞鍚�
+    public Vector2 Position { get; private set; }
+    public Vector2 Direction { get; private set; }
+    
+    // 鎴樻枟鐩稿叧
+    private PlaceUnit targetUnit;
+    private float attackCooldown;
+    
+    // 鍗曚綅琛屼负鐘舵��
+    public enum UnitState
+    {
+        Idle,       // 寰呮満
+        Moving,     // 绉诲姩涓�
+        Attacking,  // 鏀诲嚮涓�
+        Dead        // 姝讳骸
+    }
+    
+    public UnitState CurrentState { get; private set; } = UnitState.Idle;
+    
+    /// <summary>
+    /// 鏋勯�犲嚱鏁�
+    /// </summary>
+    /// <param name="data">鍗曚綅鏁版嵁</param>
+    /// <param name="isPlayer">鏄惁涓虹帺瀹跺崟浣�</param>
+    public PlaceUnit(UnitData data, bool isPlayer)
+    {
+        UnitData = data;
+        IsPlayer = isPlayer;
+        
+        // 鍒濆鍖栧睘鎬�
+        MaxHP = data.HP;
+        HP = MaxHP;
+        Attack = data.Attack;
+        AttackSpeed = data.AttackSpeed;
+        MoveSpeed = data.MoveSpeed;
+        
+        // 鍒濆鍖栨敾鍑诲喎鍗�
+        attackCooldown = Random.Range(0f, 1f / AttackSpeed);
+        
+        // 璁剧疆鍒濆浣嶇疆
+        Position = isPlayer ? new Vector2(-5f + Random.Range(-1f, 1f), Random.Range(-2f, 2f)) : 
+                             new Vector2(5f + Random.Range(-1f, 1f), Random.Range(-2f, 2f));
+        Direction = isPlayer ? Vector2.right : Vector2.left;
+        
+        IsDead = false;
+        CurrentState = UnitState.Idle;
+    }
+    
+    /// <summary>
+    /// 寮�濮嬫垬鏂�
+    /// </summary>
+    public void StartBattle()
+    {
+        if (IsDead) return;
+        
+        CurrentState = UnitState.Idle;
+        FindTarget();
+    }
+    
+    /// <summary>
+    /// 鍋滄鎴樻枟
+    /// </summary>
+    public void StopBattle()
+    {
+        if (IsDead) return;
+        
+        CurrentState = UnitState.Idle;
+        targetUnit = null;
+    }
+    
+    /// <summary>
+    /// 鏇存柊鍗曚綅鐘舵��
+    /// </summary>
+    public void UpdateUnit(float deltaTime)
+    {
+        if (IsDead) return;
+        
+        // 濡傛灉娌℃湁鐩爣锛屽皾璇曞鎵剧洰鏍�
+        if (targetUnit == null || targetUnit.IsDead)
+        {
+            FindTarget();
+            if (targetUnit == null)
+            {
+                CurrentState = UnitState.Idle;
+                return;
+            }
+        }
+        
+        // 鏍规嵁涓庣洰鏍囩殑璺濈鍐冲畾琛屼负
+        float distanceToTarget = Vector2.Distance(Position, targetUnit.Position);
+        float attackRange = 1.5f; // 鏀诲嚮鑼冨洿
+        
+        if (distanceToTarget <= attackRange)
+        {
+            // 鍦ㄦ敾鍑昏寖鍥村唴锛屾墽琛屾敾鍑�
+            AttackTarget(deltaTime);
+        }
+        else
+        {
+            // 涓嶅湪鏀诲嚮鑼冨洿鍐咃紝绉诲姩鎺ヨ繎鐩爣
+            MoveToTarget(deltaTime);
+        }
+    }
+    
+    /// <summary>
+    /// 瀵绘壘鐩爣
+    /// </summary>
+    private void FindTarget()
+    {
+        // 浠庡満鏅腑瀵绘壘鏁屽鍗曚綅浣滀负鐩爣
+        List<PlaceUnit> potentialTargets = IsPlayer ? 
+            PlaceManager.Instance.placeField.GetEnemyUnits() : 
+            PlaceManager.Instance.placeField.GetPlayerUnits();
+            
+        float minDistance = float.MaxValue;
+        PlaceUnit nearestTarget = null;
+        
+        foreach (var unit in potentialTargets)
+        {
+            if (!unit.IsDead)
+            {
+                float distance = Vector2.Distance(Position, unit.Position);
+                if (distance < minDistance)
+                {
+                    minDistance = distance;
+                    nearestTarget = unit;
+                }
+            }
+        }
+        
+        targetUnit = nearestTarget;
+    }
+    
+    /// <summary>
+    /// 绉诲姩鍚戠洰鏍�
+    /// </summary>
+    private void MoveToTarget(float deltaTime)
+    {
+        CurrentState = UnitState.Moving;
+        
+        // 璁$畻绉诲姩鏂瑰悜
+        Vector2 moveDirection = (targetUnit.Position - Position).normalized;
+        
+        // 妫�鏌ユ槸鍚︽湁闅滅鐗╋紝濡傛灉鏈夊垯闇�瑕佸璺�
+        if (HasObstacle(Position, targetUnit.Position))
+        {
+            // 绠�鍗曠殑瀵昏矾閫昏緫
+            moveDirection = FindPathDirection(targetUnit.Position);
+        }
+        
+        // 妫�鏌ユ槸鍚︿笌鍏朵粬鍗曚綅閲嶅彔
+        Vector2 avoidanceDirection = Vector2.zero;
+        int avoidanceCount = 0;
+        
+        // 鑾峰彇鎵�鏈夊崟浣�
+        List<PlaceUnit> allUnits = new List<PlaceUnit>();
+        allUnits.AddRange(PlaceManager.Instance.placeField.GetPlayerUnits());
+        allUnits.AddRange(PlaceManager.Instance.placeField.GetEnemyUnits());
+        
+        // 妫�鏌ラ檮杩戠殑鍗曚綅
+        foreach (var unit in allUnits)
+        {
+            if (unit != this && !unit.IsDead)
+            {
+                float distance = Vector2.Distance(Position, unit.Position);
+                if (distance < 1.0f) // 閬胯璺濈
+                {
+                    // 璁$畻閬胯鏂瑰悜
+                    Vector2 dir = (Position - unit.Position).normalized;
+                    avoidanceDirection += dir;
+                    avoidanceCount++;
+                }
+            }
+        }
+        
+        // 濡傛灉鏈夐渶瑕侀伩璁╃殑鍗曚綅锛岃皟鏁寸Щ鍔ㄦ柟鍚�
+        if (avoidanceCount > 0)
+        {
+            avoidanceDirection /= avoidanceCount;
+            moveDirection = Vector2.Lerp(moveDirection, avoidanceDirection, 0.5f).normalized;
+        }
+        
+        // 鏇存柊浣嶇疆
+        Position += moveDirection * MoveSpeed * deltaTime;
+        
+        // 鏇存柊鏈濆悜
+        Direction = moveDirection;
+    }
+    
+    /// <summary>
+    /// 妫�鏌ユ槸鍚︽湁闅滅鐗�
+    /// </summary>
+    private bool HasObstacle(Vector2 start, Vector2 end)
+    {
+        // 绠�鍗曠殑闅滅鐗╂娴嬶紝瀹為檯椤圭洰涓彲鑳介渶瑕佹洿澶嶆潅鐨勭鎾炴娴�
+        // 杩欓噷鍙互浣跨敤Physics2D.Raycast鏉ユ娴�
+        
+        // 绀轰緥浠g爜
+        // RaycastHit2D hit = Physics2D.Raycast(start, end - start, Vector2.Distance(start, end), obstacleLayer);
+        // return hit.collider != null;
+        
+        // 涓存椂浠g爜锛岄殢鏈虹敓鎴愰殰纰嶇墿
+        return Random.value < 0.1f;
+    }
+    
+    /// <summary>
+    /// 瀵绘壘璺緞鏂瑰悜
+    /// </summary>
+    private Vector2 FindPathDirection(Vector2 target)
+    {
+        // 浣跨敤A*瀵昏矾绠楁硶
+        List<Node> path = AStar(Position, target);
+        
+        if (path != null && path.Count > 0)
+        {
+            // 鑾峰彇涓嬩竴涓妭鐐圭殑鏂瑰悜
+            Vector2 nextNodePos = path[0].position;
+            return (nextNodePos - Position).normalized;
+        }
+        
+        // 濡傛灉瀵昏矾澶辫触锛岀洿鎺ヨ繑鍥炵洰鏍囨柟鍚�
+        return (target - Position).normalized;
+    }
+    
+    /// <summary>
+    /// A*瀵昏矾绠楁硶
+    /// </summary>
+    private List<Node> AStar(Vector2 start, Vector2 goal)
+    {
+        // 缃戞牸澶у皬璁剧疆
+        float gridSize = 0.5f;
+        int gridWidth = 20;
+        int gridHeight = 10;
+        
+        // 鍒涘缓寮�鏀惧垪琛ㄥ拰鍏抽棴鍒楄〃
+        List<Node> openList = new List<Node>();
+        List<Node> closedList = new List<Node>();
+        
+        // 鍒涘缓璧风偣鍜岀粓鐐硅妭鐐�
+        Node startNode = new Node(start, null);
+        Node goalNode = new Node(goal, null);
+        
+        // 璁$畻璧风偣鐨刦銆乬銆乭鍊�
+        startNode.g = 0;
+        startNode.h = CalculateHeuristic(startNode, goalNode);
+        startNode.f = startNode.g + startNode.h;
+        
+        // 灏嗚捣鐐瑰姞鍏ュ紑鏀惧垪琛�
+        openList.Add(startNode);
+        
+        // 寮�濮婣*绠楁硶涓诲惊鐜�
+        while (openList.Count > 0)
+        {
+            // 鎵惧埌寮�鏀惧垪琛ㄤ腑f鍊兼渶灏忕殑鑺傜偣
+            Node currentNode = FindNodeWithLowestF(openList);
+            
+            // 濡傛灉褰撳墠鑺傜偣鏄洰鏍囪妭鐐癸紝鍒欐瀯寤鸿矾寰勫苟杩斿洖
+            if (Vector2.Distance(currentNode.position, goalNode.position) < gridSize)
+            {
+                return BuildPath(currentNode);
+            }
+            
+            // 灏嗗綋鍓嶈妭鐐逛粠寮�鏀惧垪琛ㄧЩ闄わ紝鍔犲叆鍏抽棴鍒楄〃
+            openList.Remove(currentNode);
+            closedList.Add(currentNode);
+            
+            // 鑾峰彇褰撳墠鑺傜偣鐨勭浉閭昏妭鐐�
+            List<Node> neighbors = GetNeighbors(currentNode, gridSize, gridWidth, gridHeight);
+            
+            foreach (Node neighbor in neighbors)
+            {
+                // 濡傛灉鐩搁偦鑺傜偣鍦ㄥ叧闂垪琛ㄤ腑锛屽垯璺宠繃
+                if (IsNodeInList(neighbor, closedList))
+                {
+                    continue;
+                }
+                
+                // 濡傛灉鐩搁偦鑺傜偣浣嶇疆鏈夐殰纰嶇墿锛屽垯璺宠繃
+                if (HasObstacle(currentNode.position, neighbor.position))
+                {
+                    continue;
+                }
+                
+                // 璁$畻浠庤捣鐐圭粡杩囧綋鍓嶈妭鐐瑰埌鐩搁偦鑺傜偣鐨勪唬浠�
+                float tentativeG = currentNode.g + Vector2.Distance(currentNode.position, neighbor.position);
+                
+                // 濡傛灉鐩搁偦鑺傜偣涓嶅湪寮�鏀惧垪琛ㄤ腑锛屾垨鑰呮柊璺緞鏇翠紭锛屽垯鏇存柊鐩搁偦鑺傜偣
+                if (!IsNodeInList(neighbor, openList) || tentativeG < neighbor.g)
+                {
+                    neighbor.parent = currentNode;
+                    neighbor.g = tentativeG;
+                    neighbor.h = CalculateHeuristic(neighbor, goalNode);
+                    neighbor.f = neighbor.g + neighbor.h;
+                    
+                    // 濡傛灉鐩搁偦鑺傜偣涓嶅湪寮�鏀惧垪琛ㄤ腑锛屽垯鍔犲叆寮�鏀惧垪琛�
+                    if (!IsNodeInList(neighbor, openList))
+                    {
+                        openList.Add(neighbor);
+                    }
+                }
+            }
+        }
+        
+        // 濡傛灉寮�鏀惧垪琛ㄤ负绌猴紝鍒欏璺け璐ワ紝杩斿洖null
+        return null;
+    }
+    
+    /// <summary>
+    /// 璁$畻鍚彂寮忓嚱鏁板�硷紙鏇煎搱椤胯窛绂伙級
+    /// </summary>
+    private float CalculateHeuristic(Node node, Node goal)
+    {
+        // 浣跨敤鏇煎搱椤胯窛绂讳綔涓哄惎鍙戝紡鍑芥暟
+        return Mathf.Abs(node.position.x - goal.position.x) + Mathf.Abs(node.position.y - goal.position.y);
+    }
+    
+    /// <summary>
+    /// 鏌ユ壘寮�鏀惧垪琛ㄤ腑f鍊兼渶灏忕殑鑺傜偣
+    /// </summary>
+    private Node FindNodeWithLowestF(List<Node> list)
+    {
+        Node lowestNode = list[0];
+        
+        for (int i = 1; i < list.Count; i++)
+        {
+            if (list[i].f < lowestNode.f)
+            {
+                lowestNode = list[i];
+            }
+        }
+        
+        return lowestNode;
+    }
+    
+    /// <summary>
+    /// 鑾峰彇鑺傜偣鐨勭浉閭昏妭鐐�
+    /// </summary>
+    private List<Node> GetNeighbors(Node node, float gridSize, int gridWidth, int gridHeight)
+    {
+        List<Node> neighbors = new List<Node>();
+        
+        // 8涓柟鍚戠殑鐩搁偦鑺傜偣
+        Vector2[] directions = new Vector2[]
+        {
+            new Vector2(1, 0),    // 鍙�
+            new Vector2(-1, 0),   // 宸�
+            new Vector2(0, 1),    // 涓�
+            new Vector2(0, -1),   // 涓�
+            new Vector2(1, 1),    // 鍙充笂
+            new Vector2(1, -1),   // 鍙充笅
+            new Vector2(-1, 1),   // 宸︿笂
+            new Vector2(-1, -1)   // 宸︿笅
+        };
+        
+        foreach (Vector2 dir in directions)
+        {
+            Vector2 neighborPos = node.position + dir * gridSize;
+            
+            // 妫�鏌ユ槸鍚﹀湪缃戞牸鑼冨洿鍐�
+            if (neighborPos.x >= -gridWidth/2 && neighborPos.x <= gridWidth/2 &&
+                neighborPos.y >= -gridHeight/2 && neighborPos.y <= gridHeight/2)
+            {
+                Node neighbor = new Node(neighborPos, node);
+                neighbors.Add(neighbor);
+            }
+        }
+        
+        return neighbors;
+    }
+    
+    /// <summary>
+    /// 妫�鏌ヨ妭鐐规槸鍚﹀湪鍒楄〃涓�
+    /// </summary>
+    private bool IsNodeInList(Node node, List<Node> list)
+    {
+        foreach (Node n in list)
+        {
+            if (Vector2.Distance(n.position, node.position) < 0.1f)
+            {
+                return true;
+            }
+        }
+        
+        return false;
+    }
+    
+    /// <summary>
+    /// 鏋勫缓浠庤捣鐐瑰埌褰撳墠鑺傜偣鐨勮矾寰�
+    /// </summary>
+    private List<Node> BuildPath(Node node)
+    {
+        List<Node> path = new List<Node>();
+        Node currentNode = node;
+        
+        // 浠庣洰鏍囪妭鐐瑰洖婧埌璧风偣
+        while (currentNode.parent != null)
+        {
+            path.Insert(0, currentNode);
+            currentNode = currentNode.parent;
+        }
+        
+        return path;
+    }
+    
+    /// <summary>
+    /// A*瀵昏矾鐨勮妭鐐圭被
+    /// </summary>
+    private class Node
+    {
+        public Vector2 position;  // 鑺傜偣浣嶇疆
+        public Node parent;       // 鐖惰妭鐐�
+        public float g;           // 浠庤捣鐐瑰埌褰撳墠鑺傜偣鐨勪唬浠�
+        public float h;           // 浠庡綋鍓嶈妭鐐瑰埌鐩爣鑺傜偣鐨勪及璁′唬浠�
+        public float f;           // f = g + h锛屾�讳唬浠�
+        
+        public Node(Vector2 pos, Node parent)
+        {
+            this.position = pos;
+            this.parent = parent;
+        }
+    }
+    
+    /// <summary>
+    /// 鏀诲嚮鐩爣
+    /// </summary>
+    private void AttackTarget(float deltaTime)
+    {
+        CurrentState = UnitState.Attacking;
+        
+        // 鏀诲嚮鍐峰嵈
+        attackCooldown -= deltaTime;
+        if (attackCooldown <= 0)
+        {
+            // 鎵ц鏀诲嚮
+            PerformAttack();
+            
+            // 閲嶇疆鍐峰嵈
+            attackCooldown = 1f / AttackSpeed;
+        }
+    }
+    
+    /// <summary>
+    /// 鎵ц鏀诲嚮
+    /// </summary>
+    private void PerformAttack()
+    {
+        if (targetUnit != null && !targetUnit.IsDead)
+        {
+            // 閫犳垚浼ゅ
+            targetUnit.TakeDamage(Attack);
+            
+            // 鎾斁鏀诲嚮鍔ㄧ敾/鐗规晥
+            Debug.Log($"{UnitData.Name} 鏀诲嚮 {targetUnit.UnitData.Name}, 閫犳垚 {Attack} 鐐逛激瀹�");
+        }
+    }
+    
+    /// <summary>
+    /// 鍙楀埌浼ゅ
+    /// </summary>
+    public void TakeDamage(int damage)
+    {
+        if (IsDead) return;
+        
+        // 璁$畻瀹為檯浼ゅ锛堣�冭檻闃插尽绛夊洜绱狅級
+        int defense = Mathf.Max(0, MaxHP / 20); // 绠�鍗曢槻寰¤绠楋紝鍩轰簬鏈�澶х敓鍛藉��
+        int actualDamage = Mathf.Max(1, damage - defense); // 纭繚鑷冲皯閫犳垚1鐐逛激瀹�
+        
+        // 鎵i櫎鐢熷懡鍊�
+        HP -= actualDamage;
+        
+        // 妫�鏌ユ槸鍚︽浜�
+        if (HP <= 0)
+        {
+            HP = 0;
+            Die();
+        }
+        
+        // 鏄剧ず浼ゅ鏁板瓧
+        Debug.Log($"{UnitData.Name} 鍙楀埌 {actualDamage} 鐐逛激瀹�, 鍓╀綑HP: {HP}/{MaxHP}");
+    }
+    
+    /// <summary>
+    /// 姝讳骸澶勭悊
+    /// </summary>
+    private void Die()
+    {
+        IsDead = true;
+        CurrentState = UnitState.Dead;
+        
+        // 鎾斁姝讳骸鍔ㄧ敾
+        Debug.Log($"{UnitData.Name} 姝讳骸");
+    }
+}
\ No newline at end of file
diff --git a/Main/Place/PlaceUnit.cs.meta b/Main/Place/PlaceUnit.cs.meta
new file mode 100644
index 0000000..34a21a2
--- /dev/null
+++ b/Main/Place/PlaceUnit.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 84bf5729662617b4582cbe05bad8d53c
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/UI/LoadingWin.cs b/Main/UI/LoadingWin.cs
new file mode 100644
index 0000000..4f293e7
--- /dev/null
+++ b/Main/UI/LoadingWin.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.UI;
+
+public class LoadingWin : UIBase
+{
+    protected int currentProgress = 0;
+    protected int targetProgress = 0;
+
+    protected Text titleText;
+    protected Text tipsText;
+    protected Image progressBar;
+    protected Text progressText;
+
+    protected override void InitComponent()
+    {
+        base.InitComponent();
+        titleText = transform.Find("Text_Loading").GetComponent<Text>();
+        tipsText = transform.Find("Text_Tips").GetComponent<Text>();
+        progressBar = transform.Find("Img_Progress/Img_Foreground").GetComponent<Image>();
+        progressText = transform.Find("Text_Progress").GetComponent<Text>();
+    }
+
+    public override void HandleOpen()
+    {
+        base.HandleOpen();
+        currentProgress = targetProgress = 0;
+        Refresh();
+    }
+
+    public override void HandleClose()
+    {
+        base.HandleClose();
+    }
+
+    public override void Refresh()
+    {
+        base.Refresh();
+        UpdateProgress();
+    }
+
+    public void SetProgress(float value, bool directly = false)
+    {
+        if (directly)
+        {
+            currentProgress = targetProgress = (int)(value * 100);
+            UpdateProgress();
+        }
+        else
+        {
+            currentProgress = (int)(value * 100);
+        }
+
+        
+    }
+
+    protected void UpdateProgress()
+    {
+        progressText.text = currentProgress + "%";
+        progressBar.fillAmount = currentProgress / 100f;
+    }
+
+    protected void Update()
+    {
+        if (currentProgress < targetProgress)
+        {
+            currentProgress = (int)Mathf.Lerp(currentProgress, targetProgress, 0.1f);
+            UpdateProgress();
+        }
+    }
+}
\ No newline at end of file
diff --git a/Main/UI/LoadingWin.cs.meta b/Main/UI/LoadingWin.cs.meta
new file mode 100644
index 0000000..850f121
--- /dev/null
+++ b/Main/UI/LoadingWin.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e85e62037b34d9944a44a4c93764c656
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/UI/Login.meta b/Main/UI/Login.meta
new file mode 100644
index 0000000..99ddaf1
--- /dev/null
+++ b/Main/UI/Login.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: bef9e971d62416147ae8006de5cbff6a
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/UI/Login/LoginWin.cs b/Main/UI/Login/LoginWin.cs
new file mode 100644
index 0000000..3df7acb
--- /dev/null
+++ b/Main/UI/Login/LoginWin.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics.Tracing;
+using UnityEngine;
+using UnityEngine.UI;
+
+public class LoginWin : UIBase
+{
+    private InputField username;
+    private InputField password;
+    private Button loginBtn;
+    private Button registerBtn;
+
+    protected override void InitComponent()
+    {
+        base.InitComponent();
+        Debug.Log("鍒濆鍖栫櫥褰曠獥鍙�");
+        username = transform.Find("InputUserName").GetComponent<InputField>();
+        password = transform.Find("InputPassword").GetComponent<InputField>();
+        loginBtn = transform.Find("Buttons/ButtonLogin").GetComponent<Button>();
+        registerBtn = transform.Find("Buttons/ButtonRegister").GetComponent<Button>();
+
+        loginBtn.onClick.AddListener(OnLoginBtnClick);
+        registerBtn.onClick.AddListener(OnRegisterBtnClick);
+    }
+
+    public override void HandleOpen()
+    {
+        base.HandleOpen();
+        Debug.Log("鎵撳紑鐧诲綍绐楀彛");
+        ResManager.Instance.PrewarmResources();
+        Refresh();
+    }
+
+    public override void HandleClose()
+    {
+        base.HandleClose();
+        Debug.Log("鍏抽棴鐧诲綍绐楀彛");
+    }
+
+    public override void Refresh()
+    {
+        base.Refresh();
+        Debug.Log("鍒锋柊鐧诲綍绐楀彛");
+    }
+
+    private void OnRegisterBtnClick()
+    {
+        //  TODO 娉ㄥ唽
+        Debug.Log("娉ㄥ唽");
+    }
+
+    private void OnLoginBtnClick()
+    {
+        //  TODO 鐧诲綍
+        Debug.Log("鐧诲綍" + username.text + " / " + password.text);
+        UIManager.Instance.CloseWindow(this);
+
+        StageManager.Instance.ToGameScene();
+    }
+}
diff --git a/Main/UI/Login/LoginWin.cs.meta b/Main/UI/Login/LoginWin.cs.meta
new file mode 100644
index 0000000..b51a43c
--- /dev/null
+++ b/Main/UI/Login/LoginWin.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 1d9e1ce1eab28d84188a1c2db2c1c472
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/UI/Main.meta b/Main/UI/Main.meta
new file mode 100644
index 0000000..0efa991
--- /dev/null
+++ b/Main/UI/Main.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 35cec4a6bce278e4b9c8efc66988e0e2
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/UI/Main/MainWin.cs b/Main/UI/Main/MainWin.cs
new file mode 100644
index 0000000..5164b2e
--- /dev/null
+++ b/Main/UI/Main/MainWin.cs
@@ -0,0 +1,206 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.UI;
+
+/// <summary>
+/// 娓告垙涓荤晫闈�
+/// </summary>
+public class MainWin : UIBase
+{
+    private GameObject windowBackground;
+
+    // 搴曢儴鎸夐挳缁�
+    private Button[] bottomTabButtons;
+    
+    // 褰撳墠閫変腑鐨勫簳閮ㄦ爣绛剧储寮�
+    private int currentTabIndex = 0;
+    
+    // 褰撳墠鎵撳紑鐨勫瓙鐣岄潰
+    private UIBase currentSubUI;
+    
+    /// <summary>
+    /// 鍒濆鍖栫粍浠�
+    /// </summary>
+    protected override void InitComponent()
+    {
+        base.InitComponent();
+
+        windowBackground = transform.Find("RawImgBackground").gameObject;
+
+        bottomTabButtons = new Button[5];
+
+        for (int i = 1; i <= 5; i++)
+        {
+            string buttonName = "Buttons/Button" + i;
+            bottomTabButtons[i-1] = transform.Find(buttonName).GetComponent<Button>();
+        }
+
+        // 鍒濆鍖朥I缁勪欢浜嬩欢
+        InitButtonEvents();
+    }
+    
+    /// <summary>
+    /// 鍒濆鍖朥I缁勪欢浜嬩欢
+    /// </summary>
+    private void InitButtonEvents()
+    {
+        // 鍒濆鍖栧簳閮ㄦ寜閽�
+        for (int i = 0; i < bottomTabButtons.Length; i++)
+        {
+            int index = i; // 鎹曡幏绱㈠紩
+            bottomTabButtons[i].onClick.AddListener(() => {
+                OnBottomTabButtonClicked(index);
+            });
+        }
+    }
+    
+    protected override void OnOpen()
+    {
+        base.OnOpen();
+        
+        // 榛樿閫変腑绗竴涓爣绛�
+        SelectBottomTab(0);
+
+        // 鍒锋柊UI
+        Refresh();
+    }
+    
+    public override void Refresh()
+    {
+        UpdatePlayerInfo();
+        UpdateCurrency();
+    }
+    
+    /// <summary>
+    /// 鏇存柊鐜╁淇℃伅
+    /// </summary>
+    private void UpdatePlayerInfo()
+    {
+        // 浠庣帺瀹舵暟鎹腑鑾峰彇淇℃伅骞舵洿鏂癠I
+        // 渚嬪锛�
+        // playerNameText.text = PlayerData.Instance.Name;
+        // playerLevelText.text = "Lv." + PlayerData.Instance.Level;
+        // powerText.text = PlayerData.Instance.Power.ToString();
+        // expSlider.value = PlayerData.Instance.ExpRatio;
+    }
+    
+    /// <summary>
+    /// 鏇存柊璐у竵淇℃伅
+    /// </summary>
+    private void UpdateCurrency()
+    {
+        // 浠庣帺瀹舵暟鎹腑鑾峰彇璐у竵淇℃伅骞舵洿鏂癠I
+        // 渚嬪锛�
+        // goldText.text = PlayerData.Instance.Gold.ToString();
+        // diamondText.text = PlayerData.Instance.Diamond.ToString();
+        // energyText.text = PlayerData.Instance.Energy + "/" + PlayerData.Instance.MaxEnergy;
+    }
+    
+    /// <summary>
+    /// 搴曢儴鏍囩鎸夐挳鐐瑰嚮
+    /// </summary>
+    private void OnBottomTabButtonClicked(int index)
+    {
+        SelectBottomTab(index);
+    }
+    
+    /// <summary>
+    /// 閫夋嫨搴曢儴鏍囩
+    /// </summary>
+    private void SelectBottomTab(int index)
+    {
+        // 濡傛灉鐐瑰嚮褰撳墠宸查�変腑鐨勬爣绛撅紝涓嶅仛澶勭悊
+        if (currentTabIndex == index && currentSubUI != null)
+        {
+            return;
+        }
+        
+        // 鏇存柊褰撳墠閫変腑鐨勬爣绛剧储寮�
+        currentTabIndex = index;
+        
+        // 鏇存柊鎸夐挳鐘舵��
+        UpdateButtonsState();
+        
+        // 鍏抽棴褰撳墠鎵撳紑鐨勫瓙鐣岄潰
+        CloseCurrentSubUI();
+        
+        // 鏍规嵁閫変腑鐨勬爣绛炬墦寮�瀵瑰簲鐨勭晫闈�
+        OpenSubUIByTabIndex(index);
+    }
+    
+    /// <summary>
+    /// 鏇存柊鎸夐挳鐘舵��
+    /// </summary>
+    private void UpdateButtonsState()
+    {
+        // 閬嶅巻鎵�鏈夋寜閽紝璁剧疆閫変腑鐘舵��
+        for (int i = 0; i < bottomTabButtons.Length; i++)
+        {
+            // 杩欓噷鍙互鏍规嵁鏄惁閫変腑璁剧疆鎸夐挳鐨勮瑙夋晥鏋�
+            // 渚嬪锛氭敼鍙樺浘鐗囥�侀鑹茬瓑
+            // bottomTabButtons[i].GetComponent<Image>().color = (i == currentTabIndex) ? Color.blue : Color.white;
+
+            // 鎴栬�呮縺娲�/绂佺敤閫変腑鍥炬爣
+            bottomTabButtons[i].image.color = (i == currentTabIndex) ?  Color.white : Color.gray;
+        }
+    }
+    
+    /// <summary>
+    /// 鍏抽棴褰撳墠鎵撳紑鐨勫瓙鐣岄潰
+    /// </summary>
+    private void CloseCurrentSubUI()
+    {
+        if (currentSubUI != null)
+        {
+            // 鍏抽棴褰撳墠鐣岄潰
+            UIManager.Instance.CloseWindow(currentSubUI);
+            currentSubUI = null;
+        }
+    }
+
+    /// <summary>
+    /// 鏍规嵁鏍囩绱㈠紩鎵撳紑瀵瑰簲鐨勫瓙鐣岄潰
+    /// </summary>
+    private void OpenSubUIByTabIndex(int index)
+    {
+        Debug.Log("鎵撳紑瀛愮晫闈� : " + index);
+
+        // 涓诲煄 闃靛 鍚岀洘 绂忓埄 鍐掗櫓
+
+        //鏍规嵁绱㈠紩鎵撳紑涓嶅悓鐨勭晫闈�
+         switch (index)
+        {
+            case 0:
+                // 渚嬪锛氭墦寮�涓婚〉鐣岄潰
+                // currentSubUI = UIManager.Instance.OpenUI<HomeUI>();
+                Debug.Log("鎵撳紑涓诲煄鐣岄潰");
+                break;
+            case 1:
+                // 渚嬪锛氭墦寮�瑙掕壊鐣岄潰
+                // currentSubUI = UIManager.Instance.OpenUI<CharacterUI>();
+                Debug.Log("鎵撳紑闃靛鐣岄潰");
+                break;
+            case 2:
+                // 渚嬪锛氭墦寮�鑳屽寘鐣岄潰
+                // currentSubUI = UIManager.Instance.OpenUI<BagUI>();
+                Debug.Log("鎵撳紑鍚岀洘鐣岄潰");
+                break;
+            case 3:
+                // 渚嬪锛氭墦寮�浠诲姟鐣岄潰
+                // currentSubUI = UIManager.Instance.OpenUI<QuestUI>();
+                Debug.Log("鎵撳紑绂忓埄鐣岄潰");
+                break;
+            case 4:
+                // 渚嬪锛氭墦寮�璁剧疆鐣岄潰
+                currentSubUI = UIManager.Instance.OpenWindow<PlaceWin>();
+                Debug.Log("鎵撳紑鍐掗櫓鐣岄潰");
+
+                windowBackground.SetActive(false);
+                break;
+            default:
+                Debug.LogWarning("鏈煡鐨勬爣绛剧储寮�: " + index);
+                break;
+        }
+    }
+}
\ No newline at end of file
diff --git a/Main/UI/Main/MainWin.cs.meta b/Main/UI/Main/MainWin.cs.meta
new file mode 100644
index 0000000..455e629
--- /dev/null
+++ b/Main/UI/Main/MainWin.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 0b14b415a3ac64548a78d163d6cb7e33
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/UI/Place.meta b/Main/UI/Place.meta
new file mode 100644
index 0000000..29907a9
--- /dev/null
+++ b/Main/UI/Place.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 2a75dbf92ff839445b4bf6be823add40
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/UI/Place/PlaceWin.cs b/Main/UI/Place/PlaceWin.cs
new file mode 100644
index 0000000..a93134d
--- /dev/null
+++ b/Main/UI/Place/PlaceWin.cs
@@ -0,0 +1,62 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.UI;
+
+/// <summary>
+/// 鍦烘櫙鐣岄潰
+/// </summary>
+public class PlaceWin : UIBase
+{
+    protected Button btnExplore;
+
+    // protected 
+
+    /// <summary>
+    /// 鍒濆鍖栫粍浠�
+    /// </summary>
+    protected override void InitComponent()
+    {
+        base.InitComponent();
+        
+        // 鍦ㄨ繖閲屽垵濮嬪寲缁勪欢
+        btnExplore = transform.Find("BtnExplore").GetComponent<Button>();
+        btnExplore.onClick.AddListener(OnExploreClick);
+    }
+    
+    
+    /// <summary>
+    /// 绐楀彛鎵撳紑鏃惰皟鐢�
+    /// </summary>
+    protected override void OnOpen()
+    {
+        base.OnOpen();
+        
+        // 绐楀彛鎵撳紑鏃剁殑閫昏緫
+        
+    }
+    
+    /// <summary>
+    /// 绐楀彛鍏抽棴鏃惰皟鐢�
+    /// </summary>
+    protected override void OnClose()
+    {
+        base.OnClose();
+        
+        // 绐楀彛鍏抽棴鏃剁殑閫昏緫
+        
+    }
+    
+    /// <summary>
+    /// 鍒锋柊鐣岄潰
+    /// </summary>
+    public override void Refresh()
+    {
+        // 鍒锋柊鐣岄潰鐨勯�昏緫
+    }
+
+    private void OnExploreClick()
+    {
+        // UIManager.Instance.OpenUI<ExploreWin>();
+    }
+}
diff --git a/Main/UI/Place/PlaceWin.cs.meta b/Main/UI/Place/PlaceWin.cs.meta
new file mode 100644
index 0000000..ad66f43
--- /dev/null
+++ b/Main/UI/Place/PlaceWin.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 846b941e24d55594fac435ba7031cfa9
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/UI/UIBase.cs b/Main/UI/UIBase.cs
index 84e3717..d2e6a02 100644
--- a/Main/UI/UIBase.cs
+++ b/Main/UI/UIBase.cs
@@ -1,7 +1,8 @@
 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
-using DG.Tweening; // DOTween 鎻掍欢寮曠敤
+using DG.Tweening;
+using UnityEngine.UI; // DOTween 鎻掍欢寮曠敤
 
 public enum UILayer
 {
@@ -23,41 +24,44 @@
     SlideFromRight // 浠庡彸渚ф粦鍏�
 }
 
+[RequireComponent(typeof(Canvas))]
+[RequireComponent(typeof(CanvasGroup))]
+[RequireComponent(typeof(CanvasScaler))]
 public class UIBase : MonoBehaviour
 {
     #region 灞炴�у拰鍙橀噺
 
     // UI鍩烘湰灞炴��
     [SerializeField] public UILayer uiLayer = UILayer.Mid;
-    [SerializeField] public string uiName;
+    [SerializeField][HideInInspector] public string uiName;
     [SerializeField] public bool isMainUI = false;
-    
+
     // 鎸佷箙鍖栫浉鍏�
     [SerializeField] public bool isPersistent = false;
-    [SerializeField] public int maxIdleRounds = 20;
-    
+    [SerializeField][HideInInspector] public int maxIdleRounds = 20;
+
     // 鍔ㄧ敾鐩稿叧
-    [SerializeField] public UIAnimationType openAnimationType = UIAnimationType.FadeInOut;
-    [SerializeField] public UIAnimationType closeAnimationType = UIAnimationType.FadeInOut;
-    [SerializeField] public float animationDuration = 0.3f;
-    [SerializeField] public Ease animationEase = Ease.OutQuad; // 纭繚浣跨敤 DG.Tweening.Ease
-    
+    [SerializeField] public UIAnimationType openAnimationType = UIAnimationType.None;
+    [SerializeField] public UIAnimationType closeAnimationType = UIAnimationType.None;
+    [SerializeField][HideInInspector] public float animationDuration = 0.3f;
+    [SerializeField][HideInInspector] public Ease animationEase = Ease.OutQuad; // 纭繚浣跨敤 DG.Tweening.Ease
+
     // 杩愯鏃剁姸鎬�
     [HideInInspector] public int lastUsedRound = 0;
     [HideInInspector] public UIBase parentUI;
-    
+
     // 瀛怳I绠$悊
     [HideInInspector] public List<UIBase> childrenUI = new List<UIBase>();
-    
+
     // 鍐呴儴鐘舵��
     protected bool isActive = false;
     protected bool isAnimating = false;
-    
+
     // 缁勪欢寮曠敤
     protected Canvas canvas;
     protected CanvasGroup canvasGroup;
     protected RectTransform rectTransform;
-    
+
     // 鍔ㄧ敾鐩稿叧
     protected Vector3 originalScale;
     protected Vector3 originalPosition;
@@ -71,10 +75,10 @@
     {
         // 纭繚 DOTween 宸插垵濮嬪寲
         DOTween.SetTweensCapacity(500, 50);
-        
+
         // 鍦ˋwake涓繘琛屽熀鏈垵濮嬪寲
         InitComponent();
-        
+
         // 淇濆瓨鍘熷鍊肩敤浜庡姩鐢�
         if (rectTransform != null)
         {
@@ -87,7 +91,7 @@
     {
         // 瀛愮被鍙互閲嶅啓姝ゆ柟娉曡繘琛岄澶栧垵濮嬪寲
     }
-    
+
     protected virtual void OnDestroy()
     {
         // 纭繚鍔ㄧ敾琚纭竻鐞�
@@ -111,32 +115,25 @@
         {
             canvas = gameObject.AddComponent<Canvas>();
         }
-        
+
         // 璁剧疆Canvas灞炴��
         canvas.overrideSorting = true;
-        
+
         // 鑾峰彇鎴栨坊鍔燙anvasGroup缁勪欢
         canvasGroup = GetComponent<CanvasGroup>();
         if (canvasGroup == null)
         {
             canvasGroup = gameObject.AddComponent<CanvasGroup>();
         }
-        
+
         // 娣诲姞GraphicRaycaster缁勪欢锛堝鏋滄病鏈夛級
         if (GetComponent<UnityEngine.UI.GraphicRaycaster>() == null)
         {
             gameObject.AddComponent<UnityEngine.UI.GraphicRaycaster>();
         }
-        
+
         // 鑾峰彇RectTransform缁勪欢
         rectTransform = GetComponent<RectTransform>();
-    }
-    
-    // 鍒濆鍖朥I
-    public virtual void Init()
-    {
-        // 纭繚缁勪欢宸插垵濮嬪寲
-        InitComponent();
     }
 
     #endregion
@@ -151,63 +148,61 @@
             canvas.sortingOrder = order;
         }
     }
-    
+
     // 鎵撳紑UI
-    public virtual void Open()
+    public virtual void HandleOpen()
     {
         // 濡傛灉姝e湪鎾斁鍔ㄧ敾锛屽厛鍋滄
         StopCurrentAnimation();
-        
+
         gameObject.SetActive(true);
-        
+        isActive = true;
+
         // 鏍规嵁鍔ㄧ敾绫诲瀷鎾斁鎵撳紑鍔ㄧ敾
         PlayOpenAnimation();
-        
-        isActive = true;
+
         OnOpen();
+
     }
-    
+
     // 鍏抽棴UI
-    public virtual void Close()
+    public virtual void HandleClose()
     {
         // 濡傛灉姝e湪鎾斁鍔ㄧ敾锛屽厛鍋滄
         StopCurrentAnimation();
-        
+
         // 鏍规嵁鍔ㄧ敾绫诲瀷鎾斁鍏抽棴鍔ㄧ敾
         PlayCloseAnimation();
-        
-        isActive = false;
+
         OnClose();
-        
-        // 鍏抽棴鎵�鏈夊瓙UI
-        for (int i = childrenUI.Count - 1; i >= 0; i--)
-        {
-            if (childrenUI[i] != null && childrenUI[i].isActive)
-            {
-                childrenUI[i].Close();
-            }
-        }
+        gameObject.SetActive(false);
+        isActive = false;
     }
-    
+
+    public void CloseWindow()
+    {
+        UIManager.Instance.CloseWindow(this);
+    }
+
     // 鍒锋柊UI
     public virtual void Refresh()
     {
         // 瀛愮被鍙互閲嶅啓姝ゆ柟娉曞疄鐜癠I鍒锋柊閫昏緫
     }
-    
+
     // 閿�姣乁I
     public virtual void Destroy()
     {
         // 鍋滄鎵�鏈夊姩鐢�
         StopCurrentAnimation();
-        
+
         ClearChildrenUI();
-        
+
         if (parentUI != null)
         {
             parentUI.RemoveChildUI(this);
         }
-        
+
         Destroy(gameObject);
     }
 
@@ -225,7 +220,7 @@
         }
         isAnimating = false;
     }
-    
+
     // 鎾斁鎵撳紑鍔ㄧ敾
     protected virtual void PlayOpenAnimation()
     {
@@ -240,9 +235,9 @@
             }
             return;
         }
-        
+
         isAnimating = true;
-        
+
         // 鍒濆鍖栧姩鐢诲墠鐨勭姸鎬�
         switch (openAnimationType)
         {
@@ -254,7 +249,7 @@
                     canvasGroup.blocksRaycasts = false;
                 }
                 break;
-                
+
             case UIAnimationType.ScaleInOut:
                 if (rectTransform != null)
                 {
@@ -267,7 +262,7 @@
                     canvasGroup.blocksRaycasts = false;
                 }
                 break;
-                
+
             case UIAnimationType.SlideFromTop:
                 if (rectTransform != null)
                 {
@@ -282,7 +277,7 @@
                     canvasGroup.blocksRaycasts = false;
                 }
                 break;
-                
+
             case UIAnimationType.SlideFromBottom:
                 if (rectTransform != null)
                 {
@@ -297,7 +292,7 @@
                     canvasGroup.blocksRaycasts = false;
                 }
                 break;
-                
+
             case UIAnimationType.SlideFromLeft:
                 if (rectTransform != null)
                 {
@@ -312,7 +307,7 @@
                     canvasGroup.blocksRaycasts = false;
                 }
                 break;
-                
+
             case UIAnimationType.SlideFromRight:
                 if (rectTransform != null)
                 {
@@ -328,12 +323,12 @@
                 }
                 break;
         }
-        
+
         try
         {
             // 鍒涘缓鍔ㄧ敾搴忓垪
             currentAnimation = DOTween.Sequence();
-            
+
             // 娣诲姞鍔ㄧ敾
             switch (openAnimationType)
             {
@@ -343,7 +338,7 @@
                         currentAnimation.Append(canvasGroup.DOFade(1f, animationDuration).SetEase(animationEase));
                     }
                     break;
-                    
+
                 case UIAnimationType.ScaleInOut:
                     if (rectTransform != null)
                     {
@@ -354,7 +349,7 @@
                         currentAnimation.Join(canvasGroup.DOFade(1f, animationDuration).SetEase(animationEase));
                     }
                     break;
-                    
+
                 case UIAnimationType.SlideFromTop:
                 case UIAnimationType.SlideFromBottom:
                 case UIAnimationType.SlideFromLeft:
@@ -369,11 +364,12 @@
                     }
                     break;
             }
-            
+
             // 鍔ㄧ敾瀹屾垚鍚庣殑鍥炶皟
-            currentAnimation.OnComplete(() => {
+            currentAnimation.OnComplete(() =>
+            {
                 isAnimating = false;
-                
+
                 // 鍚敤浜や簰
                 if (canvasGroup != null)
                 {
@@ -385,7 +381,7 @@
         catch (System.Exception e)
         {
             Debug.LogError($"鎾斁鎵撳紑鍔ㄧ敾鏃跺嚭閿�: {e.Message}");
-            
+
             // 鍑洪敊鏃剁‘淇漊I鍙骞跺彲浜や簰
             if (canvasGroup != null)
             {
@@ -396,7 +392,7 @@
             isAnimating = false;
         }
     }
-    
+
     // 鎾斁鍏抽棴鍔ㄧ敾
     protected virtual void PlayCloseAnimation()
     {
@@ -411,21 +407,21 @@
             }
             return;
         }
-        
+
         isAnimating = true;
-        
+
         // 绂佺敤浜や簰锛屼絾淇濇寔鍙
         if (canvasGroup != null)
         {
             canvasGroup.interactable = false;
             canvasGroup.blocksRaycasts = false;
         }
-        
+
         try
         {
             // 鍒涘缓鍔ㄧ敾搴忓垪
             currentAnimation = DOTween.Sequence();
-            
+
             // 娣诲姞鍔ㄧ敾
             switch (closeAnimationType)
             {
@@ -435,7 +431,7 @@
                         currentAnimation.Append(canvasGroup.DOFade(0f, animationDuration).SetEase(animationEase));
                     }
                     break;
-                    
+
                 case UIAnimationType.ScaleInOut:
                     if (rectTransform != null)
                     {
@@ -446,7 +442,7 @@
                         currentAnimation.Join(canvasGroup.DOFade(0f, animationDuration).SetEase(animationEase));
                     }
                     break;
-                    
+
                 case UIAnimationType.SlideFromTop:
                     if (rectTransform != null)
                     {
@@ -459,7 +455,7 @@
                         currentAnimation.Join(canvasGroup.DOFade(0f, animationDuration).SetEase(animationEase));
                     }
                     break;
-                    
+
                 case UIAnimationType.SlideFromBottom:
                     if (rectTransform != null)
                     {
@@ -472,7 +468,7 @@
                         currentAnimation.Join(canvasGroup.DOFade(0f, animationDuration).SetEase(animationEase));
                     }
                     break;
-                    
+
                 case UIAnimationType.SlideFromLeft:
                     if (rectTransform != null)
                     {
@@ -485,7 +481,7 @@
                         currentAnimation.Join(canvasGroup.DOFade(0f, animationDuration).SetEase(animationEase));
                     }
                     break;
-                    
+
                 case UIAnimationType.SlideFromRight:
                     if (rectTransform != null)
                     {
@@ -499,11 +495,12 @@
                     }
                     break;
             }
-            
+
             // 鍔ㄧ敾瀹屾垚鍚庣殑鍥炶皟
-            currentAnimation.OnComplete(() => {
+            currentAnimation.OnComplete(() =>
+            {
                 isAnimating = false;
-                
+
                 // 纭繚UI涓嶅彲瑙佷笖涓嶅彲浜や簰
                 if (canvasGroup != null)
                 {
@@ -511,7 +508,7 @@
                     canvasGroup.interactable = false;
                     canvasGroup.blocksRaycasts = false;
                 }
-                
+
                 // 寤惰繜绂佺敤GameObject锛岄伩鍏嶉绻佺殑Enable/Disable鎿嶄綔
                 // 濡傛灉闇�瑕佺珛鍗抽噴鏀捐祫婧愶紝鍙互鍙栨秷娉ㄩ噴涓嬮潰鐨勪唬鐮�
                 // gameObject.SetActive(false);
@@ -520,7 +517,7 @@
         catch (System.Exception e)
         {
             Debug.LogError($"鎾斁鍏抽棴鍔ㄧ敾鏃跺嚭閿�: {e.Message}");
-            
+
             // 鍑洪敊鏃剁‘淇漊I涓嶅彲瑙佷笖涓嶅彲浜や簰
             if (canvasGroup != null)
             {
@@ -531,7 +528,7 @@
             isAnimating = false;
         }
     }
-    
+
     #endregion
 
     #region 瀛怳I绠$悊
@@ -545,7 +542,7 @@
             childUI.parentUI = this;
         }
     }
-    
+
     // 绉婚櫎瀛怳I
     public void RemoveChildUI(UIBase childUI)
     {
@@ -555,7 +552,7 @@
             childUI.parentUI = null;
         }
     }
-    
+
     // 娓呯┖鎵�鏈夊瓙UI
     public void ClearChildrenUI()
     {
@@ -566,7 +563,7 @@
                 childrenUI[i].parentUI = null;
             }
         }
-        
+
         childrenUI.Clear();
     }
 
@@ -579,7 +576,7 @@
     {
         // 瀛愮被鍙互閲嶅啓姝ゆ柟娉曞疄鐜版墦寮�UI鏃剁殑閫昏緫
     }
-    
+
     // UI鍏抽棴鏃剁殑鍥炶皟
     protected virtual void OnClose()
     {
diff --git a/Main/UI/UIManager.cs b/Main/UI/UIManager.cs
index 56abadf..297144b 100644
--- a/Main/UI/UIManager.cs
+++ b/Main/UI/UIManager.cs
@@ -38,7 +38,7 @@
     #region 鍒濆鍖栨柟娉�
     
     // 鍒濆鍖�
-    private void Init()
+    public void Init()
     {
         InitUIRoot();
     }
@@ -46,7 +46,18 @@
     // 鍒涘缓UI鏍硅妭鐐�
     private void InitUIRoot()
     {
-        GameObject root = GameObject.Instantiate(Resources.Load<GameObject>("UIRoot"));
+        GameObject root = GameObject.Find("UIRoot");
+        if (root == null)
+        {
+            root = GameObject.Instantiate(Resources.Load<GameObject>("UI/UIRoot"));
+
+            if (root == null)
+            {
+                Debug.LogError("鏃犳硶鎵惧埌UI鏍硅妭鐐�");
+                return;
+            }
+        }
+
         uiRoot = root.transform;
         uiRoot.position = Vector3.zero;
 
@@ -118,20 +129,21 @@
     }
     
     // 鑾峰彇UI瀹炰緥锛屽鏋滀笉瀛樺湪鍒欒繑鍥瀗ull
-    private UIBase GetUI(string uiName)
+    public T GetUI<T>() where T : UIBase
     {
+        string uiName = typeof(T).Name;
         if (string.IsNullOrEmpty(uiName))
         {
             Debug.LogError("UI鍚嶇О涓虹┖");
             return null;
         }
-        
+
         UIBase ui;
         if (uiDict.TryGetValue(uiName, out ui))
         {
-            return ui;
+            return ui as T;
         }
-        
+
         return null;
     }
     
@@ -171,16 +183,10 @@
     #region UI璧勬簮绠$悊
     
     // 鍔犺浇UI棰勫埗浣�
-    private UIBase LoadUIResource(string uiName)
+    private T LoadUIResource<T>(string uiName) where T : UIBase
+
     {
-        // 杩欓噷鏄祫婧愬姞杞介儴鍒嗭紝鏍规嵁椤圭洰瀹為檯鎯呭喌瀹炵幇
-        // 鍙互浣跨敤Resources.Load鎴栬�呭叾浠栬祫婧愮鐞嗙郴缁�
-
-        // 绀轰緥浠g爜锛屽疄闄呴」鐩腑闇�瑕佹浛鎹负鐪熷疄鐨勮祫婧愬姞杞介�昏緫
-        GameObject prefab = null;
-
-        // TODO: 鍦ㄨ繖閲屽疄鐜拌祫婧愬姞杞介�昏緫
-        // prefab = Resources.Load<GameObject>("UI/" + uiName);
+        GameObject prefab = ResManager.Instance.LoadUI(uiName);
 
         if (prefab == null)
         {
@@ -189,7 +195,8 @@
         }
 
         GameObject uiObject = GameObject.Instantiate(prefab);
-        UIBase uiBase = uiObject.GetComponent<UIBase>();
+        uiObject.name = uiName;
+        T uiBase = uiObject.GetComponent<T>();
 
         if (uiBase == null)
         {
@@ -202,8 +209,6 @@
         // 璁剧疆鐖惰妭鐐逛负UI鏍硅妭鐐�
         uiObject.transform.SetParent(GetTransForLayer(uiBase.uiLayer), false);
 
-        // 鍒濆鍖朥I
-        uiBase.Init();
 
         // 璁剧疆鎺掑簭椤哄簭
         int baseSortingOrder = GetBaseSortingOrderForLayer(uiBase.uiLayer);
@@ -296,8 +301,9 @@
     #region 鍏叡鎺ュ彛鏂规硶
     
     // 鎵撳紑鍗曚釜UI绐楀彛
-    public UIBase OpenWindow(string uiName)
+    public T OpenWindow<T>() where T : UIBase
     {
+        string uiName = typeof(T).Name;
         if (string.IsNullOrEmpty(uiName))
         {
             Debug.LogError("灏濊瘯鎵撳紑绌哄悕绉扮殑UI绐楀彛");
@@ -308,12 +314,12 @@
         currentRound++;
         
         // 鍏堝皾璇曡幏鍙栧凡鍔犺浇鐨刄I
-        UIBase ui = GetUI(uiName);
+        T ui = GetUI<T>();
         
         // 濡傛灉UI涓嶅瓨鍦紝鍒欏姞杞�
         if (ui == null)
         {
-            ui = LoadUIResource(uiName);
+            ui = LoadUIResource<T>(uiName);
             if (ui == null)
                 return null;
                 
@@ -370,7 +376,7 @@
                     }
 
                     // 鍏抽棴褰撳墠UI閾句笂鐨勯潪System灞俇I
-                    topUI.Close();
+                    topUI.HandleClose();
 
                     // 娓呯悊鐖跺瓙鍏崇郴
                     if (topUI.parentUI != null)
@@ -389,7 +395,7 @@
             }
         }
 
-        ui.Open();
+        ui.HandleOpen();
         
         // 濡傛灉鏍堜腑鏈夊叾浠朥I锛屽垯灏嗘爤椤禪I璁句负鐖禪I
         if (!ui.isMainUI && ui.uiLayer != UILayer.System && uiStack.Count > 0)
@@ -449,8 +455,10 @@
             return;
         
         // 鍒涘缓涓�涓垪琛ㄦ潵瀛樺偍闇�瑕佸叧闂殑UI
-        List<UIBase> uisToClose = new List<UIBase>();
-        uisToClose.Add(ui);
+        List<UIBase> uisToClose = new List<UIBase>
+        {
+            ui
+        };
         
         // 閫掑綊鏀堕泦鎵�鏈夊瓙UI
         CollectChildrenUI(ui, uisToClose);
@@ -465,7 +473,7 @@
         foreach (var uiToClose in uisToClose)
         {
             // 鍏抽棴UI
-            uiToClose.Close();
+            uiToClose.HandleClose();
             
             // 娓呯悊鐖跺瓙鍏崇郴
             if (uiToClose.parentUI != null)
@@ -486,19 +494,6 @@
         RemoveFromUIStack(uisToClose);
     }
     
-    // 鍏抽棴鎵�鏈塙I绐楀彛
-    public void CloseAllWindows()
-    {
-        foreach (var ui in uiDict.Values)
-        {
-            if (ui != null)
-            {
-                ui.Close();
-            }
-        }
-        
-        uiStack.Clear();
-    }
 
     // 杩斿洖涓婁竴绾I
     public void GoBack()
@@ -508,7 +503,8 @@
         
         // 鍏抽棴褰撳墠UI
         UIBase currentUI = uiStack.Pop();
-        currentUI.Close();
+
+        CloseWindow(currentUI);
         
         // 鏇存柊鎺掑簭椤哄簭
         UpdateUISortingOrder();
@@ -545,7 +541,9 @@
     // 閿�姣佹墍鏈塙I
     public void DestroyAllUI()
     {
-        foreach (var ui in uiDict.Values)
+        List<string> uiNames = new List<string>(uiDict.Keys);
+
+        foreach (var ui in uiNames)
         {
             if (ui != null)
             {
diff --git a/Utility/DontDestroyOnLoad.cs b/Utility/DontDestroyOnLoad.cs
new file mode 100644
index 0000000..7f3489e
--- /dev/null
+++ b/Utility/DontDestroyOnLoad.cs
@@ -0,0 +1,11 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+public class DontDestroyOnLoad : MonoBehaviour
+{
+    void Awake()
+    {
+        DontDestroyOnLoad(gameObject);
+    }
+}
diff --git a/Utility/DontDestroyOnLoad.cs.meta b/Utility/DontDestroyOnLoad.cs.meta
new file mode 100644
index 0000000..d8483e0
--- /dev/null
+++ b/Utility/DontDestroyOnLoad.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ebddc3e48e1baa844a56615981c5c152
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

--
Gitblit v1.8.0