236 lines
7.7 KiB
C#
236 lines
7.7 KiB
C#
using OctoCore;
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering.Universal;
|
|
|
|
namespace Unheimlich.NonEuclidean
|
|
{
|
|
public class NonEuclideanManager : MonoBehaviour
|
|
{
|
|
public static NonEuclideanManager Instance { get; private set; }
|
|
|
|
[System.Serializable]
|
|
private class Configuration
|
|
{
|
|
public NonEuclideanRoom StartRoom;
|
|
public LayerMask InFrontOfPortalLayer = 1 << 0;
|
|
public LayerMask BehindPortalLayer = 1 << 20;
|
|
}
|
|
|
|
[System.Serializable]
|
|
private class References
|
|
{
|
|
public NonEuclideanRoom[] Rooms;
|
|
}
|
|
|
|
[System.Serializable]
|
|
private class State
|
|
{
|
|
public NonEuclideanRoom ActiveRoom;
|
|
public NonEuclideanPortal ActivePortal;
|
|
}
|
|
|
|
[SerializeField] private Configuration _configuration;
|
|
[SerializeField] private References _references;
|
|
[SerializeField, OctoReadOnly] private State _state;
|
|
|
|
private int _bacwardLayer;
|
|
private int _forwardLayer;
|
|
private Camera _camera;
|
|
|
|
public int BackwardLayer => _bacwardLayer;
|
|
public int ForwardLayer => _forwardLayer;
|
|
public NonEuclideanRoom ActiveRoom => _state.ActiveRoom;
|
|
public Camera Camera => _camera;
|
|
public NonEuclideanPortal ActivePortal => _state.ActivePortal;
|
|
|
|
void OnEnable()
|
|
{
|
|
if (!Instance)
|
|
Instance = this;
|
|
}
|
|
|
|
void OnDisable()
|
|
{
|
|
if (Instance == this)
|
|
Instance = null;
|
|
}
|
|
|
|
void Start()
|
|
{
|
|
_camera = Camera.main;
|
|
|
|
if (_camera == null)
|
|
{
|
|
Debug.LogWarning("No MainCamera found");
|
|
return;
|
|
}
|
|
|
|
_bacwardLayer = GetFirstLayerFromMask(_configuration.InFrontOfPortalLayer);
|
|
_forwardLayer = GetFirstLayerFromMask(_configuration.BehindPortalLayer);
|
|
SetActiveRoom(_configuration.StartRoom);
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
EvaluatePortals();
|
|
}
|
|
|
|
void EvaluatePortals()
|
|
{
|
|
bool checkPortals = true;
|
|
if (_state.ActivePortal)
|
|
checkPortals = !_state.ActivePortal.IsPortalPassed();
|
|
|
|
if (checkPortals)
|
|
{
|
|
NonEuclideanPortal shouldBeActivatedPortal = _state.ActivePortal;
|
|
float minDist = float.MaxValue;
|
|
|
|
foreach (NonEuclideanPortal portal in ActiveRoom.Portals)
|
|
{
|
|
// Is camera behind portal
|
|
if (portal.transform.InverseTransformPoint(_camera.transform.position).z < 0)
|
|
{
|
|
Vector3 portalDir = (transform.position - _camera.transform.position).normalized;
|
|
Vector3 viewDir = _camera.transform.forward;
|
|
float angle = Vector3.Angle(viewDir, portalDir);
|
|
|
|
// Is camera pointing to portal
|
|
if (angle < 80)
|
|
{
|
|
float dist = Vector3.Distance(portal.transform.position, _camera.transform.position);
|
|
|
|
// Is this portal nearest than other portal
|
|
if (dist < minDist)
|
|
{
|
|
minDist = dist;
|
|
shouldBeActivatedPortal = portal;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (_state.ActivePortal != shouldBeActivatedPortal)
|
|
{
|
|
if (_state.ActivePortal)
|
|
_state.ActivePortal.Activate(false);
|
|
|
|
_state.ActivePortal = shouldBeActivatedPortal;
|
|
|
|
if (_state.ActivePortal)
|
|
_state.ActivePortal.Activate(true);
|
|
|
|
ConfigureRooms();
|
|
|
|
Debug.Log($"[PortalManager] Portal activated: {_state.ActivePortal.name}");
|
|
}
|
|
}
|
|
}
|
|
|
|
public void SetActiveRoom(NonEuclideanRoom activeRoom)
|
|
{
|
|
if (_state.ActivePortal)
|
|
{
|
|
_state.ActivePortal.Activate(false);
|
|
_state.ActivePortal = null;
|
|
}
|
|
|
|
_state.ActiveRoom = activeRoom;
|
|
|
|
ConfigureRooms();
|
|
}
|
|
|
|
private void ConfigureRooms()
|
|
{
|
|
// Set active or not rooms
|
|
|
|
foreach (NonEuclideanRoom room in _references.Rooms)
|
|
{
|
|
bool isActiveRoom = room == _state.ActiveRoom;
|
|
bool isTargetRoom = _state.ActivePortal ? room == _state.ActivePortal.TargetRoom : false;
|
|
|
|
room.gameObject.SetActive(isActiveRoom || isTargetRoom);
|
|
}
|
|
|
|
// Configure Active & Target Rooms
|
|
|
|
ConfigureRoom(_state.ActiveRoom, false);
|
|
if (_state.ActivePortal)
|
|
ConfigureRoom(_state.ActivePortal.TargetRoom, true);
|
|
}
|
|
|
|
private void ConfigureRoom(NonEuclideanRoom room, bool isBehindPortal)
|
|
{
|
|
if (room == null) return;
|
|
|
|
int layer = isBehindPortal ? _forwardLayer : _bacwardLayer;
|
|
|
|
SetLayerAndPropertyRecursive(room.gameObject, layer, isBehindPortal);
|
|
|
|
foreach (Light light in room.GetComponentsInChildren<Light>()) // TMP
|
|
{
|
|
bool isBehind = layer == NonEuclideanManager.Instance.ForwardLayer;
|
|
|
|
if (!light.TryGetComponent(out UniversalAdditionalLightData urp))
|
|
urp = light.gameObject.AddComponent<UniversalAdditionalLightData>();
|
|
urp.renderingLayers = 1u << (isBehind ? 1 : 0);
|
|
|
|
light.cullingMask = 1 << layer;
|
|
}
|
|
}
|
|
|
|
private void SetLayerAndPropertyRecursive(GameObject obj, int layer, bool isBehindPortal)
|
|
{
|
|
if (obj == null) return;
|
|
|
|
int currentLayer = obj.layer;
|
|
|
|
bool shouldPreserveLayer =
|
|
currentLayer == LayerMask.NameToLayer("UI") ||
|
|
currentLayer == LayerMask.NameToLayer("DetectiveBoard") ||
|
|
currentLayer == LayerMask.NameToLayer("Interactable") ||
|
|
currentLayer == LayerMask.NameToLayer("Player") ||
|
|
currentLayer == LayerMask.NameToLayer("Words") ||
|
|
currentLayer == LayerMask.NameToLayer("Listenable") ||
|
|
currentLayer == LayerMask.NameToLayer("HandsTouch");
|
|
|
|
if (!shouldPreserveLayer)
|
|
{
|
|
obj.layer = layer;
|
|
}
|
|
|
|
Collider collider = obj.GetComponent<Collider>();
|
|
if (collider)
|
|
{
|
|
collider.enabled = !isBehindPortal;
|
|
}
|
|
|
|
Renderer renderer = obj.GetComponent<Renderer>();
|
|
if (renderer && !(renderer is CanvasRenderer))
|
|
{
|
|
/*MaterialPropertyBlock block = new MaterialPropertyBlock();
|
|
renderer.GetPropertyBlock(block);
|
|
block.SetFloat(IsBehindPortalID, isBehindPortal ? 1 : 0);
|
|
renderer.SetPropertyBlock(block);*/
|
|
|
|
if (isBehindPortal)
|
|
renderer.renderingLayerMask = 1u << 1; // Light Layer 1
|
|
else
|
|
renderer.renderingLayerMask = 1u << 0; // Default
|
|
}
|
|
|
|
foreach (Transform child in obj.transform)
|
|
SetLayerAndPropertyRecursive(child.gameObject, layer, isBehindPortal);
|
|
}
|
|
|
|
private int GetFirstLayerFromMask(LayerMask mask)
|
|
{
|
|
for (int i = 0; i < 32; i++)
|
|
{
|
|
if ((mask & (1 << i)) != 0)
|
|
return i;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
} |