/// <summary> /// Check if the specified bounds intersect with anything in the tree. See also: GetColliding. /// </summary> /// <param name="checkBounds">Bounds to check.</param> /// <returns>True if there was a collision.</returns> public bool IsColliding(ColliderProxy obj, ref LRect checkBounds) { // Are the input bounds at least partially in this node? if (!bounds.Overlaps(checkBounds)) { return(false); } // Check against any objects in this node for (int i = 0; i < objects.Count; i++) { var o = objects[i]; if (!ReferenceEquals(o.Obj, obj) && o.Bounds.Overlaps(checkBounds)) { return(true); } } // Check children if (children != null) { for (int i = 0; i < NUM_CHILDREN; i++) { if (children[i].IsColliding(obj, ref checkBounds)) { return(true); } } } return(false); }
public void CheckCollision(ColliderProxy obj, ref LRect checkBounds) { // Are the input bounds at least partially in this node? if (!bounds.Overlaps(checkBounds)) { return; } // Check against any objects in this node for (int i = 0; i < objects.Count; i++) { var o = objects[i]; if (!ReferenceEquals(o.Obj, obj) && BoundsQuadTree.FuncCanCollide(o.Obj, obj) && o.Bounds.Overlaps(checkBounds) ) { BoundsQuadTree.funcOnCollide(obj, o.Obj); } } // Check children if (children != null) { for (int i = 0; i < NUM_CHILDREN; i++) { children[i].CheckCollision(obj, ref checkBounds); } } }
/// <summary> /// Private counterpart to the public <see cref="Remove(ColliderProxy, LRect)"/> method. /// </summary> /// <param name="obj">Object to remove.</param> /// <param name="objBounds">3D bounding box around the object.</param> /// <returns>True if the object was removed successfully.</returns> bool SubRemove(ColliderProxy obj, LRect objBounds) { bool removed = false; for (int i = 0; i < objects.Count; i++) { if (ReferenceEquals(objects[i].Obj, obj)) { removed = objects.Remove(objects[i]); break; } } if (!removed && children != null) { int bestFitChild = BestFitChild(objBounds.center); removed = children[bestFitChild].SubRemove(obj, objBounds); } if (removed && children != null) { // Check if we should merge nodes now that we've removed an item if (ShouldMerge()) { Merge(); } } return(removed); }
/// <summary> /// Remove an object. Makes the assumption that the object only exists once in the tree. /// </summary> /// <param name="obj">Object to remove.</param> /// <returns>True if the object was removed successfully.</returns> public bool Remove(ColliderProxy obj) { if (obj2Node.TryGetValue(obj, out var val)) { obj2Node.Remove(obj); bool removed = false; for (int i = 0; i < val.objects.Count; i++) { if (ReferenceEquals(val.objects[i].Obj, obj)) { val.objects.RemoveAt(i); removed = true; break; } } if (removed) { val.OnRemoved(); } return(removed); } return(false); }
bool NeedCheck(ColliderProxy a, ColliderProxy b) { var val = _collisionMask[a.LayerType]; var val2 = 1 << b.LayerType; var needCheck = (val & val2) != 0; return(needCheck); }
private void _CheckRegionCircle(ColliderProxy obj) { Debug.Trace($"ColliderProxy _CheckRegionCircle {obj.Id} trans{obj.Transform2D} col{obj.Prefab}"); if (CollisionHelper.CheckCollision(obj.Prefab, obj.Transform2D, _tempPos, _tempRadius)) { tempCallback(obj); } }
private void _CheckRegionOBB(ColliderProxy obj) { Debug.Trace($"ColliderProxy _CheckRegionOBB {obj.Id} trans{obj.Transform2D} col{obj.Prefab}"); if (CollisionHelper.CheckCollision(obj.Prefab, obj.Transform2D, _tempPos, _tempSize, _tempForward)) { tempCallback(obj); } }
/// <summary> /// Check if the specified bounds intersect with anything in the tree. See also: GetColliding. /// </summary> /// <param name="checkBounds">bounds to check.</param> /// <returns>True if there was a collision.</returns> public bool IsColliding(ColliderProxy obj, LRect checkBounds) { //#if UNITY_EDITOR // For debugging //AddCollisionCheck(checkBounds); //#endif return(rootNode.IsColliding(obj, ref checkBounds)); }
/// <summary> /// Removes the specified object at the given position. Makes the assumption that the object only exists once in the tree. /// </summary> /// <param name="obj">Object to remove.</param> /// <param name="objBounds">3D bounding box around the object.</param> /// <returns>True if the object was removed successfully.</returns> public bool Remove(ColliderProxy obj, LRect objBounds) { if (!Encapsulates(bounds, objBounds)) { return(false); } return(false); }
// #### PUBLIC METHODS #### // #### PUBLIC METHODS #### public BoundsQuadTreeNode GetNode(ColliderProxy obj) { if (BoundsQuadTreeNode.obj2Node.TryGetValue(obj, out var val)) { return(val); } return(null); }
/// <summary> /// Add an object. /// </summary> /// <param name="obj">Object to add.</param> /// <param name="objBounds">3D bounding box around the object.</param> /// <returns>True if the object fits entirely within this node.</returns> public bool Add(ColliderProxy obj, LRect objBounds) { if (!Encapsulates(bounds, objBounds)) { return(false); } SubAdd(obj, objBounds); return(true); }
private ColliderProxy CreateType(int layerType, bool isStatic, Color rawColor) { var prefab = prefabs[Random.Range(0, prefabs.Count)]; var type = (EShape2D)prefab.collider.TypeId; var obj = GameObject.CreatePrimitive(type2PType[type]).GetComponent <Collider>(); obj.transform.SetParent(transform, false); obj.transform.position = new Vector3(Random.Range(-halfworldSize, halfworldSize), 0, Random.Range(-halfworldSize, halfworldSize)); switch (type) { case EShape2D.Circle: { var colInfo = (CCircle)prefab.collider; obj.transform.localScale = new Vector3(colInfo.radius.ToFloat() * 2, 1, colInfo.radius.ToFloat() * 2); break; } case EShape2D.AABB: { var colInfo = (CAABB)prefab.collider; obj.transform.localScale = new Vector3(colInfo.size.x.ToFloat() * 2, 1, colInfo.size.y.ToFloat() * 2); break; } case EShape2D.OBB: { var colInfo = (COBB)prefab.collider; obj.transform.localScale = new Vector3(colInfo.size.x.ToFloat() * 2, 1, colInfo.size.y.ToFloat() * 2); break; } } var proxy = new ColliderProxy(); proxy.Init(prefab, obj.transform.position.ToLVector2XZ()); proxy.UnityTransform = obj.transform; var mono = obj.gameObject.AddComponent <ColliderProxyMono>(); mono.proxy = proxy; if (!isStatic) { var mover = obj.gameObject.AddComponent <RandomMove>(); mover.halfworldSize = halfworldSize; mover.isNeedRotate = type == EShape2D.OBB; } proxy.IsStatic = isStatic; proxy.LayerType = layerType; mono.rawColor = rawColor; return(proxy); }
public void UpdateObj(ColliderProxy obj, LRect bound) { for (int i = 0; i < objects.Count; i++) { if (ReferenceEquals(objects[i].Obj, obj)) { objects[i] = new OctreeObject() { Obj = obj, Bounds = bound }; } } }
/// <summary> /// Removes the specified object at the given position. Makes the assumption that the object only exists once in the tree. /// </summary> /// <param name="obj">Object to remove.</param> /// <param name="objBounds">3D bounding box around the object.</param> /// <returns>True if the object was removed successfully.</returns> public bool Remove(ColliderProxy obj, LRect objBounds) { bool removed = rootNode.Remove(obj, objBounds); // See if we can shrink the octree down now that we've removed the item if (removed) { Count--; Shrink(); } return(removed); }
/// <summary> /// Removes the specified object at the given position. Makes the assumption that the object only exists once in the tree. /// </summary> /// <param name="obj">Object to remove.</param> /// <param name="objBounds">3D bounding box around the object.</param> /// <returns>True if the object was removed successfully.</returns> public bool Remove(ColliderProxy obj, LRect objBounds) { Debug.Trace($"ColliderProxy Add { obj.Id} objBounds {objBounds}"); bool removed = rootNode.Remove(obj, objBounds); // See if we can shrink the octree down now that we've removed the item if (removed) { Count--; Shrink(); } return(removed); }
void OnTriggerEvent(ColliderProxy other, ECollisionEvent type) { hasCollided = true; if (IsDebug) { if (type != ECollisionEvent.Stay) { Debug.Log(type); } } if (proxy.IsStatic) { int i = 0; } }
public void NotifyCollisionEvent(ColliderProxy a, ColliderProxy b, ECollisionEvent type) { funcGlobalOnTriggerEvent?.Invoke(a, b, type); if (!a.IsStatic) { a.OnTriggerEvent?.Invoke(b, type); //TriggerEvent(a, b, type); } if (!b.IsStatic) { b.OnTriggerEvent?.Invoke(a, type); //TriggerEvent(b, a, type); } }
public void OnQuadTreeCollision(ColliderProxy a, ColliderProxy b) { var pairId = (((long)a.Id) << 32) + b.Id; if (_curPairs.Contains(pairId)) { return; } bool isCollided = CollisionHelper.CheckCollision (a.Prefab, a.Transform2D, b.Prefab, b.Transform2D); if (isCollided) { _curPairs.Add(pairId); var type = _prePairs.Contains(pairId) ? ECollisionEvent.Stay : ECollisionEvent.Enter; NotifyCollisionEvent(a, b, type); } }
/// <summary> /// Add an object. /// </summary> /// <param name="obj">Object to add.</param> /// <param name="objBounds">3D bounding box around the object.</param> public void Add(ColliderProxy obj, LRect objBounds) { // Add object or expand the octree until it can be added int count = 0; // Safety check against infinite/excessive growth while (!rootNode.Add(obj, objBounds)) { Debug.LogError("Grow"); Grow(objBounds.center - rootNode.Center); if (++count > 20) { Debug.LogError("Aborted Add operation as it seemed to be going on forever (" + (count - 1) + ") attempts at growing the octree."); return; } } Count++; }
public static void TriggerEvent(ILPTriggerEventHandler a, ColliderProxy other, ECollisionEvent type) { switch (type) { case ECollisionEvent.Enter: { a.OnLPTriggerEnter(other); break; } case ECollisionEvent.Stay: { a.OnLPTriggerStay(other); break; } case ECollisionEvent.Exit: { a.OnLPTriggerExit(other); break; } } }
void TriggerEvent(ColliderProxy a, ColliderProxy other, ECollisionEvent type) { switch (type) { case ECollisionEvent.Enter: { a.OnTriggerEnter(other); break; } case ECollisionEvent.Stay: { a.OnTriggerStay(other); break; } case ECollisionEvent.Exit: { a.OnTriggerExit(other); break; } } }
public void UpdateObj(ColliderProxy obj, LRect bound) { var node = GetNode(obj); if (node == null) { Add(obj, bound); } else { if (!node.ContainBound(bound)) { Remove(obj); Add(obj, bound); } else { node.UpdateObj(obj, bound); } } }
public void UpdateObj(ColliderProxy obj, LRect bound) { Debug.Trace($"ColliderProxy UpdateObj { obj.Id} objBounds {bound}"); var node = GetNode(obj); if (node == null) { Add(obj, bound); } else { if (!node.ContainBound(bound)) { Remove(obj); Add(obj, bound); } else { node.UpdateObj(obj, bound); } } }
public void CheckCollision(ColliderProxy obj, LRect checkBounds) { rootNode.CheckCollision(obj, ref checkBounds); }
public void CheckCollision(ColliderProxy obj, FuncCollision callback) { var checkBounds = LRect.CreateRect(obj.pos, new LVector2(obj.MaxSideSize, obj.MaxSideSize)); rootNode.CheckCollision(ref checkBounds, callback); }
public void RemoveCollider(ColliderProxy collider) { GetBoundTree(collider.LayerType).Remove(collider); id2Proxy.Remove(collider.Id); _id2LastMovePos.Remove(collider.Id); }
//public List<> public void DoUpdate(LFloat deltaTime) { tempLst.Clear(); //deal layer foreach (var pair in BoundsQuadTreeNode.obj2Node) { var val = pair.Key; if (!val.IsStatic) { val.DoUpdate(deltaTime); if (val.IsMoved) { val.IsMoved = false; tempLst.Add(val); } } } //Check Collision with static colliders var staticTree = GetStaticBoundTree(); __DebugColProxy1 = null; __DebugColProxy2 = null; foreach (var proxy in tempLst) { var lastPos = _id2LastMovePos[proxy.Id]; var curPos = proxy.Pos3; if (lastPos == curPos) { continue; } staticTree.CheckCollision(proxy, (ColliderProxy obj) => { if (__DebugColProxy1 != null) { return; } if (obj.Id == __DegbuLastCollisionId) { } bool isCollided = CollisionHelper.CheckCollision (proxy.Prefab, proxy.Transform2D, obj.Prefab, obj.Transform2D); if (isCollided) { __DebugColProxy1 = proxy; __DebugColProxy2 = obj; __DegbuLastCollisionId = obj.Id; //Debug.LogError("碰撞到了静态物体 不让其移动"); proxy.Transform2D.Pos3 = lastPos; } }); if (proxy.Transform2D.Pos3 != lastPos) { _id2LastMovePos[proxy.Id] = curPos; } } //swap var temp = _prePairs; _prePairs = _curPairs; _curPairs = temp; _curPairs.Clear(); ////class version 1.41ms Profiler.BeginSample("UpdateObj"); foreach (var val in tempLst) { val.IsMoved = false; var bound = val.GetBounds(); var boundsTree = GetBoundTree(val.LayerType); boundsTree.UpdateObj(val, bound); } Profiler.EndSample(); ////0.32~0.42ms Profiler.BeginSample("CheckCollision"); foreach (var val in tempLst) { val.IsMoved = false; var bound = val.GetBounds(); for (int i = 0; i < LayerCount; i++) { if (InterestingMasks[val.LayerType * LayerCount + i]) { var boundsTree = GetBoundTree(i); boundsTree.CheckCollision(val, bound); } } } Profiler.EndSample(); Profiler.BeginSample("CheckLastFrameCollison"); foreach (var pairId in _curPairs) { _prePairs.Remove(pairId); } //check stay leave event foreach (var idPair in _prePairs) { var a = GetCollider((int)(idPair >> 32)); var b = GetCollider((int)(idPair & 0xffffffff)); if (a == null || b == null) { continue; } bool isCollided = CollisionHelper.CheckCollision (a.Prefab, a.Transform2D, b.Prefab, b.Transform2D); if (isCollided) { _curPairs.Add(idPair); NotifyCollisionEvent(a, b, ECollisionEvent.Stay); } else { NotifyCollisionEvent(a, b, ECollisionEvent.Exit); } } Profiler.EndSample(); }
/// <summary> /// Private counterpart to the public Add method. /// </summary> /// <param name="obj">Object to add.</param> /// <param name="objBounds">3D bounding box around the object.</param> void SubAdd(ColliderProxy obj, LRect objBounds) { // We know it fits at this level if we've got this far // We always put things in the deepest possible child // So we can skip some checks if there are children aleady if (!HasChildren) { // Just add if few objects are here, or children would be below min size if (objects.Count < NUM_OBJECTS_ALLOWED || (BaseLength / 2) < minSize) { OctreeObject newObj = new OctreeObject { Obj = obj, Bounds = objBounds }; objects.Add(newObj); #if SHOW_NODES obj.UnityTransform?.SetParent(monoTrans, true); #endif obj2Node[obj] = this; return; // We're done. No children yet } // Fits at this level, but we can go deeper. Would it fit there? // Create the 8 children int bestFitChild; if (children == null) { Split(); if (children == null) { Debug.LogError("Child creation failed for an unknown reason. Early exit."); return; } // Now that we have the new children, see if this node's existing objects would fit there for (int i = objects.Count - 1; i >= 0; i--) { OctreeObject existingObj = objects[i]; // Find which child the object is closest to based on where the // object's center is located in relation to the octree's center bestFitChild = BestFitChild(existingObj.Bounds.center); // Does it fit? if (Encapsulates(children[bestFitChild].bounds, existingObj.Bounds)) { children[bestFitChild] .SubAdd(existingObj.Obj, existingObj.Bounds); // Go a level deeper objects.Remove(existingObj); // Remove from here } } } } // Handle the new object we're adding now int bestFit = BestFitChild(objBounds.center); if (Encapsulates(children[bestFit].bounds, objBounds)) { children[bestFit].SubAdd(obj, objBounds); } else { // Didn't fit in a child. We'll have to it to this node instead OctreeObject newObj = new OctreeObject { Obj = obj, Bounds = objBounds }; objects.Add(newObj); obj2Node[obj] = this; } }
public void AddCollider(ColliderProxy collider) { GetBoundTree(collider.LayerType).Add(collider, collider.GetBounds()); id2Proxy[collider.Id] = collider; _id2LastMovePos[collider.Id] = collider.Pos3; }