using System; using System.Collections.Generic; using SanAndreasUnity.Behaviours.WorldSystem; using UnityEngine; namespace SanAndreasUnity.Behaviours.World { [Serializable] public struct FocusPointParameters { public bool hasRevealRadius; public float revealRadius; public float timeToKeepRevealingAfterRemoved; public FocusPointParameters(bool hasRevealRadius, float revealRadius, float timeToKeepRevealingAfterRemoved) { this.hasRevealRadius = hasRevealRadius; this.revealRadius = revealRadius; this.timeToKeepRevealingAfterRemoved = timeToKeepRevealingAfterRemoved; } public static FocusPointParameters Default => new FocusPointParameters(true, 150f, 3f); } /// /// Handles registration, unregistration, and updating of focus points for a world system. /// public class FocusPointManager { private IWorldSystem _worldSystem; private float _defaultRevealRadius; public struct FocusPointInfo { public WorldSystem.FocusPoint focusPoint; public Transform transform; public float timeToKeepRevealingAfterRemoved; public float timeWhenRemoved; public bool hasRevealRadius; } private List _focusPoints = new List(); public IReadOnlyList FocusPoints => _focusPoints; private List _focusPointsToRemoveAfterTimeout = new List(); public FocusPointManager( IWorldSystem worldSystem, float defaultRevealRadius) { _worldSystem = worldSystem; _defaultRevealRadius = defaultRevealRadius; } public void RegisterFocusPoint(Transform tr, FocusPointParameters parameters) { if (!_focusPoints.Exists(f => f.transform == tr)) { float revealRadius = parameters.hasRevealRadius ? parameters.revealRadius : _defaultRevealRadius; var registeredFocusPoint = _worldSystem.RegisterFocusPoint(revealRadius, tr.position); _focusPoints.Add(new FocusPointInfo { focusPoint = registeredFocusPoint, transform = tr, timeToKeepRevealingAfterRemoved = parameters.timeToKeepRevealingAfterRemoved, hasRevealRadius = parameters.hasRevealRadius, }); } } public void UnRegisterFocusPoint(Transform tr) { int index = _focusPoints.FindIndex(f => f.transform == tr); if (index < 0) return; // maybe we could just set transform to null, so it gets removed during next update ? var focusPoint = _focusPoints[index]; if (focusPoint.timeToKeepRevealingAfterRemoved > 0) { focusPoint.timeWhenRemoved = Time.time; _focusPointsToRemoveAfterTimeout.Add(focusPoint); _focusPoints.RemoveAt(index); return; } _worldSystem.UnRegisterFocusPoint(focusPoint.focusPoint); _focusPoints.RemoveAt(index); } public void Update() { float timeNow = Time.time; UnityEngine.Profiling.Profiler.BeginSample("Update focus points"); this._focusPoints.RemoveAll(f => { if (null == f.transform) { if (f.timeToKeepRevealingAfterRemoved > 0f) { f.timeWhenRemoved = timeNow; _focusPointsToRemoveAfterTimeout.Add(f); return true; } UnityEngine.Profiling.Profiler.BeginSample("WorldSystem.UnRegisterFocusPoint()"); _worldSystem.UnRegisterFocusPoint(f.focusPoint); UnityEngine.Profiling.Profiler.EndSample(); return true; } _worldSystem.FocusPointChangedPosition(f.focusPoint, f.transform.position); return false; }); UnityEngine.Profiling.Profiler.EndSample(); bool hasElementToRemove = false; _focusPointsToRemoveAfterTimeout.ForEach(_ => { if (timeNow - _.timeWhenRemoved > _.timeToKeepRevealingAfterRemoved) { hasElementToRemove = true; UnityEngine.Profiling.Profiler.BeginSample("WorldSystem.UnRegisterFocusPoint()"); _worldSystem.UnRegisterFocusPoint(_.focusPoint); UnityEngine.Profiling.Profiler.EndSample(); } }); if (hasElementToRemove) _focusPointsToRemoveAfterTimeout.RemoveAll(_ => timeNow - _.timeWhenRemoved > _.timeToKeepRevealingAfterRemoved); } public void ChangeDefaultRevealRadius(float newDefaultRevealRadius) { _defaultRevealRadius = newDefaultRevealRadius; for (int i = 0; i < _focusPoints.Count; i++) { var focusPoint = _focusPoints[i]; if (!focusPoint.hasRevealRadius) { _worldSystem.FocusPointChangedRadius(focusPoint.focusPoint, newDefaultRevealRadius); } } } } }