Комнаты: ручные фикс-позиции слотов (Room.SlotPos), по ногам как в дебаге

- Каждый слот может иметь точную позицию (перекрывает авто-распределение)
- Дойка слот раба 1 = (1100, 918)
- Фикс-позиция ставит НОГИ персонажа в координату (совпадает с DEBUG при drag),
  авто-слоты по-прежнему центрируются

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Leonid Pershin
2026-08-04 05:32:57 +03:00
co-authored by Claude Opus 4.8
parent 214d6e3c5b
commit 7a754d618d
+31 -20
View File
@@ -54,9 +54,10 @@ public partial class RoomMap : Node2D
public string[] States; // приоритет состояний-скелетов
public CType[] SlotTypes; // тип, разрешённый в каждом слоте
public Pawn[] SlotOcc; // кто в слоте (null = свободно)
public Vector2?[] SlotPos; // точная позиция слота (null = авто)
public Label Header;
public int Cap => SlotTypes.Length;
public void Init() => SlotOcc = new Pawn[SlotTypes.Length];
public void Init() { SlotOcc = new Pawn[SlotTypes.Length]; SlotPos = new Vector2?[SlotTypes.Length]; }
public int Count() { int n = 0; foreach (var s in SlotOcc) if (s != null) n++; return n; }
public int SlotOf(Pawn p) => System.Array.IndexOf(SlotOcc, p);
public int FreeSlotFor(CType t)
@@ -338,6 +339,11 @@ public partial class RoomMap : Node2D
SlotTypes = new[] { CType.Slave, CType.Slave, CType.Child, CType.Child, CType.Child, CType.Child } },
};
foreach (var r in _rooms) r.Init();
// ручные позиции посадки (фикс, по ногам как в дебаге)
var doyka = _rooms.First(r => r.Type == "Дойка");
doyka.SlotPos[0] = new Vector2(1100, 918); // раб, слот 1
BuildRoomHeaders();
// рамки поверх всех ячеек — читаемость сетки
@@ -502,37 +508,42 @@ public partial class RoomMap : Node2D
private static readonly Vector2 CenterAnchor = new Vector2(640f, 360f); // центр кадра 1280x720
// расставить по слотам: основные (Игрок/Раб/Монстр) в ряд, дети — ниже и мельче
// расставить по слотам: фикс-позиция (SlotPos, по ногам) либо авто-распределение (по центру)
private void LayoutRoom(Room room)
{
bool group = room.Count() >= 2;
var main = new List<int>();
var kids = new List<int>();
for (int i = 0; i < room.Cap; i++)
(room.SlotTypes[i] == CType.Child ? kids : main).Add(i);
PlaceGroup(room, main, group, Cell * 0.74f, 1f);
PlaceGroup(room, kids, group, Cell * 0.9f, 0.55f);
UpdateRoomHeader(room);
}
private void PlaceGroup(Room room, List<int> slots, bool group, float yOff, float scale)
{
int n = slots.Count;
for (int k = 0; k < n; k++)
{
var q = room.SlotOcc[slots[k]];
var q = room.SlotOcc[i];
if (q == null) continue;
float t = n == 1 ? 0.5f : (k + 0.5f) / n;
float sx = room.Col * Cell + t * (room.Span * Cell);
bool child = room.SlotTypes[i] == CType.Child;
bool fixedPos = room.SlotPos != null && room.SlotPos[i].HasValue;
Vector2 pos = fixedPos ? room.SlotPos[i].Value : AutoSlotPos(room, i);
Vector2 anchor = fixedPos ? FootAnchor : CenterAnchor; // фикс — по ногам (как в дебаге)
if (q.Node.GetChildCount() > 0 && q.Node.GetChild(0) is Node2D sc)
sc.Position = -CenterAnchor * CharScale;
q.X = sx;
q.Node.Position = new Vector2(sx, room.Row * Cell + yOff);
sc.Position = -anchor * CharScale;
float scale = child ? 0.55f : 1f;
q.X = pos.X;
q.Node.Position = pos;
q.Node.Scale = new Vector2(scale, scale);
var anims = q.Ap != null ? q.Ap.GetAnimationList() : System.Array.Empty<string>();
string a = PickAction(anims, group);
if (q.Ap != null && a != null) q.Ap.Play(a);
}
UpdateRoomHeader(room);
}
private static Vector2 AutoSlotPos(Room room, int slot)
{
bool child = room.SlotTypes[slot] == CType.Child;
var grp = new List<int>();
for (int i = 0; i < room.Cap; i++)
if ((room.SlotTypes[i] == CType.Child) == child) grp.Add(i);
int idx = grp.IndexOf(slot), n = grp.Count;
float t = n == 1 ? 0.5f : (idx + 0.5f) / n;
float sx = room.Col * Cell + t * (room.Span * Cell);
float yOff = child ? Cell * 0.9f : Cell * 0.74f;
return new Vector2(sx, room.Row * Cell + yOff);
}
private static string StateScene(string name, string[] states)