ThreeKingdomsSlingshot/Assets/Scripts/OutGame/UI/FormationScreen.cs

461 lines
23 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace TKS.OutGame
{
/// <summary>
/// 편성(img08 · 기획 S12 v3) — 프리셋 3 · 전열 3(윗줄)·후열 2(아랫줄) 자리 = 영웅 목록 카드(축소) · 하단 보유 목록(장수 ▼ 전환 · 같은 카드 4열 · 출전) ·
/// 탭(자리 고르기 → 카드 탭 = 넣기 · 같은 자리 두 번 = 빼기 · 다른 자리 = 맞바꾸기) · 끌기(자리 ↔ 자리 · 카드 → 자리) · 저장 = 그 프리셋을 출전 편성으로.
/// 빈 칸 허용 · 최소 1 · 편성 제약 없음(D4).
/// </summary>
public class FormationScreen : OutGameScreen
{
int preset;
readonly List<string> work = new List<string>();
bool dirty;
int selected = -1;
bool soldiers;
readonly List<Button> presetBtns = new List<Button>();
readonly List<RectTransform> slots = new List<RectTransform>();
RectTransform list;
ScrollRect scroll;
RectTransform ghost;
public IList<string> Working
{
get { return work; }
}
public int Preset
{
get { return preset; }
}
public bool Dirty
{
get { return dirty; }
}
// Fable 제안서 §3(2026-11-09 · PD 「편성 메뉴와 영웅 목록 프레임 구분 · 디자인 요소 · 카드 목록 완성도」) — 본문 좌표 = 절대 y − 224
// 섹션 A 「출전 편성」 패널(절대 236~1010) · 홈 16 · 섹션 B 「보유 영웅」 패널(1026~1760) · 자리 = 목록 카드 × SeatScale · 보유 = × ListScale
const float SeatScale = 0.62f;
const float ListScale = 0.72f;
const int GhostMin = 8; // 보유 격자 최소 칸(2줄 · 빈 칸 = 고스트 카드)
const float SeatPitch = 222f; // 자리 중심 간격(198 + 24)
const float SeatCenterX = 608f; // 자리 줄 가운데(절대 x · 왼쪽 라벨 칸만큼 오른쪽)
const float PanelX = 24f, PanelW = 1032f;
const float PanelA_Y = 12f, PanelA_H = 760f; // 절대 236~996(Fable 검수 결함 4)
const float PanelB_Y = 804f, PanelB_H = 708f; // 절대 1028~1736(Fable 재검수 결함 4 · 그림자 아래 탭 바까지 바탕 틈 ≈ 29 · PD 2026-11-09 「고쳐」)
const float GridBottomAbs = 1730f; // 격자 아래 끝(절대 · B 필드 안쪽 1730)
const float FrontY = 182f, BackY = 471f; // 자리 위 끝(패널 A 기준 · 밴드 412~691 / 701~980 가운데)
Text countText;
Text filterText;
Text ownedCount;
Text powerText;
Image saveImg;
Text saveText;
Image saveDot;
readonly List<GameObject> presetTails = new List<GameObject>();
static RectTransform At(Transform p, string name, float x, float y, float w, float h)
{
return UiKit.Rect(name, p, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(x, -y), new Vector2(w, h));
}
public override void Build()
{
int n = Root.Battle.Config.playerSpawnPoints.Length;
int front = Mathf.Clamp(S.Db.Economy.FormationFront, 0, n);
// 바탕 = 영웅 목록과 같음(진남 + 재화 바 뒤 띠) · 헤더 오른쪽 사선 칸 = 출전 n / 칸 수
UiKit.Paint(UiKit.Fill("ListBg", Rt), UiKit.Col("list_bg", UiKit.Bg), false);
UiKit.Paint(UiKit.TopBand("ListTop", Rt, 0f, OutGameRoot.TopBarH), UiKit.Col("band_top", UiKit.Bg), false);
var head = Header("편성", "", true);
var ob = UiKit.Rect("Oblique", head, new Vector2(1f, 0.5f), new Vector2(1f, 0.5f), Vector2.zero, new Vector2(239f, OutGameRoot.HeaderH - 7f));
UiKit.Skin(ob, "oblique", UiKit.Col("oblique", UiKit.White));
countText = UiKit.Title(UiKit.Label(ob, "", 40, UiKit.Col("count_text", UiKit.Dark), TextAnchor.MiddleCenter, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(12f, 0f), new Vector2(220f, 80f)));
countText.horizontalOverflow = HorizontalWrapMode.Overflow;
// 본문 = 1080 폭 틀(낮은 화면에서도 가운데)
var body = UiKit.Rect("Mock", Body(), new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), Vector2.zero, new Vector2(OutGameRoot.Reference.x, OutGameRoot.BodyH));
// ===== 섹션 A 「출전 편성」 =====
RectTransform a;
UiKit.SectionPanel(body, "PanelA", PanelX, PanelA_Y, PanelW, PanelA_H, true, true, out a);
UiKit.SectionTitle(a, "출전 편성");
// 제약 칩(ⓘ = 편성 안내 팝업 · 안내 문장 이관)
var lim = At(a, "Limit", 592f, 12f, 230f, 56f);
UiKit.Skin(lim, "chip", UiKit.Col("chip_dark", UiKit.Dark), true);
UiKit.Layer(lim, "Line", "chip_line", UiKit.Col("chip_line", Color.clear), 4f, 4f, 4f, 4f);
UiKit.Label(lim, "편성 제약 없음", 26, UiKit.Col("text_soft", UiKit.InkSoft), TextAnchor.MiddleLeft, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(18f, 0f), new Vector2(170f, 50f)).horizontalOverflow = HorizontalWrapMode.Overflow;
UiKit.Icon(lim, "info", new Vector2(1f, 0.5f), new Vector2(1f, 0.5f), new Vector2(-16f, 0f), 32f);
lim.gameObject.AddComponent<Button>().onClick.AddListener(ShowGuide);
// 저장(녹 · 바뀐 것 없으면 비활성 색 · 바뀌면 알림 점)
var sv = At(a, "Save", 832f, 14f, 180f, 56f);
saveImg = UiKit.Skin(sv, UISkin.Has("btn_s_green") ? "btn_s_green" : "button", UiKit.White, true);
sv.gameObject.AddComponent<Button>().onClick.AddListener(SaveNow);
saveText = UiKit.Title(UiKit.Label(sv, "저장", 34, UiKit.Col("text_on_green", UiKit.Dark), TextAnchor.MiddleCenter, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 3f), new Vector2(170f, 50f)));
saveDot = UiKit.Icon(sv, "new_dot", new Vector2(1f, 1f), new Vector2(0.5f, 0.5f), new Vector2(-6f, -6f), 20f);
// 프리셋 탭 3 + 출전 꼬리 칩
for (int i = 0; i < S.Save.presets.Count; i++)
{
int k = i;
var b = SubTab("Preset" + i, a, "프리셋 " + (i + 1), new Vector2(20f + i * 212f, -92f), new Vector2(200f, 72f), () => LoadPreset(k));
presetBtns.Add(b);
var tail = UiKit.Skin(UiKit.Rect("Active", b.transform, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(-8f, 4f), new Vector2(64f, 30f)), "tail", UiKit.Col("tail_red", UiKit.Red));
UiKit.Title(UiKit.FillLabel(tail.transform, "출전", 18, UiKit.White), true);
presetTails.Add(tail.gameObject);
}
// 총 전투력 칩(편성 변화가 숫자로 바로 보임)
var pw = At(a, "Power", 736f, 96f, 276f, 64f);
UiKit.Skin(pw, "chip", UiKit.Col("chip_dark", UiKit.Dark));
UiKit.Icon(pw, "sword", new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(12f, 0f), 44f);
UiKit.Label(pw, "전투력", 24, UiKit.Col("text_soft", UiKit.InkSoft), TextAnchor.MiddleLeft, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(62f, 0f), new Vector2(90f, 40f));
powerText = UiKit.Title(UiKit.Label(pw, "", 40, UiKit.White, TextAnchor.MiddleRight, new Vector2(1f, 0.5f), new Vector2(1f, 0.5f), new Vector2(-18f, 2f), new Vector2(150f, 56f)), true);
powerText.horizontalOverflow = HorizontalWrapMode.Overflow;
// 열 밴드 2 · 구분선 · 전열/후열 칩
UiKit.Skin(At(a, "FrontBand", 20f, 176f, 992f, 279f), "row_band", UiKit.Col("row_band", Color.clear));
UiKit.Skin(At(a, "Divider", 76f, 457f, 880f, 8f), "divider", UiKit.Col("divider", Color.clear));
UiKit.Skin(At(a, "BackBand", 20f, 465f, 992f, 279f), "row_band", UiKit.Col("row_band", Color.clear));
// 라벨 칸 세로 띠(라벨 쪽을 면으로 분리 · 검수 결함 7)
UiKit.Skin(At(a, "FrontStrip", 20f, 176f, 156f, 279f), "row_band", UiKit.Col("row_label_strip", Color.clear));
UiKit.Skin(At(a, "BackStrip", 20f, 465f, 156f, 279f), "row_band", UiKit.Col("row_label_strip", Color.clear));
Pill(a, "전열", UiKit.Col("row_front", UiKit.Red), 16f, 176f + 139.5f - 30f);
Pill(a, "후열", UiKit.Col("row_back", UiKit.Dark), 16f, 465f + 139.5f - 30f);
// 자리 = 받침(빈 자리에도) + 카드 칸
float sw = CollectionCards.CellSize.x * SeatScale, sh = CollectionCards.CellSize.y * SeatScale;
for (int i = 0; i < n; i++)
{
bool f = i < front;
int col = f ? i : i - front;
int cnt = f ? front : n - front;
float cx = SeatCenterX - PanelX + (col - (cnt - 1) / 2f) * SeatPitch;
float top = f ? FrontY : BackY;
var plate = At(a, "Plate" + i, cx - sw / 2f - 8f, top - 8f, sw + 16f, sh + 16f);
UiKit.Skin(plate, "seat_plate", UiKit.Col("seat_plate", UiKit.Dark));
var pl = UiKit.Rect("Light", plate, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -4f), new Vector2(sw, 10f));
UiKit.Skin(pl, "panel_light", UiKit.Col("seat_light", Color.clear)).enabled = UISkin.Has("panel_light");
var s = At(a, "Slot" + i, cx - sw / 2f, top, sw, sh);
var hit = s.gameObject.AddComponent<Image>();
hit.color = Color.clear;
hit.raycastTarget = true;
var td = s.gameObject.AddComponent<TapDrag>();
td.AnyDirection = true;
int k = i;
td.OnTap = () => TapSlot(k);
td.OnDragStart = e => StartGhost(work[k], e);
td.OnDragMove = MoveGhost;
td.OnDragEnd = e => DropFromSlot(k, e);
slots.Add(s);
}
// ===== 섹션 B 「보유 영웅」 =====
RectTransform b2;
UiKit.SectionPanel(body, "PanelB", PanelX, PanelB_Y, PanelW, PanelB_H, false, false, out b2);
var tb = UiKit.SectionTitle(b2, "보유 영웅");
var cnt2 = UiKit.Skin(UiKit.Rect("Count", tb, new Vector2(0f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(300f, 2f), new Vector2(44f, 46f)), "badge_circle", UiKit.Col("grade_blue", UiKit.Dark));
cnt2.preserveAspect = true;
ownedCount = UiKit.Title(UiKit.FillLabel(cnt2.transform, "", 26, UiKit.White), true);
// 「장수 ▼」 필터 칩
var pick = At(b2, "Filter", 812f, 6f, 200f, 56f);
UiKit.Skin(pick, "chip", UiKit.Col("chip_dark", UiKit.Dark), true);
UiKit.Layer(pick, "Line", "chip_line", UiKit.Col("chip_line", Color.clear), 4f, 4f, 4f, 4f);
pick.gameObject.AddComponent<Button>().onClick.AddListener(() =>
{
soldiers = !soldiers;
Refresh();
});
filterText = UiKit.Title(UiKit.Label(pick, "", 30, UiKit.White, TextAnchor.MiddleCenter, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(-18f, 2f), new Vector2(140f, 50f)));
UiKit.Icon(pick, "arrow_down", new Vector2(1f, 0.5f), new Vector2(1f, 0.5f), new Vector2(-22f, 0f), 28f);
// 격자 4열(절대 x 54~1026 · y 1108~1730) + 위·아래 페이드
var cell = CollectionCards.CellSize * ListScale;
float gridTop = 1110f - 224f, gridBottom = OutGameRoot.BodyH - (GridBottomAbs - 224f);
list = UiKit.ScrollGrid("List", body, 54f, 54f, gridTop, gridBottom, cell, new Vector2(17f, 16f), 4, out scroll);
UiKit.ScrollFades(body, gridTop, gridBottom, 40f, 30f);
}
/// <summary>편성 안내(제약 칩 ⓘ · 화면의 안내 문장을 이관).</summary>
void ShowGuide()
{
Root.Modal("편성 안내", "편성 제약 없음 · 빈 칸 허용 · 최소 1명\n\n자리 탭 → 카드 탭 = 넣기 · 교체\n같은 자리 두 번 탭 = 빼기\n끌기 = 자리 ↔ 자리 · 카드 → 자리\n저장 = 이 프리셋을 출전 편성으로", new OutGameRoot.ModalButton("확인", UiKit.Dark, null));
}
/// <summary>서브탭(팩 Button_Round10 + 윗면 광택 · 선택 = 붉은 옻칠).</summary>
static Button SubTab(string name, Transform parent, string label, Vector2 pos, Vector2 size, System.Action onClick)
{
var img = UiKit.Skin(UiKit.Rect(name, parent, new Vector2(0f, 1f), new Vector2(0f, 1f), pos, size), UISkin.Has("subtab") ? "subtab" : "button", UiKit.Col("subtab_off", UiKit.Paper), true);
var b = img.gameObject.AddComponent<Button>();
b.onClick.AddListener(() => onClick());
UiKit.Title(UiKit.FillLabel(img.transform, label, 32, UiKit.White, TextAnchor.MiddleCenter, true, 8f), true);
return b;
}
static void Pill(RectTransform panel, string label, Color c, float x, float y)
{
// 전열·후열 라벨 = 평행사변형 칩 120×54(Fable §3-3)
var p = UISkin.Has("para_orange")
? UiKit.Skin(At(panel, "Row_" + label, x, y, 140f, 60f), "para_orange", c)
: UiKit.Paint(At(panel, "Row_" + label, x, y, 140f, 60f), c);
UiKit.Title(UiKit.FillLabel(p.transform, label, 30, UiKit.White), true);
}
public override void OnShow()
{
LoadPreset(S.Save.presetIdx, true);
}
public override bool OnBack()
{
if (dirty) Root.Toast("저장하지 않은 편성 변경은 취소됩니다");
dirty = false;
return false;
}
public void LoadPreset(int idx, bool quiet = false)
{
if (dirty && !quiet) Root.Toast("저장하지 않은 변경 취소");
preset = Mathf.Clamp(idx, 0, S.Save.presets.Count - 1);
work.Clear();
work.AddRange(S.Save.presets[preset].slots);
dirty = false;
selected = -1;
Refresh();
}
int Filled()
{
int n = 0;
foreach (var id in work)
if (!string.IsNullOrEmpty(id)) n++;
return n;
}
public void TapSlot(int i)
{
if (selected < 0)
{
selected = i;
}
else if (selected == i)
{
if (!string.IsNullOrEmpty(work[i]))
{
if (Filled() > 1)
{
work[i] = "";
dirty = true;
}
else Root.Toast("최소 1명은 출전해야 합니다");
}
selected = -1;
}
else
{
Swap(selected, i);
selected = -1;
}
Refresh();
}
public void TapCard(string id)
{
int at = work.IndexOf(id);
if (at >= 0)
{
if (Filled() > 1)
{
work[at] = "";
dirty = true;
}
else Root.Toast("최소 1명은 출전해야 합니다");
}
else
{
int target = selected >= 0 ? selected : work.IndexOf("");
if (target < 0) Root.Toast("빈 자리가 없습니다 — 자리를 먼저 탭해 고른 뒤 카드를 탭(교체)");
else
{
work[target] = id;
dirty = true;
}
}
selected = -1;
Refresh();
}
/// <summary>id 를 자리 slot 에 넣는다(이미 다른 자리에 있으면 맞바꿈).</summary>
public void Place(string id, int slot)
{
if (slot < 0 || slot >= work.Count || string.IsNullOrEmpty(id)) return;
int at = work.IndexOf(id);
if (at >= 0) Swap(at, slot);
else
{
work[slot] = id;
dirty = true;
}
Refresh();
}
public void Swap(int a, int b)
{
if (a == b) return;
var t = work[a];
work[a] = work[b];
work[b] = t;
dirty = true;
}
public void SaveNow()
{
var why = S.SavePreset(preset, work);
if (why != null)
{
Root.Toast(why);
return;
}
dirty = false;
Root.Toast("프리셋 " + (preset + 1) + " 저장 · 출전 편성으로 지정");
Refresh();
}
// ---------- 끌기 ----------
void StartGhost(string id, PointerEventData e)
{
if (string.IsNullOrEmpty(id)) return;
if (ghost != null) Object.Destroy(ghost.gameObject);
ghost = UiKit.Portrait("Ghost", Root.TopRoot, S.Def(id), new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, new Vector2(170f, 170f), true, 2.1f, UiKit.Red);
ghost.gameObject.name = "Ghost_" + id;
UiLayer.Nest(ghost.gameObject, UiRate.Frame); // 끄는 동안 매 프레임 이동 = 자기 캔버스(PD 2026-11-10)
MoveGhost(e);
}
void MoveGhost(PointerEventData e)
{
if (ghost == null) return;
Vector2 lp;
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(Root.TopRoot, e.position, Root.Cam, out lp)) ghost.anchoredPosition = lp;
}
int SlotAt(Vector2 screen)
{
for (int i = 0; i < slots.Count; i++)
if (RectTransformUtility.RectangleContainsScreenPoint(slots[i], screen, Root.Cam)) return i;
return -1;
}
void DropFromSlot(int from, PointerEventData e)
{
EndGhost();
int to = SlotAt(e.position);
if (to < 0 || to == from) return;
Swap(from, to);
selected = -1;
Refresh();
}
void DropCard(string id, PointerEventData e)
{
EndGhost();
int to = SlotAt(e.position);
if (to >= 0) Place(id, to);
}
void EndGhost()
{
if (ghost == null) return;
ghost.gameObject.SetActive(false);
Object.Destroy(ghost.gameObject);
ghost = null;
}
// ---------- 그리기 ----------
public override void Refresh()
{
for (int i = 0; i < presetBtns.Count; i++)
{
bool on = i == preset;
presetBtns[i].GetComponent<Image>().color = on ? UiKit.Red : UiKit.Col("subtab_off", UiKit.Paper);
var t = UiKit.LabelOf(presetBtns[i]);
t.color = UiKit.White;
t.text = "프리셋 " + (i + 1) + (on && dirty ? "*" : "");
presetTails[i].SetActive(i == S.Save.presetIdx);
}
countText.text = "출전 " + Filled() + "/" + work.Count;
float power = 0f;
foreach (var id in work)
if (!string.IsNullOrEmpty(id) && S.Def(id) != null) power += S.StatsOf(id).power;
powerText.text = power.ToString("N0");
// 저장 = 바뀐 것이 있을 때만 녹(+ 알림 점)
// 비활성 = 회색 스프라이트(녹에 회색을 곱하면 녹이 남음 · 검수 결함 3) · 광택 없음 · 글자 #5A5E70
UISkin.Apply(saveImg, dirty || !UISkin.Has("btn_s_gray") ? "btn_s_green" : "btn_s_gray");
saveImg.color = UiKit.White;
saveText.color = UiKit.Col(dirty ? "text_on_green" : "disabled_text", UiKit.Dark);
if (saveDot != null) saveDot.gameObject.SetActive(dirty);
// 자리 = 목록 카드(배율) · 빈 자리 = 원본 빈 카드 + 초록 플러스 뱃지 · 고른 자리 = 노란 포커스 테두리(깜빡)
for (int i = 0; i < slots.Count; i++)
{
var s = slots[i];
UiKit.Clear(s);
var id = i < work.Count ? work[i] : "";
var h = S.Def(id);
if (h != null) CollectionCards.CardIn(s, S, h, false, null, SeatScale);
else
{
CollectionCards.EmptyIn(s, SeatScale);
var badge = UiKit.Skin(UiKit.Rect("Plus", s, new Vector2(1f, 0f), new Vector2(0.5f, 0.5f), new Vector2(-24f, 24f), new Vector2(48f, 50f)), "badge_circle", UiKit.Col("ok", UiKit.Red));
badge.preserveAspect = true;
UiKit.Icon(badge.transform, "plus_glyph", new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 1f), 26f);
}
if (i == selected)
{
var fx = UiKit.Layer(s, "Select", "focus_line", UiKit.Col("select_line", UiKit.Star), -6f, -6f, -6f, -6f);
fx.gameObject.AddComponent<UiPulse>();
}
}
// 보유 목록 = 영웅 목록 카드(배율 · 레벨 높은 순) · 출전 중 = 꼬리 칩 + 35 % 덮개 + 초록 체크 뱃지
filterText.text = soldiers ? "병사" : "장수";
UiKit.Clear(list);
var owned = new List<HeroDb.Hero>(S.Owned(soldiers));
ownedCount.text = owned.Count.ToString();
owned.Sort((a, b) =>
{
int la = S.Save.Level(a.id) != null ? S.Save.Level(a.id).lv : 1, lb = S.Save.Level(b.id) != null ? S.Save.Level(b.id).lv : 1;
return lb.CompareTo(la);
});
var cellSize = CollectionCards.CellSize * ListScale;
foreach (var h in owned)
{
var id = h.id;
bool on = work.Contains(id);
var holder = UiKit.Rect("C_" + id, list, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, cellSize);
var card = CollectionCards.CardIn(holder, S, h, on, null, ListScale);
if (on)
{
var dim = UiKit.Layer(card.transform, "Dim", "card_bg", UiKit.Col("seat_dim", Color.clear), 2f, 80f, 2f, 70f); // 초상만(이름·레벨·별 제외)
dim.transform.SetSiblingIndex(2); // 바탕·테두리 위 · 글자·뱃지 아래
var ck = UiKit.Skin(UiKit.Rect("Check", card.transform, new Vector2(1f, 0f), new Vector2(0.5f, 0.5f), new Vector2(-47f, 86f), new Vector2(67f, 70f)), "check_circle", UiKit.Col("ok", UiKit.Red));
ck.preserveAspect = true;
UiKit.Icon(ck.transform, "check_badge", new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 2f), 39f);
}
var td = card.gameObject.AddComponent<TapDrag>();
td.OnTap = () => TapCard(id);
td.OnDragStart = e => StartGhost(id, e);
td.OnDragMove = MoveGhost;
td.OnDragEnd = e => DropCard(id, e);
}
// 빈 칸 = 고스트 카드(영웅 목록과 같은 빈 카드)로 최소 2줄(8칸)을 채움(Fable 검수 결함 5)
for (int i = owned.Count; i < GhostMin; i++)
{
var holder = UiKit.Rect("Ghost" + i, list, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, cellSize);
CollectionCards.EmptyIn(holder, ListScale).raycastTarget = false;
}
}
}
}