角色能力,存档

This commit is contained in:
2026-05-19 11:50:21 +08:00
parent d25f237e76
commit 2dcb7a961a
136 changed files with 36035 additions and 27551 deletions

View File

@@ -17,8 +17,9 @@ namespace BaseGames.Editor
///
/// 新格式:
/// [新 CameraArea GO]CameraArea 组件_visibleBounds = 本地 Rect
/// ├─ AreaBoundaryPolygonCollider2DisTrigger=true,对应旧 Confiner
/// ─ TriggerZoneCameraTriggerZone + PolygonCollider2D对应旧 TriggerRegion
/// ├─ AreaBoundaryBoxCollider对应旧 Confiner
/// ─ TriggerZoneCameraTriggerZone + PolygonCollider2D对应旧 TriggerRegion
/// └─ VCam_xxxCinemachineCamera + 所有扩展组件,专属虚拟相机)
///
/// 菜单BaseGames → Camera → 相机区域迁移工具
/// </summary>
@@ -32,9 +33,10 @@ namespace BaseGames.Editor
}
// ── 设置字段 ──────────────────────────────────────────────────────────
private Transform _sourcesParent; // 旧 Zone_xxx 的父节点(通常名为 Zones
private Transform _targetParent; // 新对象放置位置(留空 = 与旧区域同级)
private CameraLensConfigSO _lensConfig; // 绑定到新 CameraArea._lensConfig
private Transform _sourcesParent; // 旧 Zone_xxx 的父节点(通常名为 Zones
private Transform _targetParent; // 新对象放置位置(留空 = 与旧区域同级)
private CameraLensConfigSO _lensConfig; // 绑定到新 CameraArea._lensConfig
private bool _createDedicatedVCam = true; // 为每个区域创建专属 CinemachineCamera
// ── 运行时状态 ────────────────────────────────────────────────────────
@@ -86,6 +88,12 @@ namespace BaseGames.Editor
new GUIContent("镜头配置 SO", "赋给所有新 CameraArea._lensConfig留空则不赋值"),
_lensConfig, typeof(CameraLensConfigSO), false);
_createDedicatedVCam = EditorGUILayout.Toggle(
new GUIContent("创建专属 VCam",
"为每个迁移区域创建子节点 CinemachineCamera含所有扩展组件\n" +
"并绑定到 CameraArea._dedicatedCamera。"),
_createDedicatedVCam);
EditorGUILayout.Space(8);
@@ -220,17 +228,24 @@ namespace BaseGames.Editor
foreach (Transform child in _sourcesParent)
{
Debug.Log($"[root]:{child.name}");
// 旧 Zone 的标识:子节点直属,且挂有 BoxCollider2D
var box = child.GetComponent<BoxCollider2D>();
if (box == null) continue;
var entry = new ZoneEntry { ZoneObj = child.gameObject, VisibleBox = box };
// 收集触发多边形顶点TriggerRegion 子节点的各个点对象)
Transform triggerRoot = FindChildContaining(child, "TriggerRegion");
if (triggerRoot != null)
foreach (Transform pt in triggerRoot)
// 收集触发多边形顶点——xxx_TriggerRegion 下每个子节点的世界坐标即一个顶点,
// 按子节点顺序依次连线围成多边形触发区域。
Transform triggerRoot = FindChildContaining(child, "Trigger");
if (triggerRoot != null){
Debug.Log($"[trigger]:{triggerRoot.name}");
foreach (Transform pt in triggerRoot){
Debug.Log($"{pt.name}");
entry.TriggerWorldPts.Add((Vector2)pt.position);
}
}
// 读取限位碰撞体Zone_xxx_Confiner 上的 Collider2D
Transform confinerT = FindChildContaining(child, "Confiner");
@@ -298,20 +313,20 @@ namespace BaseGames.Editor
soArea.FindProperty("_lensConfig").objectReferenceValue = _lensConfig;
soArea.ApplyModifiedProperties();
// ── 3. 创建 AreaBoundary限位多边形isTrigger = true──────────
// ── 3. 创建 AreaBoundary限位体积 BoxCollider─────────────────────────────
GameObject boundaryGO = new GameObject($"{zoneGO.name}_AreaBoundary");
Undo.RegisterCreatedObjectUndo(boundaryGO, "Migrate Camera Zone");
boundaryGO.transform.SetParent(areaGO.transform, worldPositionStays: false);
boundaryGO.transform.localPosition = Vector3.zero;
PolygonCollider2D confinerPoly = boundaryGO.AddComponent<PolygonCollider2D>();
confinerPoly.isTrigger = true;
confinerPoly.pathCount = 1;
confinerPoly.SetPath(0, BuildConfinerPath(entry, worldPos, localBounds));
BoxCollider confinerBox = boundaryGO.AddComponent<BoxCollider>();
confinerBox.isTrigger = true;
confinerBox.center = new Vector3(0f, 0f, -10f); // Z 占位符SyncConfiner 会立即重算
confinerBox.size = new Vector3(localBounds.width, localBounds.height, 1f);
// 绑定 _confinerCollider
soArea.Update();
soArea.FindProperty("_confinerCollider").objectReferenceValue = confinerPoly;
soArea.FindProperty("_confinerCollider").objectReferenceValue = confinerBox;
soArea.ApplyModifiedProperties();
EditorUtility.SetDirty(area);
@@ -330,9 +345,10 @@ namespace BaseGames.Editor
// AddComponent 会因 [RequireComponent] 自动添加 PolygonCollider2D
CameraTriggerZone triggerComp = triggerGO.AddComponent<CameraTriggerZone>();
PolygonCollider2D triggerPoly = triggerGO.GetComponent<PolygonCollider2D>();
// 将旧触发多边形路径(本地坐标,相对于新 CameraArea 世界位置)直接赋给 PolygonCollider2D
Vector2[] triggerPath = BuildTriggerPath(entry, worldPos, localBounds);
triggerPoly.isTrigger = true;
triggerPoly.pathCount = 1;
triggerPoly.SetPath(0, BuildTriggerPath(entry, worldPos, localBounds));
triggerPoly.SetPath(0, triggerPath);
// _targetArea → 指向刚创建的 CameraArea
var soTrigger = new SerializedObject(triggerComp);
@@ -340,7 +356,11 @@ namespace BaseGames.Editor
soTrigger.ApplyModifiedProperties();
EditorUtility.SetDirty(triggerComp);
// ── 5. 处理旧对象 ──────────────────────────────────────────────
// ── 5. 创建专属 VCam每区域独立相机─────────────────────────────
if (_createDedicatedVCam)
CameraAreaEditor.CreateDedicatedVCamForArea(area);
// ── 6. 处理旧对象 ──────────────────────────────────────────────
// 先记录原始激活状态,再对旧对象做处理,避免 SetActive(false) 后误读
bool wasActive = zoneGO.activeSelf;
@@ -356,8 +376,8 @@ namespace BaseGames.Editor
Debug.Log($"[迁移工具] {zoneGO.name} → {areaGO.name} " +
$"可视 {localBounds.width:F0}×{localBounds.height:F0} " +
$"触发 {triggerPoly.GetTotalPointCount()} pt " +
$"限位 {confinerPoly.GetTotalPointCount()} pt");
$"触发 PolygonCollider2D ({triggerPath.Length} 点) " +
$"限位 BoxCollider ({confinerBox.size.x:F1}×{confinerBox.size.y:F1})");
}
// ── 限位多边形路径 ────────────────────────────────────────────────────
@@ -405,14 +425,40 @@ namespace BaseGames.Editor
{
if (entry.TriggerWorldPts.Count >= 3)
{
var path = new Vector2[entry.TriggerWorldPts.Count];
for (int i = 0; i < path.Length; i++)
path[i] = entry.TriggerWorldPts[i] - (Vector2)areaWorldPos;
return path;
// 将世界坐标转换为 areaGO 本地坐标
var localPts = new Vector2[entry.TriggerWorldPts.Count];
for (int i = 0; i < localPts.Length; i++)
localPts[i] = entry.TriggerWorldPts[i] - (Vector2)areaWorldPos;
// 按照质心角度排序,确保顶点顺序能够围成合法多边形
return SortPointsByAngle(localPts);
}
return RectToPolygon(fallback);
}
/// <summary>
/// 将一组点按照围绕质心的角度(逆时针)排序,使其能够围成合法的简单多边形。
/// 适用于凸多边形及质心在多边形内部的凹多边形。
/// </summary>
private static Vector2[] SortPointsByAngle(Vector2[] points)
{
// 计算质心
Vector2 centroid = Vector2.zero;
foreach (var p in points)
centroid += p;
centroid /= points.Length;
// 按照相对质心的极角升序排列(逆时针)
var sorted = new System.Collections.Generic.List<Vector2>(points);
sorted.Sort((a, b) =>
{
float angleA = Mathf.Atan2(a.y - centroid.y, a.x - centroid.x);
float angleB = Mathf.Atan2(b.y - centroid.y, b.x - centroid.x);
return angleA.CompareTo(angleB);
});
return sorted.ToArray();
}
/// <summary>
/// 手动计算 BoxCollider2D 的世界 AABB不依赖 .boundsinactive 对象上 .bounds 无效)。
/// </summary>