SummerGame/Assets/Scripts/RoomVisibilityController.cs

165 lines
6.6 KiB
C#
Raw 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;
[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;
}
}