3D: призрак нового здания -- на ближайшем свободном месте, а не на Ратуше в центре камеры

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Alexander
2026-11-05 16:56:44 +01:00
co-authored by Claude Opus 5.5
parent 56b66af0c3
commit c29a4ae708
+27
View File
@@ -540,11 +540,38 @@ public class City3DController : MonoBehaviour, City3DSave.ILive
Vector3 c = cameraRig.target;
ghostX = Mathf.Clamp(Mathf.RoundToInt(c.x - t.W / 2f), 0, City3DLayout.Size - t.W);
ghostY = Mathf.Clamp(Mathf.RoundToInt(c.z - t.H / 2f), 0, City3DLayout.Size - t.H);
// Не на Ратуше и не в чужом здании: ближайшее к центру экрана место, где здание можно поставить
if (FindFreeSpot(t, ghostX, ghostY, out int fx, out int fy, out int frot))
{
ghostX = fx; ghostY = fy; ghostRot = frot;
// камера плавно подъезжает к месту, не меняя приближения
float size = cameraRig.distance / 1.15f;
cameraRig.FocusOn(new Rect(fx + t.W / 2f - size / 2f, fy + t.H / 2f - size / 2f, size, size));
}
EnsureFootprint();
RefreshGround();
UpdateGhost();
}
// Ближайшее свободное место (по кольцам от x0, y0), сначала без поворота, потом с поворотом на 90
bool FindFreeSpot(BuildingType t, int x0, int y0, out int x, out int y, out int rot)
{
for (int r = 0; r < City3DLayout.Size; r++)
for (int dy = -r; dy <= r; dy++)
for (int dx = -r; dx <= r; dx++)
{
if (Mathf.Max(Mathf.Abs(dx), Mathf.Abs(dy)) != r) continue; // только кольцо радиуса r
foreach (int tryRot in new[] { 0, 90 })
if (map.Validate(x0 + dx, y0 + dy, t.W, t.H, tryRot, townHallLevel, null, out _) == PlaceError.None)
{
x = x0 + dx; y = y0 + dy; rot = tryRot;
return true;
}
}
x = x0; y = y0; rot = 0;
return false; // места нет -- призрак там, где камера, красный с причиной
}
void StartMoving(string id)
{
if (!map.TryGetBuilding(id, out var r)) return;