165 lines
6.6 KiB
C#
165 lines
6.6 KiB
C#
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<GameObject, bool> _wallHiddenStates = new Dictionary<GameObject, bool>();
|
||
|
||
// Новые словари для контроля плавного исчезновения
|
||
private Dictionary<GameObject, float> _targetAlphas = new Dictionary<GameObject, float>();
|
||
private Dictionary<GameObject, List<Material>> _objectMaterials = new Dictionary<GameObject, List<Material>>();
|
||
private Dictionary<GameObject, Renderer[]> _objectRenderers = new Dictionary<GameObject, Renderer[]>();
|
||
|
||
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<Renderer>();
|
||
List<Material> mats = new List<Material>();
|
||
|
||
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<Material> 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<Renderer>();
|
||
if (r != null)
|
||
{
|
||
return r.bounds.center;
|
||
}
|
||
return obj.transform.position;
|
||
}
|
||
} |