using UnityEngine; namespace Vanguard.Board3D { /// Колода, дроп или душа: стопка карт с подписью и коллайдером. public sealed class Pile3D : MonoBehaviour { private PlaymatLayoutConfig _config; private readonly GameObject[] _layers = new GameObject[3]; private MeshRenderer _top; private MaterialPropertyBlock _block; private TextMesh _label; private int _count; public BoardZone Zone { get; private set; } public int Player { get; private set; } public BoardCardRef Ref => BoardCardRef.Pile(Zone, Player, _count); public void SetPlayer(int player) { Player = player; } public static Pile3D Create( Transform parent, PlaymatLayoutConfig config, BoardZone zone, int player, Vector3 position, string title, Color accent) { var go = new GameObject("Pile " + zone); go.transform.SetParent(parent, false); go.transform.localPosition = position; var pile = go.AddComponent(); pile.Zone = zone; pile.Player = player; pile._config = config; pile._block = new MaterialPropertyBlock(); pile.Build(title, accent, config); return pile; } private void Build(string title, Color accent, PlaymatLayoutConfig config) { var width = config.cardWidth; var height = config.cardHeight; var thickness = Mathf.Max(0.006f, config.cardThickness * 1.2f); for (var i = 0; i < _layers.Length; i++) { var layer = GameObject.CreatePrimitive(PrimitiveType.Cube); layer.name = "Layer " + i; RemoveCollider(layer); layer.transform.SetParent(transform, false); layer.transform.localPosition = new Vector3(0f, i * thickness, 0f); layer.transform.localScale = new Vector3(width, thickness, height); var renderer = layer.GetComponent(); renderer.sharedMaterial = Zone == BoardZone.Soul ? BoardMaterials.CreateUnlit(null, accent) : BoardMaterials.Back; BoardMaterials.SetShadows(renderer, true); _layers[i] = layer; } var topGo = new GameObject("Top"); topGo.transform.SetParent(transform, false); var topFilter = topGo.AddComponent(); topFilter.sharedMesh = BoardMeshLibrary.CardFace(width, height, front: true); _top = topGo.AddComponent(); _top.sharedMaterial = BoardMaterials.White; BoardMaterials.SetShadows(_top, false); _label = BoardText.Create( transform, title, 0.115f, new Color(0.86f, 0.90f, 1f), new Vector3(0f, 0.02f, -(height * 0.78f))); var collider = gameObject.AddComponent(); collider.size = new Vector3(width * 1.06f, 0.16f, height * 1.06f); collider.center = new Vector3(0f, 0.08f, 0f); } public void SetCount(int count, Texture2D topTexture, string title, Color accent) { _count = count; var safe = Mathf.Max(0, count); var layers = safe <= 0 ? 1 : safe < 5 ? 1 : safe < 20 ? 2 : 3; if (Zone == BoardZone.Soul) layers = safe < 10 ? 1 : 2; var thickness = Mathf.Max(0.006f, _config.cardThickness * 1.2f); for (var i = 0; i < _layers.Length; i++) _layers[i].SetActive(i < layers); _top.transform.localPosition = new Vector3( 0f, (layers - 1) * thickness + 0.0015f, 0f); if (topTexture != null) { _top.GetPropertyBlock(_block); _block.Clear(); BoardMaterials.SetTexture(_block, _top.sharedMaterial, topTexture); BoardMaterials.SetColor(_block, _top.sharedMaterial, Color.white); _top.SetPropertyBlock(_block); } else { _top.GetPropertyBlock(_block); _block.Clear(); if (Zone == BoardZone.Soul) { BoardMaterials.SetTexture(_block, _top.sharedMaterial, BoardTextures.White); BoardMaterials.SetColor(_block, _top.sharedMaterial, accent); } else { BoardMaterials.SetTexture(_block, _top.sharedMaterial, BoardTextures.Back); BoardMaterials.SetColor(_block, _top.sharedMaterial, Color.white); } _top.SetPropertyBlock(_block); } BoardText.SetText(_label, title + " " + safe); } private static void RemoveCollider(GameObject target) { var collider = target.GetComponent(); if (collider == null) return; if (Application.isPlaying) Destroy(collider); else DestroyImmediate(collider); } } }