using UnityEngine; namespace Quadtree.Items { /// /// Custom item interface for GameObject quadtree items. /// public abstract class GameObjectItemBase : MonoBehaviour, IItem where TItem : IItem where TNode : INode { /// /// Game object's bounds from last update call. /// private Bounds _lastBounds; /// /// Game object's bounds from last update call. /// private Bounds _safeBounds; //==========================================================================dd== // MonoBehaviour METHODS //==========================================================================dd== private void Start() { Init(); } private void OnEnable() { Init(); } private void OnDisable() { Root = null; ItemInitialized = false; ParentNode.Remove(This()); } private void LateUpdate() { var currentBounds = GetBounds(); if (currentBounds != _lastBounds) { // the object has moved or changed size var forceInsertionEvaluation = false; if (!currentBounds.Intersects(_safeBounds) || (currentBounds.size - _lastBounds.size).magnitude > 0) { // ...far enough to force re-insertion forceInsertionEvaluation = true; _safeBounds = currentBounds; } // current object bounds are not the same as last update // initiate tree update from currently ParentNode?.Update(This(), forceInsertionEvaluation); _lastBounds = currentBounds; } } //==========================================================================dd== // CORE TREE ITEM METHODS //==========================================================================dd== /// /// True if the item has been initialized. /// protected internal bool ItemInitialized = false; public IQuadtreeRoot Root { get; set; } public TNode ParentNode { get; set; } public abstract Bounds GetBounds(); public void QuadTree_Root_Initialized(IQuadtreeRoot root) { Root = root; if (ItemInitialized) { // the item has been initialized before the tree root root.Insert(This()); } } /// /// Returns reference to corresponding game object. /// /// /// Game object instance. public abstract GameObject GetGameObject(); /// /// Initializes the item instance. /// /// /// This may be called either before or after the initialization of the tree root. /// protected virtual void Init() { // designate item as initialized ItemInitialized = true; // set initial last bounds _lastBounds = GetBounds(); // set initial safe bounds _safeBounds = _lastBounds; if (Root == null) { if (TryGetComponent(out GameObjectQuadtreeRoot quadtreeRoot) && quadtreeRoot.Initialized) { Root = (IQuadtreeRoot)quadtreeRoot; } } if (Root != null) { // the tree root has been initialized before the item Root.Insert(This()); } } /// /// Overloaded in sub-classes to return correct instance of the item. /// /// /// This method is necessary due to generic typechecking -- this in context of the abstract generic class does not reference TItem itself. /// /// /// Instance of the item protected abstract TItem This(); /// /// Returns unique identifier of the item. /// /// /// It is extremely important to override this method because nodes are using HashSets to store items and the items are changing during the updates and so are the hash codes which can result in program not working properly. /// /// /// Unique identifier public override int GetHashCode() { return GetInstanceID(); } } }