摄像机区域的优化
This commit is contained in:
@@ -385,46 +385,101 @@ namespace BaseGames.Editor
|
||||
MarkDirtyAndLog("Room Transition", go, report);
|
||||
}
|
||||
|
||||
[MenuItem("BaseGames/Scene/Place/Room Camera", priority = 140)]
|
||||
public static void PlaceRoomCamera()
|
||||
[MenuItem("BaseGames/Scene/Place/Camera Area", priority = 140)]
|
||||
public static void PlaceCameraArea() => PlaceCameraArea("CameraArea");
|
||||
|
||||
/// <param name="areaName">
|
||||
/// 生成的 CameraArea GameObject 名称。
|
||||
/// 子节点 AreaBoundary 和 TriggerZone 将以此为前缀命名(如 MyZone_AreaBoundary)。
|
||||
/// </param>
|
||||
/// <param name="parent">生成的 GameObject 所挂载的父节点(为 null 时放置于场景根节点)。</param>
|
||||
public static void PlaceCameraArea(string areaName, Transform parent = null)
|
||||
{
|
||||
var report = new List<string>();
|
||||
int undoGroup = Undo.GetCurrentGroup();
|
||||
Undo.SetCurrentGroupName("Place Camera Area (+ TriggerZone)");
|
||||
|
||||
GameObject go = new GameObject("RoomCamera");
|
||||
Undo.RegisterCreatedObjectUndo(go, "Place Room Camera");
|
||||
go.transform.position = GetDropPosition();
|
||||
Vector3 pos = GetDropPosition();
|
||||
|
||||
CinemachineCamera cinemachine = GetOrAddComponent<CinemachineCamera>(go);
|
||||
RoomCamera roomCamera = GetOrAddComponent<RoomCamera>(go);
|
||||
CinemachineConfiner2D confiner = GetOrAddComponent<CinemachineConfiner2D>(go);
|
||||
// ── CameraArea ─────────────────────────────────────────────────────
|
||||
GameObject go = new GameObject(areaName);
|
||||
Undo.RegisterCreatedObjectUndo(go, "Place Camera Area");
|
||||
go.transform.position = pos;
|
||||
if (parent != null)
|
||||
Undo.SetTransformParent(go.transform, parent, "Parent Camera Area");
|
||||
|
||||
// RoomBoundary child — defines the camera confinement area
|
||||
Transform boundaryT = GetOrCreateChild(go.transform, "RoomBoundary");
|
||||
CameraArea cameraArea = GetOrAddComponent<CameraArea>(go);
|
||||
|
||||
// AreaBoundary child — 提供 CinemachineConfiner2D 所需的限位多边形(isTrigger = true,仅作为相机约束边界)
|
||||
Transform boundaryT = GetOrCreateChild(go.transform, $"{areaName}_AreaBoundary");
|
||||
PolygonCollider2D boundaryCollider = GetOrAddComponent<PolygonCollider2D>(boundaryT.gameObject);
|
||||
boundaryCollider.isTrigger = true;
|
||||
boundaryCollider.pathCount = 1;
|
||||
// 顶点必须逆时针(CCW)排列:Cinemachine 底层 Clipper 库对 CW 多边形(area<0)会取反 delta,
|
||||
// 导致向外膨胀而非向内收缩,相机将不受限制地跑出边界。
|
||||
boundaryCollider.SetPath(0, new Vector2[]
|
||||
{
|
||||
new Vector2(-12f, -6f),
|
||||
new Vector2(-12f, 6f),
|
||||
new Vector2( 12f, 6f),
|
||||
new Vector2( 12f, -6f),
|
||||
new Vector2(-12f, -6f), // BL
|
||||
new Vector2( 12f, -6f), // BR
|
||||
new Vector2( 12f, 6f), // TR
|
||||
new Vector2(-12f, 6f), // TL
|
||||
});
|
||||
RoomVisibleArea visibleArea = GetOrAddComponent<RoomVisibleArea>(boundaryT.gameObject);
|
||||
|
||||
AssignReference(roomCamera, "_visibleArea", visibleArea, report);
|
||||
AssignReference(confiner, "m_BoundingShape2D", boundaryCollider, report);
|
||||
AssignReference(cameraArea, "_confinerCollider", boundaryCollider, report);
|
||||
|
||||
// Disable any Camera and AudioListener added by Cinemachine
|
||||
UnityEngine.Camera cam = go.GetComponent<UnityEngine.Camera>();
|
||||
if (cam != null) cam.enabled = false;
|
||||
AudioListener al = go.GetComponent<AudioListener>();
|
||||
if (al != null) { Undo.DestroyObjectImmediate(al); }
|
||||
// ── CameraTriggerZone(配对)─────────────────────────────────────────
|
||||
GameObject zoneGo = new GameObject($"{areaName}_TriggerZone");
|
||||
Undo.RegisterCreatedObjectUndo(zoneGo, "Place Camera Trigger Zone");
|
||||
zoneGo.transform.position = pos;
|
||||
SetLayer(zoneGo, "TriggerZone", report);
|
||||
|
||||
report.Add("将 Player/CameraFollowTarget Transform 拖入 CinemachineCamera.Follow 字段以跟随玩家(或使用 Room Camera Setup 工具批量赋值)。");
|
||||
report.Add("调整 RoomBoundary PolygonCollider2D 顶点以匹配房间边界。");
|
||||
PolygonCollider2D col = GetOrAddComponent<PolygonCollider2D>(zoneGo);
|
||||
col.isTrigger = true;
|
||||
// 默认矩形轮廓(CCW),与 AreaBoundary 默认尺寸一致(可在 Inspector 中编辑顶点调整为任意多边形)
|
||||
col.SetPath(0, new Vector2[]
|
||||
{
|
||||
new Vector2(-12f, -6f), // BL
|
||||
new Vector2( 12f, -6f), // BR
|
||||
new Vector2( 12f, 6f), // TR
|
||||
new Vector2(-12f, 6f), // TL
|
||||
});
|
||||
|
||||
CameraTriggerZone zone = GetOrAddComponent<CameraTriggerZone>(zoneGo);
|
||||
AssignReference(zone, "_targetArea", cameraArea, report);
|
||||
// TriggerZone 归入 CameraArea 节点,方便统一调整与查找
|
||||
Undo.SetTransformParent(zoneGo.transform, go.transform, "Parent TriggerZone to CameraArea");
|
||||
zoneGo.transform.localPosition = Vector3.zero;
|
||||
Undo.CollapseUndoOperations(undoGroup);
|
||||
|
||||
report.Add($"调整 {areaName}_AreaBoundary PolygonCollider2D 顶点以匹配区域边界。");
|
||||
report.Add($"调整 {areaName}_TriggerZone PolygonCollider2D 顶点以匹配入口走廊(支持任意多边形)。");
|
||||
|
||||
// ── 自动关联到同场景 RoomController(若其 _cameraArea 为空)────────
|
||||
#if UNITY_6000_0_OR_NEWER
|
||||
var roomControllers = Object.FindObjectsByType<RoomController>(FindObjectsSortMode.None);
|
||||
#else
|
||||
var roomControllers = Object.FindObjectsOfType<RoomController>();
|
||||
#endif
|
||||
bool autoAssigned = false;
|
||||
foreach (var rc in roomControllers)
|
||||
{
|
||||
// 仅使用反射检查,避免每次都覆盖已绑定的引用
|
||||
var fi = typeof(RoomController).GetField("_cameraArea",
|
||||
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
|
||||
if (fi == null) continue;
|
||||
if (fi.GetValue(rc) != null) continue;
|
||||
|
||||
Undo.RecordObject(rc, "Auto-assign CameraArea to RoomController");
|
||||
fi.SetValue(rc, cameraArea);
|
||||
EditorUtility.SetDirty(rc);
|
||||
report.Add($"✅ 已自动将 {areaName} 关联到 {rc.gameObject.name}.RoomController._cameraArea。");
|
||||
autoAssigned = true;
|
||||
}
|
||||
if (!autoAssigned)
|
||||
report.Add("将此 CameraArea 拖入 RoomController._cameraArea 字段(未找到空 _cameraArea 的 RoomController)。");
|
||||
|
||||
Selection.activeGameObject = go;
|
||||
MarkDirtyAndLog("Room Camera", go, report);
|
||||
MarkDirtyAndLog($"Camera Area (+ TriggerZone): {areaName}", go, report);
|
||||
}
|
||||
|
||||
[MenuItem("BaseGames/Scene/Place/Ground Platform", priority = 150)]
|
||||
@@ -534,28 +589,6 @@ namespace BaseGames.Editor
|
||||
MarkDirtyAndLog("Nav Surface", go, report);
|
||||
}
|
||||
|
||||
[MenuItem("BaseGames/Scene/Place/Camera Trigger Zone", priority = 180)]
|
||||
public static void PlaceCameraTriggerZone()
|
||||
{
|
||||
var report = new List<string>();
|
||||
|
||||
GameObject go = new GameObject("CameraTriggerZone");
|
||||
Undo.RegisterCreatedObjectUndo(go, "Place Camera Trigger Zone");
|
||||
go.transform.position = GetDropPosition();
|
||||
SetLayer(go, "TriggerZone", report);
|
||||
|
||||
BoxCollider2D col = GetOrAddComponent<BoxCollider2D>(go);
|
||||
col.isTrigger = true;
|
||||
col.size = new Vector2(2f, 2f);
|
||||
|
||||
GetOrAddComponent<CameraTriggerZone>(go);
|
||||
|
||||
report.Add("将目标 RoomCamera 拖入 CameraTriggerZone._targetCamera 字段。");
|
||||
|
||||
Selection.activeGameObject = go;
|
||||
MarkDirtyAndLog("Camera Trigger Zone", go, report);
|
||||
}
|
||||
|
||||
[MenuItem("BaseGames/Scene/Place/Obstacle (Static)", priority = 190)]
|
||||
public static void PlaceObstacle()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user