From fc6fac0ea215b7b74dad0627fd7b5710b513a97b Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Sun, 11 Dec 2016 15:03:52 +0700 Subject: [PATCH] QuadTree WIP --- Assets/IsoTools/Examples/Scenes/Scene10.unity | 264 +++++++++++++++++ .../Examples/Scenes/Scene10.unity.meta | 8 + Assets/IsoTools/Scripts/Internal/IsoMinMax.cs | 4 + .../IsoTools/Scripts/Internal/IsoQuadTree.cs | 269 ++++++++++++++++++ .../Scripts/Internal/IsoQuadTree.cs.meta | 12 + Assets/IsoTools/Scripts/Internal/IsoRect.cs | 10 + Assets/IsoTools/Scripts/IsoWorld.cs | 11 + 7 files changed, 578 insertions(+) create mode 100644 Assets/IsoTools/Examples/Scenes/Scene10.unity create mode 100644 Assets/IsoTools/Examples/Scenes/Scene10.unity.meta create mode 100644 Assets/IsoTools/Scripts/Internal/IsoQuadTree.cs create mode 100644 Assets/IsoTools/Scripts/Internal/IsoQuadTree.cs.meta diff --git a/Assets/IsoTools/Examples/Scenes/Scene10.unity b/Assets/IsoTools/Examples/Scenes/Scene10.unity new file mode 100644 index 0000000..ada9066 --- /dev/null +++ b/Assets/IsoTools/Examples/Scenes/Scene10.unity @@ -0,0 +1,264 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 7 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} +--- !u!157 &4 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 7 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_TemporalCoherenceThreshold: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 4 + m_Resolution: 2 + m_BakeResolution: 40 + m_TextureWidth: 1024 + m_TextureHeight: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 0 + m_CompAOExponentDirect: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_DirectLightInLightProbes: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 1024 + m_ReflectionCompression: 2 + m_LightingDataAsset: {fileID: 0} + m_RuntimeCPUUsage: 25 +--- !u!196 &5 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + accuratePlacement: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &1396455878 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 5 + m_Component: + - component: {fileID: 1396455884} + - component: {fileID: 1396455883} + - component: {fileID: 1396455882} + - component: {fileID: 1396455881} + - component: {fileID: 1396455880} + - component: {fileID: 1396455879} + m_Layer: 0 + m_Name: Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1396455879 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 1396455878} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3f01619d3802e814f86f9e6bb965349a, type: 3} + m_Name: + m_EditorClassIdentifier: + _tileSize: 2.2 + _tileRatio: 0.5 + _tileAngle: 45 + _tileHeight: 1.6 + _stepDepth: 0.1 + _startDepth: 1 +--- !u!81 &1396455880 +AudioListener: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 1396455878} + m_Enabled: 1 +--- !u!92 &1396455881 +Behaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 1396455878} + m_Enabled: 1 +--- !u!124 &1396455882 +Behaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 1396455878} + m_Enabled: 1 +--- !u!20 &1396455883 +Camera: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 1396455878} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 1 + orthographic size: 5 + m_Depth: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 + m_StereoMirrorMode: 0 +--- !u!4 &1396455884 +Transform: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 1396455878} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1001 &1656047475 +Prefab: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 417424, guid: 185575a05f87743c0b2ddb83dd39c6cd, type: 2} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 417424, guid: 185575a05f87743c0b2ddb83dd39c6cd, type: 2} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 417424, guid: 185575a05f87743c0b2ddb83dd39c6cd, type: 2} + propertyPath: m_LocalPosition.z + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 417424, guid: 185575a05f87743c0b2ddb83dd39c6cd, type: 2} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 417424, guid: 185575a05f87743c0b2ddb83dd39c6cd, type: 2} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 417424, guid: 185575a05f87743c0b2ddb83dd39c6cd, type: 2} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 417424, guid: 185575a05f87743c0b2ddb83dd39c6cd, type: 2} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 417424, guid: 185575a05f87743c0b2ddb83dd39c6cd, type: 2} + propertyPath: m_RootOrder + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 11472392, guid: 185575a05f87743c0b2ddb83dd39c6cd, type: 2} + propertyPath: _position.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 11472392, guid: 185575a05f87743c0b2ddb83dd39c6cd, type: 2} + propertyPath: _position.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 11472392, guid: 185575a05f87743c0b2ddb83dd39c6cd, type: 2} + propertyPath: _position.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 11472392, guid: 185575a05f87743c0b2ddb83dd39c6cd, type: 2} + propertyPath: _isShowBounds + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 180122, guid: 185575a05f87743c0b2ddb83dd39c6cd, type: 2} + propertyPath: m_IsActive + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 180122, guid: 185575a05f87743c0b2ddb83dd39c6cd, type: 2} + propertyPath: m_Name + value: TileA + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_ParentPrefab: {fileID: 100100000, guid: 185575a05f87743c0b2ddb83dd39c6cd, type: 2} + m_IsPrefabParent: 0 diff --git a/Assets/IsoTools/Examples/Scenes/Scene10.unity.meta b/Assets/IsoTools/Examples/Scenes/Scene10.unity.meta new file mode 100644 index 0000000..06c6636 --- /dev/null +++ b/Assets/IsoTools/Examples/Scenes/Scene10.unity.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 791584dcfc13145ff8d4699ad898a7f1 +timeCreated: 1477147799 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/IsoTools/Scripts/Internal/IsoMinMax.cs b/Assets/IsoTools/Scripts/Internal/IsoMinMax.cs index a8adef2..fb7b94b 100644 --- a/Assets/IsoTools/Scripts/Internal/IsoMinMax.cs +++ b/Assets/IsoTools/Scripts/Internal/IsoMinMax.cs @@ -33,6 +33,10 @@ namespace IsoTools.Internal { max = other.max; } + public void Resize(float size) { + max = min + size; + } + public void Translate(float delta) { min += delta; max += delta; diff --git a/Assets/IsoTools/Scripts/Internal/IsoQuadTree.cs b/Assets/IsoTools/Scripts/Internal/IsoQuadTree.cs new file mode 100644 index 0000000..6df99da --- /dev/null +++ b/Assets/IsoTools/Scripts/Internal/IsoQuadTree.cs @@ -0,0 +1,269 @@ +namespace IsoTools.Internal { + public class IsoQuadTree { + + const int MinChildCountPerNode = 3; + + // + // IItem + // + + public interface IItem { + } + + // + // Item + // + + class Item : IItem { + 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)); + } + } + + // + // Node + // + + class Node { + public Node Parent = null; + public IsoRect Bounds = IsoRect.zero; + public Node[] Children = new Node[4]; + public IsoAssocList Contents = new IsoAssocList(MinChildCountPerNode); + + public Node Init(Node parent, IsoRect bounds) { + Parent = parent; + Bounds = bounds; + return this; + } + + public Node Clear(IsoIPool node_pool, IsoIPool item_pool) { + ClearChildren(node_pool, item_pool); + ClearContents(item_pool); + return Init(null, IsoRect.zero); + } + + public bool Insert( + IsoRect bounds, T content, out Item item, + IsoIPool node_pool, IsoIPool item_pool) + { + if ( !Bounds.Contains(bounds) ) { + item = null; + return false; + } + bool has_any_children = false; + for ( int i = 0, e = Children.Length; i < e; ++i ) { + if ( Children[i] != null ) { + has_any_children = true; + if ( Children[i].Insert(bounds, content, out item, node_pool, item_pool) ) { + return true; + } + } + } + if ( has_any_children || Contents.Count >= MinChildCountPerNode ) { + for ( int i = 0, e = Children.Length; i < e; ++i ) { + if ( Children[i] == null ) { + var child_bounds = GetChildBounds(i); + if ( child_bounds.Contains(bounds) ) { + Children[i] = node_pool.Take().Init(this, child_bounds); + if ( Children[i].Insert(bounds, content, out item, node_pool, item_pool) ) { + return true; + } + } + } + } + } + item = item_pool.Take().Init(this, bounds, content); + Contents.Add(item); + return true; + } + + public void VisitAllBounds(System.Action act) { + act(Bounds); + for ( int i = 0, e = Children.Length; i < e; ++i ) { + if ( Children[i] != null ) { + Children[i].VisitAllBounds(act); + } + } + } + + public void VisitItemsByBounds(IsoRect bounds, System.Action act) { + if ( Bounds.Overlaps(bounds) ) { + for ( int i = 0, e = Contents.Count; i < e; ++i ) { + act(Contents[i].Content); + } + for ( int i = 0, e = Children.Length; i < e; ++i ) { + if ( Children[i] != null ) { + Children[i].VisitItemsByBounds(bounds, act); + } + } + } + } + + // + // Private + // + + IsoRect GetChildBounds(int index) { + var size = Bounds.size * 0.5f; + var center = Bounds.center; + switch ( index ) { + case 0: { // LT + return new IsoRect(center - size, center); + } + case 1: { // RT + var rect = new IsoRect(center - size, center); + rect.Translate(size.x, 0.0f); + return rect; + } + case 2: { // LB + var rect = new IsoRect(center, center + size); + rect.Translate(-size.x, 0.0f); + return rect; + } + case 3: { // RB + return new IsoRect(center, center + size); + } + default: + return IsoRect.zero; + } + } + + void ClearChildren(IsoIPool node_pool, IsoIPool item_pool) { + for ( int i = 0, e = Children.Length; i < e; ++i ) { + if ( Children[i] != null ) { + node_pool.Release( + Children[i].Clear(node_pool, item_pool)); + } + } + System.Array.Clear(Children, 0, Children.Length); + } + + void ClearContents(IsoIPool item_pool) { + for ( int i = 0, e = Contents.Count; i < e; ++i ) { + item_pool.Release( + Contents[i].Clear()); + } + Contents.Clear(); + } + } + + // + // NodePool + // + + class NodePool : IsoPool { + public NodePool(int capacity) : base(capacity) { + } + + public override Node CreateItem() { + return new Node(); + } + } + + // + // ItemPool + // + + class ItemPool : IsoPool { + public ItemPool(int capacity) : base(capacity) { + } + + public override Item CreateItem() { + return new Item(); + } + } + + // + // Members + // + + Node _root = null; + IsoIPool _nodePool = null; + IsoIPool _itemPool = null; + + // + // Public + // + + public IsoQuadTree(int capacity) { + _root = null; + _nodePool = new NodePool(capacity); + _itemPool = new ItemPool(capacity); + } + + public IItem Insert(IsoRect bounds, T content) { + if ( _root == null ) { + var initial_bounds = new IsoRect( + bounds.center - bounds.size * 2.0f, + bounds.center + bounds.size * 2.0f); + _root = _nodePool.Take().Init(null, initial_bounds); + } + Item item; + while ( !_root.Insert(bounds, content, out item, _nodePool, _itemPool) ) { + GrowUp( + bounds.center.x < _root.Bounds.center.x, + bounds.center.y < _root.Bounds.center.y); + } + return item; + } + + public void Clear() { + if ( _root != null ) { + _nodePool.Release( + _root.Clear(_nodePool, _itemPool)); + _root = null; + } + } + + public void VisitAllBounds(System.Action act) { + if ( _root != null ) { + _root.VisitAllBounds(act); + } + } + + public void VisitItemsByBounds(IsoRect bounds, System.Action act) { + if ( _root != null ) { + _root.VisitItemsByBounds(bounds, act); + } + } + + // + // Private + // + + void GrowUp(bool left, bool top) { + var new_root_bounds = _root.Bounds; + new_root_bounds.Translate( + left ? -_root.Bounds.size.x : 0.0f, + top ? -_root.Bounds.size.y : 0.0f); + new_root_bounds.Resize(_root.Bounds.size * 2.0f); + var new_root = _nodePool.Take().Init(null, new_root_bounds); + if ( left ) { + if ( top ) { + new_root.Children[3] = _root; + } else { + new_root.Children[1] = _root; + } + } else { + if ( top ) { + new_root.Children[2] = _root; + } else { + new_root.Children[0] = _root; + } + } + _root.Parent = new_root; + _root = new_root; + } + } +} \ No newline at end of file diff --git a/Assets/IsoTools/Scripts/Internal/IsoQuadTree.cs.meta b/Assets/IsoTools/Scripts/Internal/IsoQuadTree.cs.meta new file mode 100644 index 0000000..a37c221 --- /dev/null +++ b/Assets/IsoTools/Scripts/Internal/IsoQuadTree.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 9b73113fdfe654417af852054183c19d +timeCreated: 1480519801 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/IsoTools/Scripts/Internal/IsoRect.cs b/Assets/IsoTools/Scripts/Internal/IsoRect.cs index 55d3608..a5af056 100644 --- a/Assets/IsoTools/Scripts/Internal/IsoRect.cs +++ b/Assets/IsoTools/Scripts/Internal/IsoRect.cs @@ -53,6 +53,16 @@ namespace IsoTools.Internal { y.Set(other.y); } + public void Resize(float size_x, float size_y) { + x.Resize(size_x); + y.Resize(size_y); + } + + public void Resize(Vector2 size) { + x.Resize(size.x); + y.Resize(size.y); + } + public void Translate(float delta_x, float delta_y) { x.Translate(delta_x); y.Translate(delta_y); diff --git a/Assets/IsoTools/Scripts/IsoWorld.cs b/Assets/IsoTools/Scripts/IsoWorld.cs index 6f801e7..a103e7c 100644 --- a/Assets/IsoTools/Scripts/IsoWorld.cs +++ b/Assets/IsoTools/Scripts/IsoWorld.cs @@ -795,6 +795,17 @@ namespace IsoTools { StepSort(); } } + + /* 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