using System.Collections.Generic; using UnityEngine; [System.Serializable] public class PillarData { public GameObject pillarObject; public GameObject connectedWall1; public GameObject connectedWall2; } public class RoomVisibilityController : MonoBehaviour { [Header("Центр комнаты")] public Transform roomCenter; [Header("Стены (Просто перетащите 4 стены)")] public GameObject[] walls; [Header("Столбики")] public PillarData[] pillars; [Header("Настройки видимости")] [Range(-0.5f, 0.5f)] public float hideThreshold = 0.1f; [Header("Настройки плавности (НОВОЕ)")] public float fadeSpeed = 3f; // Скорость исчезновения (чем больше, тем быстрее) private Camera _mainCamera; private Dictionary _wallHiddenStates = new Dictionary(); // Новые словари для контроля плавного исчезновения private Dictionary _targetAlphas = new Dictionary(); private Dictionary> _objectMaterials = new Dictionary>(); private Dictionary _objectRenderers = new Dictionary(); void Start() { _mainCamera = Camera.main; // При старте игры находим и запоминаем все материалы стен и столбиков foreach (var wall in walls) { InitializeFadingData(wall); } foreach (var pillar in pillars) { InitializeFadingData(pillar.pillarObject); } } // Метод для кэширования материалов (чтобы не искать их каждый кадр) private void InitializeFadingData(GameObject obj) { if (obj == null || _objectMaterials.ContainsKey(obj)) return; Renderer[] renderers = obj.GetComponentsInChildren(); List mats = new List(); foreach (Renderer r in renderers) { // Обращение к .materials создает уникальную копию материала для объекта. // Это нужно, чтобы стены исчезали по отдельности, а не все разом. mats.AddRange(r.materials); } _objectRenderers[obj] = renderers; _objectMaterials[obj] = mats; _targetAlphas[obj] = 1f; // 1f - это 100% непрозрачности (видимый) } void LateUpdate() { if (_mainCamera == null || roomCenter == null) return; Vector3 dirToCamera = _mainCamera.transform.position - roomCenter.position; dirToCamera.y = 0; // Игнорируем высоту // 1. СТЕНЫ foreach (var wall in walls) { if (wall == null) continue; Vector3 targetPos = GetRealCenter(wall); Vector3 dirToWall = targetPos - roomCenter.position; dirToWall.y = 0; bool isHidden = Vector3.Dot(dirToCamera.normalized, dirToWall.normalized) > hideThreshold; // Вместо мгновенного выключения, задаем ЦЕЛЕВУЮ прозрачность (0 - скрыть, 1 - показать) _targetAlphas[wall] = isHidden ? 0f : 1f; _wallHiddenStates[wall] = isHidden; Debug.DrawLine(roomCenter.position, targetPos, isHidden ? Color.red : Color.green); } // 2. СТОЛБИКИ foreach (var pillar in pillars) { if (pillar.pillarObject == null || pillar.connectedWall1 == null || pillar.connectedWall2 == null) continue; bool isWall1Hidden = _wallHiddenStates.ContainsKey(pillar.connectedWall1) && _wallHiddenStates[pillar.connectedWall1]; bool isWall2Hidden = _wallHiddenStates.ContainsKey(pillar.connectedWall2) && _wallHiddenStates[pillar.connectedWall2]; bool shouldHidePillar = isWall1Hidden && isWall2Hidden; // Задаем целевую прозрачность для столбика _targetAlphas[pillar.pillarObject] = shouldHidePillar ? 0f : 1f; } // 3. Вызываем функцию плавного изменения прозрачности UpdateFading(); } // Метод, который плавно меняет Альфа-канал каждый кадр private void UpdateFading() { foreach (var kvp in _objectMaterials) { GameObject obj = kvp.Key; float targetAlpha = _targetAlphas[obj]; List mats = kvp.Value; if (mats.Count == 0) continue; // Берем текущую прозрачность из первого материала float currentAlpha = mats[0].color.a; // Если текущая прозрачность не равна целевой (надо менять) if (!Mathf.Approximately(currentAlpha, targetAlpha)) { // Плавно меняем значение от текущего к целевому float newAlpha = Mathf.MoveTowards(currentAlpha, targetAlpha, fadeSpeed * Time.deltaTime); // Применяем новую прозрачность ко всем материалам объекта foreach (Material mat in mats) { Color c = mat.color; c.a = newAlpha; mat.color = c; } // ОПТИМИЗАЦИЯ: // Включаем Renderer, если прозрачность больше 0. // Выключаем Renderer полностью, только когда он на 100% прозрачен. Renderer[] renderers = _objectRenderers[obj]; bool shouldRender = newAlpha > 0f; foreach (Renderer r in renderers) { if (r.enabled != shouldRender) { r.enabled = shouldRender; } } } } } private Vector3 GetRealCenter(GameObject obj) { Renderer r = obj.GetComponentInChildren(); if (r != null) { return r.bounds.center; } return obj.transform.position; } }