-
-
Save SorraTheOrc/7c8548c796032707553ac968d0a3a438 to your computer and use it in GitHub Desktop.
using UnityEngine; | |
using System.Collections; | |
using System.Collections.Generic; | |
using Sirenix.OdinInspector; | |
using System.Linq; | |
using System; | |
using WizardsCode; | |
namespace WizardsCode.Optimization | |
{ | |
/// <summary> | |
/// The ProximityActivationManager will enable and disable objects based on their proximity to a target object. | |
/// Place this component on a manager object. | |
/// | |
/// Objects are automatically regiested with the manager if they have a `ProximityRegistration` | |
/// behaviour attached to the object. | |
/// </summary> | |
public class ProximityActivationManager : MonoBehaviour | |
{ | |
[Header("Target")] | |
[SerializeField, Tooltip("The target to detect proximity to. If null the system will attempt to find the player on startup.")] | |
Transform m_ProximityTarget; | |
[Header("Tick")] | |
[SerializeField, Tooltip("The frequency, in seconds, at which to evaluate distances from the target and to enable/disable managed objects. Not that not every object will be evaluated on every tick. Ones that are closer to the target will be evaluated more frequently.")] | |
float m_TickFrequency = 0.5f; | |
HashSet<ProximityRegistration> m_FrequentlyManagedObjects = new HashSet<ProximityRegistration>(); | |
HashSet<ProximityRegistration> m_MidFrequencyManagedObjects = new HashSet<ProximityRegistration>(); | |
HashSet<ProximityRegistration> m_InfrequentManagedObjects = new HashSet<ProximityRegistration>(); | |
Transform ProximityTarget | |
{ | |
get { | |
return m_ProximityTarget; | |
} | |
} | |
private void Start() | |
{ | |
StartCoroutine(EvalauteCo()); | |
} | |
internal void Add(ProximityRegistration obj) | |
{ | |
obj.Disable(); | |
m_FrequentlyManagedObjects.Add(obj); | |
} | |
private IEnumerator EvalauteCo() | |
{ | |
while (true) | |
{ | |
// First cycle check all | |
EvaluateAll(m_InfrequentManagedObjects); | |
yield return new WaitForSeconds(m_TickFrequency); | |
EvaluateAll(m_MidFrequencyManagedObjects); | |
yield return new WaitForSeconds(m_TickFrequency); | |
EvaluateAll(m_FrequentlyManagedObjects); | |
yield return new WaitForSeconds(m_TickFrequency); | |
// Second cycle check only mid and near | |
EvaluateAll(m_MidFrequencyManagedObjects); | |
yield return new WaitForSeconds(m_TickFrequency); | |
EvaluateAll(m_FrequentlyManagedObjects); | |
yield return new WaitForSeconds(m_TickFrequency); | |
// Third cycle check only near | |
EvaluateAll(m_FrequentlyManagedObjects); | |
yield return new WaitForSeconds(m_TickFrequency); | |
} | |
} | |
private void EvaluateAll(HashSet<ProximityRegistration> set) | |
{ | |
for (int i = set.Count - 1; i >= 0; i--) | |
{ | |
Evaluate(set.ElementAt(i), set); | |
} | |
} | |
private void Evaluate(ProximityRegistration obj, HashSet<ProximityRegistration> currentSet) | |
{ | |
if (!ProximityTarget) return; | |
float distance = Vector3.SqrMagnitude(ProximityTarget.position - obj.transform.position); | |
if (!obj.gameObject.activeInHierarchy && obj.DisabledByProximity && distance < obj.NearDistanceSqr) | |
{ | |
if (currentSet != null && currentSet != m_FrequentlyManagedObjects) | |
{ | |
currentSet.Remove(obj); | |
m_FrequentlyManagedObjects.Add(obj); | |
} | |
obj.Enable(); | |
} | |
else if (obj.gameObject.activeInHierarchy && distance > obj.FarDistanceSqr) | |
{ | |
if (currentSet != null && currentSet != m_InfrequentManagedObjects) | |
{ | |
currentSet.Remove(obj); | |
m_InfrequentManagedObjects.Add(obj); | |
} | |
obj.Disable(); | |
} | |
else | |
{ | |
if (currentSet != null && currentSet != m_MidFrequencyManagedObjects) | |
{ | |
currentSet.Remove(obj); | |
m_MidFrequencyManagedObjects.Add(obj); | |
} | |
} | |
} | |
} | |
} |
using UnityEngine; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System; | |
namespace WizardsCode.Optimization | |
{ | |
/// <summary> | |
/// This component will cause the object to self register with the `ProximityActivationManager` | |
/// in the scene when it awakes. | |
/// </summary> | |
public class ProximityRegistration : MonoBehaviour | |
{ | |
[SerializeField, Tooltip("The distance at which the object is considered nearby and thus should be enabled.")] | |
float m_NearDistance = 20; | |
[SerializeField, Tooltip("The distance at which the object is considered far away and thus should be disabled.")] | |
float m_FarDistance = 30; | |
/// <summary> | |
/// The square of the distance at which the object is considered nearby and thus should be enabled. | |
/// </summary> | |
public float NearDistanceSqr | |
{ | |
get; private set; | |
} | |
/// <summary> | |
/// The square of the distance at which the object is considered far away and thus should be disabled. | |
/// </summary> | |
public float FarDistanceSqr | |
{ | |
get; private set; | |
} | |
/// <summary> | |
/// Indicates whether this object has been disabled due to proximity to the target or not. | |
/// </summary> | |
public bool DisabledByProximity | |
{ | |
get; private set; | |
} | |
/// <summary> | |
/// Disable this object because of its proximity check. | |
/// </summary> | |
public void Disable() | |
{ | |
DisabledByProximity = true; | |
gameObject.SetActive(false); | |
} | |
/// <summary> | |
/// Disable this object because of its proximity check. | |
/// </summary> | |
public void Enable() | |
{ | |
DisabledByProximity = false; | |
gameObject.SetActive(true); | |
} | |
private void Awake() | |
{ | |
NearDistanceSqr = m_NearDistance * m_NearDistance; | |
FarDistanceSqr = m_FarDistance * m_FarDistance; | |
//OPTIMIZATION: make the ProximityActivationManager a singleton | |
ProximityActivationManager manager = GameObject.FindObjectOfType<ProximityActivationManager>(); | |
manager.Add(this); | |
} | |
} | |
} |
@SawyerK8 see line 42:
internal void Add(ProximityRegistration obj) { obj.Disable(); m_FrequentlyManagedObjects.Add(obj); }
Just comment out the
obj.Disable()
to prevent all objects being disabled on startup. However, this isn't really the right way to do things. It will put significant overhead on your startup process if you have many objects and if you don't then why do you need this script. You can (and should) do all your object configuration in Awake and/or Start and/or OnEnable - all of which are fired before the above disable call.For the destroyed object problem all you need to do is add an equivalent of the above
Add
method in the manage, butRemove
then have the ProximityRegistration cace the reference to the manager object and call your newmanager.Remove(gameObject)
fromOnDestroy
in the proximity registration object.
it's awesome !! instead of culling we can practice this thing for performance.,
Hey Buddy , I was working on my android project, can you consider licensing it under MIT please?
it's awesome !! instead of culling we can practice this thing for performance., Hey Buddy , I was working on my android project, can you consider licensing it under MIT please?
There's no way to license Gusts, and I'm to lazy to add headers when the intent is just to dump it here for notes. Consider all my Gists to be CC0
it's awesome !! instead of culling we can practice this thing for performance., Hey Buddy , I was working on my android project, can you consider licensing it under MIT please?
There's no way to license Gusts, and I'm to lazy to add headers when the intent is just to dump it here for notes. Consider all my Gists to be CC0
Thanks a lot💚
@SawyerK8 see line 42:
internal void Add(ProximityRegistration obj) { obj.Disable(); m_FrequentlyManagedObjects.Add(obj); }
Just comment out the
obj.Disable()
to prevent all objects being disabled on startup. However, this isn't really the right way to do things. It will put significant overhead on your startup process if you have many objects and if you don't then why do you need this script. You can (and should) do all your object configuration in Awake and/or Start and/or OnEnable - all of which are fired before the above disable call.For the destroyed object problem all you need to do is add an equivalent of the above
Add
method in the manage, butRemove
then have the ProximityRegistration cace the reference to the manager object and call your newmanager.Remove(gameObject)
fromOnDestroy
in the proximity registration object.
Awesome script, works great. I noticed this error when an object is destroyed using "ProximityRegistration", unfortunately, I have no clue how to write a single line of code and only use Playmaker, are you able to quickly adjust the script so I don't get the error, I tried putting in these lines but I only get errors.
@SawyerK8 see line 42:
Just comment out the
obj.Disable()
to prevent all objects being disabled on startup. However, this isn't really the right way to do things. It will put significant overhead on your startup process if you have many objects and if you don't then why do you need this script. You can (and should) do all your object configuration in Awake and/or Start and/or OnEnable - all of which are fired before the above disable call.For the destroyed object problem all you need to do is add an equivalent of the above
Add
method in the manage, butRemove
then have the ProximityRegistration cace the reference to the manager object and call your newmanager.Remove(gameObject)
fromOnDestroy
in the proximity registration object.