diff --git a/Assets/IsoTools/Examples/Scenes/Scene11.unity b/Assets/IsoTools/Examples/Scenes/Scene11.unity index 2543475..30e62e4 100644 --- a/Assets/IsoTools/Examples/Scenes/Scene11.unity +++ b/Assets/IsoTools/Examples/Scenes/Scene11.unity @@ -108,7 +108,7 @@ Prefab: objectReference: {fileID: 0} - target: {fileID: 417424, guid: 185575a05f87743c0b2ddb83dd39c6cd, type: 2} propertyPath: m_LocalPosition.z - value: 1 + value: 1.2 objectReference: {fileID: 0} - target: {fileID: 417424, guid: 185575a05f87743c0b2ddb83dd39c6cd, type: 2} propertyPath: m_LocalRotation.x @@ -240,9 +240,11 @@ MonoBehaviour: _startDepth: 1 _showIsoBounds: 0 _showScreenBounds: 0 - _showDepends: 1 _snapByCells: 1 _snapByObjects: 1 + _showDepends: 1 + _showQuadTree: 0 + _showScreenGrid: 0 --- !u!1001 &769235453 Prefab: m_ObjectHideFlags: 0 @@ -424,7 +426,7 @@ Prefab: objectReference: {fileID: 0} - target: {fileID: 417424, guid: 185575a05f87743c0b2ddb83dd39c6cd, type: 2} propertyPath: m_LocalPosition.z - value: 1.2 + value: 1 objectReference: {fileID: 0} - target: {fileID: 417424, guid: 185575a05f87743c0b2ddb83dd39c6cd, type: 2} propertyPath: m_LocalRotation.x diff --git a/Assets/IsoTools/Scripts/Internal/IsoGrid.cs b/Assets/IsoTools/Scripts/Internal/IsoGrid.cs index 48e8702..db9745a 100644 --- a/Assets/IsoTools/Scripts/Internal/IsoGrid.cs +++ b/Assets/IsoTools/Scripts/Internal/IsoGrid.cs @@ -15,7 +15,11 @@ namespace IsoTools.Internal { void GetMinMaxCells (T item, ref IsoPoint2 min, ref IsoPoint2 max); } - public interface ILookUpper { + public interface IBoundsLookUpper { + void LookUp(IsoRect bounds); + } + + public interface IContentLookUpper { void LookUp(IsoList items); } @@ -109,13 +113,35 @@ namespace IsoTools.Internal { _gridNumPosCount = IsoPoint2.zero; } - public void LookUpCells( - IsoPoint2 min_cell, IsoPoint2 max_cell, ILookUpper look_upper) + public void VisitAllBounds(IBoundsLookUpper look_upper) { + if ( look_upper == null ) { + throw new System.ArgumentNullException("look_upper"); + } + for ( int y = 0, ye = _gridNumPosCount.y; y < ye; ++y ) { + for ( int x = 0, xe = _gridNumPosCount.x; x < xe; ++x ) { + var cell = GetCell(x, y); + if ( cell.Items.Count > 0 ) { + var rect = new IsoRect( + x * _gridCellSize, + y * _gridCellSize, + x * _gridCellSize + _gridCellSize, + y * _gridCellSize + _gridCellSize); + rect.Translate( + _gridMinNumPos.x * _gridCellSize, + _gridMinNumPos.y * _gridCellSize); + look_upper.LookUp(rect); + } + }} + } + + public void VisitItemsByCells( + IsoPoint2 min_cell, IsoPoint2 max_cell, + IContentLookUpper look_upper) { if ( min_cell.x < 0 || min_cell.y < 0 ) { throw new System.ArgumentOutOfRangeException("min_cell"); } - if ( min_cell.y >= _gridNumPosCount.x || min_cell.y >= _gridNumPosCount.y ) { + if ( max_cell.x > _gridNumPosCount.x || max_cell.y > _gridNumPosCount.y ) { throw new System.ArgumentOutOfRangeException("max_cell"); } if ( look_upper == null ) { diff --git a/Assets/IsoTools/Scripts/Internal/IsoQuadTree.cs b/Assets/IsoTools/Scripts/Internal/IsoQuadTree.cs index 875d960..5549906 100644 --- a/Assets/IsoTools/Scripts/Internal/IsoQuadTree.cs +++ b/Assets/IsoTools/Scripts/Internal/IsoQuadTree.cs @@ -19,39 +19,7 @@ namespace IsoTools.Internal { // --------------------------------------------------------------------- // - // ItemPool - // - // --------------------------------------------------------------------- - - class Item { - public Node Owner = null; - public IsoRect Bounds = IsoRect.zero; - public T Content = default(T); - - public Item Init(Node owner, IsoRect bounds, T content) { - Owner = owner; - Bounds = bounds; - Content = content; - return this; - } - - public Item Clear() { - return Init(null, IsoRect.zero, default(T)); - } - } - - class ItemPool : IsoPool { - public ItemPool(int capacity) : base(capacity) { - } - - public override Item CreateItem() { - return new Item(); - } - } - - // --------------------------------------------------------------------- - // - // NodePool + // Node // // --------------------------------------------------------------------- @@ -61,26 +29,47 @@ namespace IsoTools.Internal { public Node[] Nodes = new Node[4]; public IsoAssocList Items = new IsoAssocList(MinChildCountPerNode); public Node Parent = null; - public IsoRect Bounds = IsoRect.zero; + public IsoRect SelfBounds = IsoRect.zero; public IsoRect[] NodeBounds = new IsoRect[4]; public Node Init(Node parent, IsoRect bounds) { - Parent = parent; - Bounds = bounds; + Parent = parent; + SelfBounds = bounds; return FillNodeBounds(); } - public Node Clear(IsoIPool node_pool, IsoIPool item_pool) { + public Node Clear( + IsoIPool node_pool, IsoIPool item_pool) + { ClearNodes(node_pool, item_pool); ClearItems(item_pool); return Init(null, IsoRect.zero); } + public bool CleanUpNodes( + IsoIPool node_pool, IsoIPool item_pool) + { + var has_any_busy_nodes = false; + for ( int i = 0, e = Nodes.Length; i < e; ++i ) { + var node = Nodes[i]; + if ( node != null ) { + if ( node.CleanUpNodes(node_pool, item_pool) ) { + node_pool.Release( + node.Clear(node_pool, item_pool)); + Nodes[i] = null; + } else { + has_any_busy_nodes = true; + } + } + } + return !has_any_busy_nodes && Items.Count == 0; + } + public bool AddItem( IsoRect bounds, T content, out Item item, IsoIPool node_pool, IsoIPool item_pool) { - if ( !Bounds.Contains(bounds) ) { + if ( !SelfBounds.Contains(bounds) ) { item = null; return false; } @@ -112,12 +101,14 @@ namespace IsoTools.Internal { return true; } - public void RemoveItem(Item item) { - Items.Remove(item); + public void RemoveItem(Item item, IsoIPool item_pool) { + if ( Items.Remove(item) ) { + item_pool.Release(item.Clear()); + } } public void VisitAllBounds(IBoundsLookUpper look_upper) { - look_upper.LookUp(Bounds); + look_upper.LookUp(SelfBounds); for ( int i = 0, e = Nodes.Length; i < e; ++i ) { if ( Nodes[i] != null ) { Nodes[i].VisitAllBounds(look_upper); @@ -125,8 +116,10 @@ namespace IsoTools.Internal { } } - public void VisitItemsByBounds(IsoRect bounds, IContentLookUpper look_upper) { - if ( Bounds.Overlaps(bounds) ) { + public void VisitItemsByBounds( + IsoRect bounds, IContentLookUpper look_upper) + { + if ( bounds.Overlaps(SelfBounds) ) { for ( int i = 0, e = Items.Count; i < e; ++i ) { var item = Items[i]; if ( bounds.Overlaps(item.Bounds) ) { @@ -147,8 +140,8 @@ namespace IsoTools.Internal { // Node FillNodeBounds() { - var size = Bounds.size * 0.5f; - var center = Bounds.center; + var size = SelfBounds.size * 0.5f; + var center = SelfBounds.center; { // LT var rect = new IsoRect(center - size, center); NodeBounds[0] = rect; @@ -174,8 +167,7 @@ namespace IsoTools.Internal { for ( int i = 0, e = Nodes.Length; i < e; ++i ) { var node = Nodes[i]; if ( node != null ) { - node_pool.Release( - node.Clear(node_pool, item_pool)); + node_pool.Release(node.Clear(node_pool, item_pool)); } } System.Array.Clear(Nodes, 0, Nodes.Length); @@ -184,13 +176,41 @@ namespace IsoTools.Internal { void ClearItems(IsoIPool item_pool) { for ( int i = 0, e = Items.Count; i < e; ++i ) { var item = Items[i]; - item_pool.Release( - item.Clear()); + item_pool.Release(item.Clear()); } Items.Clear(); } } + // --------------------------------------------------------------------- + // + // Item + // + // --------------------------------------------------------------------- + + class Item { + public Node Owner = null; + public IsoRect Bounds = IsoRect.zero; + public T Content = default(T); + + public Item Init(Node owner, IsoRect bounds, T content) { + Owner = owner; + Bounds = bounds; + Content = content; + return this; + } + + public Item Clear() { + return Init(null, IsoRect.zero, default(T)); + } + } + + // --------------------------------------------------------------------- + // + // Pools + // + // --------------------------------------------------------------------- + class NodePool : IsoPool { public NodePool(int capacity) : base(capacity) { } @@ -200,6 +220,15 @@ namespace IsoTools.Internal { } } + class ItemPool : IsoPool { + public ItemPool(int capacity) : base(capacity) { + } + + public override Item CreateItem() { + return new Item(); + } + } + // --------------------------------------------------------------------- // // Members @@ -225,44 +254,67 @@ namespace IsoTools.Internal { } public void AddItem(IsoRect bounds, T content) { - if ( bounds.x.size > 0.0f && bounds.y.size > 0.0f ) { - if ( _allItems.ContainsKey(content) ) { - MoveItem(bounds, content); - } else { - if ( _rootNode == null ) { - var initial_bounds = new IsoRect( - bounds.center - bounds.size * 2.0f, - bounds.center + bounds.size * 2.0f); - _rootNode = _nodePool.Take().Init(null, initial_bounds); - } - Item item; - while ( !_rootNode.AddItem(bounds, content, out item, _nodePool, _itemPool) ) { - GrowUp( - bounds.center.x < _rootNode.Bounds.center.x, - bounds.center.y < _rootNode.Bounds.center.y); - } - _allItems.Add(content, item); + if ( _allItems.ContainsKey(content) ) { + MoveItem(bounds, content); + } else if ( bounds.x.size > 0.0f && bounds.y.size > 0.0f ) { + if ( _rootNode == null ) { + var initial_side = IsoUtils.Vec2From( + IsoUtils.Vec2MaxF(bounds.size)); + var initial_bounds = new IsoRect( + bounds.center - initial_side * 2.0f, + bounds.center + initial_side * 2.0f); + _rootNode = _nodePool.Take().Init(null, initial_bounds); } + Item item; + while ( !_rootNode.AddItem(bounds, content, out item, _nodePool, _itemPool) ) { + GrowUp( + bounds.center.x < _rootNode.SelfBounds.center.x, + bounds.center.y < _rootNode.SelfBounds.center.y); + } + _allItems.Add(content, item); + _rootNode.CleanUpNodes(_nodePool, _itemPool); } } - public bool RemoveItem(T content) { + public void RemoveItem(T content) { Item item; if ( _allItems.TryGetValue(content, out item) ) { - if ( item.Owner != null ) { - item.Owner.RemoveItem(item); - } _allItems.Remove(content); - return true; - } else { - return false; + var item_node = item.Owner; + item_node.RemoveItem(item, _itemPool); + if ( item_node.Items.Count == 0 ) { + BackwardNodeCleanUp(item_node); + } } } public void MoveItem(IsoRect bounds, T content) { - //TODO implme - RemoveItem(content); - AddItem(bounds, content); + Item item; + if ( _allItems.TryGetValue(content, out item) ) { + var item_node = item.Owner; + if ( item_node.SelfBounds.Contains(bounds) && item_node.Items.Count <= MinChildCountPerNode ) { + item.Bounds = bounds; + } else { + item_node.RemoveItem(item, _itemPool); + if ( item_node.Items.Count == 0 ) { + item_node = BackwardNodeCleanUp(item_node) ?? _rootNode; + } + while ( item_node != null ) { + Item new_item; + if ( item_node.SelfBounds.Contains(bounds) ) { + if ( item_node.AddItem(bounds, content, out new_item, _nodePool, _itemPool) ) { + _allItems[content] = new_item; + return; + } + } + item_node = item_node.Parent; + } + _allItems.Remove(content); + AddItem(bounds, content); + } + } else { + AddItem(bounds, content); + } } public void Clear() { @@ -299,11 +351,11 @@ namespace IsoTools.Internal { // --------------------------------------------------------------------- void GrowUp(bool left, bool top) { - var new_root_bounds = _rootNode.Bounds; + var new_root_bounds = _rootNode.SelfBounds; new_root_bounds.Translate( - left ? -_rootNode.Bounds.size.x : 0.0f, - top ? -_rootNode.Bounds.size.y : 0.0f); - new_root_bounds.Resize(_rootNode.Bounds.size * 2.0f); + left ? -new_root_bounds.size.x : 0.0f, + top ? -new_root_bounds.size.y : 0.0f); + new_root_bounds.Resize(new_root_bounds.size * 2.0f); var new_root = _nodePool.Take().Init(null, new_root_bounds); if ( left ) { if ( top ) { @@ -321,5 +373,12 @@ namespace IsoTools.Internal { _rootNode.Parent = new_root; _rootNode = new_root; } + + Node BackwardNodeCleanUp(Node node) { + while ( node != null && node.CleanUpNodes(_nodePool, _itemPool) ) { + node = node.Parent; + } + return node; + } } } \ No newline at end of file diff --git a/Assets/IsoTools/Scripts/Internal/IsoScreenSolver.cs b/Assets/IsoTools/Scripts/Internal/IsoScreenSolver.cs index 0e6cf54..1a46794 100644 --- a/Assets/IsoTools/Scripts/Internal/IsoScreenSolver.cs +++ b/Assets/IsoTools/Scripts/Internal/IsoScreenSolver.cs @@ -7,16 +7,18 @@ using UnityEngine.Profiling; namespace IsoTools.Internal { public class IsoScreenSolver { - Vector2 _minIsoXY = Vector2.zero; - IsoAssocList _oldVisibles = new IsoAssocList(); - IsoAssocList _curVisibles = new IsoAssocList(); + Vector2 _minIsoXY = Vector2.zero; + IsoAssocList _oldVisibles = new IsoAssocList(); + IsoAssocList _curVisibles = new IsoAssocList(); - IsoQuadTree _quadTree = new IsoQuadTree(47); - IsoGrid _screenGrid = new IsoGrid(new IsoGridItemAdapter(), 47); + IsoQuadTree _quadTree = new IsoQuadTree(47); + IsoGrid _screenGrid = new IsoGrid(new IsoSGItemAdapter(), 47); - IsoQTBoundsLookUpper _qtBoundsLU = new IsoQTBoundsLookUpper(); - IsoQTContentLookUpper _qtContentLU = new IsoQTContentLookUpper(); - IsoGridLookUpper _screenGridLU = new IsoGridLookUpper(); + IsoQTBoundsLookUpper _qtBoundsLU = new IsoQTBoundsLookUpper(); + IsoQTContentLookUpper _qtContentLU = new IsoQTContentLookUpper(); + + IsoSGBoundsLookUpper _sgBoundsLU = new IsoSGBoundsLookUpper(); + IsoSGContentLookUpper _sgContentLU = new IsoSGContentLookUpper(); // --------------------------------------------------------------------- // @@ -27,7 +29,10 @@ namespace IsoTools.Internal { class IsoQTBoundsLookUpper : IsoQuadTree.IBoundsLookUpper { public void LookUp(IsoRect bounds) { #if UNITY_EDITOR - IsoUtils.DrawRect(bounds, Color.blue); + IsoUtils.DrawSolidRect( + bounds, + IsoUtils.ColorChangeA(Color.red, 0.05f), + Color.red); #endif } } @@ -64,11 +69,11 @@ namespace IsoTools.Internal { // --------------------------------------------------------------------- // - // IsoGridItemAdapter + // IsoSGItemAdapter // // --------------------------------------------------------------------- - class IsoGridItemAdapter : IsoGrid.IItemAdapter { + class IsoSGItemAdapter : IsoGrid.IItemAdapter { public IsoRect GetBounds(IsoObject item) { return item.Internal.ScreenBounds; } @@ -86,11 +91,28 @@ namespace IsoTools.Internal { // --------------------------------------------------------------------- // - // IsoGridLookUpper + // IsoSGBoundsLookUpper // // --------------------------------------------------------------------- - class IsoGridLookUpper : IsoGrid.ILookUpper { + class IsoSGBoundsLookUpper : IsoGrid.IBoundsLookUpper { + public void LookUp(IsoRect bounds) { + #if UNITY_EDITOR + IsoUtils.DrawSolidRect( + bounds, + IsoUtils.ColorChangeA(Color.green, 0.1f), + Color.green); + #endif + } + } + + // --------------------------------------------------------------------- + // + // IsoSGContentLookUpper + // + // --------------------------------------------------------------------- + + class IsoSGContentLookUpper : IsoGrid.IContentLookUpper { IsoObject _isoObject; public void LookUp(IsoList items) { @@ -102,7 +124,7 @@ namespace IsoTools.Internal { IsoScreenSolver screen_solver, IsoObject iso_object) { _isoObject = iso_object; - screen_solver._screenGrid.LookUpCells( + screen_solver._screenGrid.VisitItemsByCells( iso_object.Internal.MinGridCell, iso_object.Internal.MaxGridCell, this); @@ -138,6 +160,7 @@ namespace IsoTools.Internal { _quadTree.AddItem( iso_object.Internal.ScreenBounds, iso_object); + _minIsoXY = IsoUtils.Vec2Min(_minIsoXY, iso_object.position); } public void OnRemoveInstance(IsoObject iso_object) { @@ -151,6 +174,7 @@ namespace IsoTools.Internal { _quadTree.MoveItem( iso_object.Internal.ScreenBounds, iso_object); + _minIsoXY = IsoUtils.Vec2Min(_minIsoXY, iso_object.position); if ( !iso_object.Internal.Dirty && _curVisibles.Contains(iso_object) ) { iso_object.Internal.Dirty = true; return true; @@ -160,21 +184,12 @@ namespace IsoTools.Internal { #if UNITY_EDITOR public void OnDrawGizmos(IsoWorld iso_world) { - _quadTree.VisitAllBounds(_qtBoundsLU); - /* - for ( int y = 0, ye = (int)_sectorsNumPosCount.y; y < ye; ++y ) { - for ( int x = 0, xe = (int)_sectorsNumPosCount.x; x < xe; ++x ) { - var sector = FindSector((float)x, (float)y); - if ( sector != null && sector.objects.Count > 0 ) { - var rect = new IsoRect( - (x * _sectorsSize), - (y * _sectorsSize), - (x * _sectorsSize) + _sectorsSize, - (y * _sectorsSize) + _sectorsSize); - rect.Translate(_sectorsMinNumPos * _sectorsSize); - IsoUtils.DrawRect(rect, Color.blue); - } - }}*/ + if ( iso_world.isShowQuadTree ) { + _quadTree.VisitAllBounds(_qtBoundsLU); + } + if ( iso_world.isShowScreenGrid ) { + _screenGrid.VisitAllBounds(_sgBoundsLU); + } } #endif @@ -205,7 +220,7 @@ namespace IsoTools.Internal { public void SetupIsoObjectDepends(IsoObject iso_object) { ClearIsoObjectDepends(iso_object); - _screenGridLU.LookUpForDepends(this, iso_object); + _sgContentLU.LookUpForDepends(this, iso_object); } public void ClearIsoObjectDepends(IsoObject iso_object) { @@ -237,16 +252,8 @@ namespace IsoTools.Internal { void ProcessAllInstances(IsoAssocList instances) { if ( instances.Count > 0 ) { - _minIsoXY.Set(float.MaxValue, float.MaxValue); for ( int i = 0, e = instances.Count; i < e; ++i ) { var iso_object = instances[i]; - var object_pos = iso_object.position; - if ( _minIsoXY.x > object_pos.x ) { - _minIsoXY.x = object_pos.x; - } - if ( _minIsoXY.y > object_pos.y ) { - _minIsoXY.y = object_pos.y; - } if ( !IsoUtils.Vec2Approximately( iso_object.Internal.LastTrans, iso_object.Internal.Transform.position) ) @@ -254,8 +261,6 @@ namespace IsoTools.Internal { iso_object.FixIsoPosition(); } } - } else { - _minIsoXY.Set(0.0f, 0.0f); } } diff --git a/Assets/IsoTools/Scripts/Internal/IsoUtils.cs b/Assets/IsoTools/Scripts/Internal/IsoUtils.cs index 55e504a..aa79e31 100644 --- a/Assets/IsoTools/Scripts/Internal/IsoUtils.cs +++ b/Assets/IsoTools/Scripts/Internal/IsoUtils.cs @@ -542,6 +542,13 @@ namespace IsoTools.Internal { Handles.DrawLine(point2, point3); Handles.DrawLine(point3, point0); } + + public static void DrawSolidRect(IsoRect rect, Color face_color, Color outline_color) { + Handles.DrawSolidRectangleWithOutline( + new Rect(rect.x.min, rect.y.min, rect.size.x, rect.size.y), + face_color, + outline_color); + } #endif } } \ No newline at end of file diff --git a/Assets/IsoTools/Scripts/IsoWorld.cs b/Assets/IsoTools/Scripts/IsoWorld.cs index b7af7ed..98c481e 100644 --- a/Assets/IsoTools/Scripts/IsoWorld.cs +++ b/Assets/IsoTools/Scripts/IsoWorld.cs @@ -297,11 +297,6 @@ namespace IsoTools { get { return _showScreenBounds; } set { _showScreenBounds = value; } } - [SerializeField] bool _showDepends = false; - public bool isShowDepends { - get { return _showDepends; } - set { _showDepends = value; } - } [SerializeField] bool _snapByCells = true; public bool isSnapByCells { get { return _snapByCells; } @@ -312,6 +307,22 @@ namespace IsoTools { get { return _snapByObjects; } set { _snapByObjects = value; } } + [Header("Development Only")] + [SerializeField] bool _showDepends = false; + public bool isShowDepends { + get { return _showDepends; } + set { _showDepends = value; } + } + [SerializeField] bool _showQuadTree = false; + public bool isShowQuadTree { + get { return _showQuadTree; } + set { _showQuadTree = value; } + } + [SerializeField] bool _showScreenGrid = false; + public bool isShowScreenGrid { + get { return _showScreenGrid; } + set { _showScreenGrid = value; } + } #endif // --------------------------------------------------------------------- @@ -441,17 +452,6 @@ namespace IsoTools { _screenSolver.OnDrawGizmos(this); _sortingSolver.OnDrawGizmos(); } - - /* QuadTree WIP - void OnDrawGizmos() { - var qt = new IsoQuadTree(_objects.Count); - for ( int i = 0, e = _objects.Count; i < e; ++i ) { - qt.Insert(_objects[i].Internal.ScreenRect, _objects[i]); - } - qt.VisitAllBounds(rect => { - IsoUtils.DrawRect(rect, Color.green); - }); - }*/ #endif } } \ No newline at end of file