/// <summary> /// moves the entity taking collisions into account /// </summary> /// <returns><c>true</c>, if move actor was newed, <c>false</c> otherwise.</returns> /// <param name="motion">Motion.</param> /// <param name="collisionResult">Collision result.</param> public bool move( Vector2 motion, out CollisionResult collisionResult ) { collisionResult = new CollisionResult(); // no collider? just move and forget about it if( entity.getComponent<Collider>() == null || _triggerHelper == null ) { entity.transform.position += motion; return false; } // 1. move all non-trigger Colliders and get closest collision var colliders = entity.getComponents<Collider>(); for( var i = 0; i < colliders.Count; i++ ) { var collider = colliders[i]; // skip triggers for now. we will revisit them after we move. if( collider.isTrigger ) continue; // fetch anything that we might collide with at our new position var bounds = collider.bounds; bounds.x += motion.X; bounds.y += motion.Y; var neighbors = Physics.boxcastBroadphaseExcludingSelf( collider, ref bounds, collider.collidesWithLayers ); foreach( var neighbor in neighbors ) { // skip triggers for now. we will revisit them after we move. if( neighbor.isTrigger ) continue; if( collider.collidesWith( neighbor, motion, out collisionResult ) ) { // hit. back off our motion motion -= collisionResult.minimumTranslationVector; } } } ListPool<Collider>.free( colliders ); // 2. move entity to its new position if we have a collision else move the full amount. motion is updated when a collision occurs entity.transform.position += motion; // 3. do an overlap check of all Colliders that are triggers with all broadphase colliders, triggers or not. // Any overlaps result in trigger events. _triggerHelper.update(); return collisionResult.collider != null; }
/// <summary> /// checks to see if this Collider with motion applied (delta movement vector) collides with any collider. If it does, true will be /// returned and result will be populated with collision data. Motion will be set to the maximum distance the Collider can travel /// before colliding. /// </summary> /// <returns><c>true</c>, if with was collidesed, <c>false</c> otherwise.</returns> /// <param name="motion">Motion.</param> /// <param name="result">Result.</param> public bool collidesWithAny(ref Vector2 motion, out CollisionResult result) { result = new CollisionResult(); // fetch anything that we might collide with at our new position var colliderBounds = bounds; colliderBounds.x += motion.X; colliderBounds.y += motion.Y; var neighbors = Physics.boxcastBroadphaseExcludingSelf(this, ref colliderBounds, collidesWithLayers); // alter the shapes position so that it is in the place it would be after movement so we can check for overlaps var oldPosition = shape.position; shape.position += motion; var didCollide = false; foreach (var neighbor in neighbors) { // skip triggers if (neighbor.isTrigger) { continue; } if (collidesWith(neighbor, out result)) { // hit. back off our motion and our Shape.position motion -= result.minimumTranslationVector; shape.position -= result.minimumTranslationVector; didCollide = true; } } // return the shapes position to where it was before the check shape.position = oldPosition; return(didCollide); }
/// <summary> /// Checks for any collisions a colliser will have following a motion vector and modifies the vector to account for them. /// </summary> /// <param name="collider"></param> /// <param name="motion"></param> /// <param name="collisionResult"></param> /// <returns>Whether or not there was a collision</returns> private bool CheckRaycast(Collider collider, ref Vector2 motion, ref CollisionResult collisionResult) { var cPosition = collider.AbsolutePosition; if (cPosition == new Vector2(float.NaN, float.NaN)) { return(false); } var cDestination = collider.AbsolutePosition + motion; var rayHit = Physics.Linecast(cPosition, cDestination); if (rayHit.Collider != null) { collisionResult.MinimumTranslationVector = motion - (rayHit.Point - cPosition); motion = (rayHit.Point - cPosition); collisionResult.Collider = rayHit.Collider; collisionResult.Normal = rayHit.Normal; collisionResult.Point = rayHit.Point; return(true); } return(false); }
/// <summary> /// checks to see if this Collider collides with any other Colliders in the Scene. The first Collider it intersects will have its collision /// data returned in the CollisionResult. /// </summary> /// <returns><c>true</c>, if with was collidesed, <c>false</c> otherwise.</returns> /// <param name="result">Result.</param> public bool collidesWithAny(out CollisionResult result) { result = new CollisionResult(); // fetch anything that we might collide with at our new position var neighbors = Physics.boxcastBroadphaseExcludingSelf(this, collidesWithLayers); foreach (var neighbor in neighbors) { // skip triggers if (neighbor.isTrigger) { continue; } if (collidesWith(neighbor, out result)) { return(true); } } return(false); }
/// <summary> /// checks to see if this Collider collides with collider. If it does, true will be returned and result will be populated /// with collision data /// </summary> /// <returns><c>true</c>, if with was collidesed, <c>false</c> otherwise.</returns> /// <param name="collider">Collider.</param> /// <param name="result">Result.</param> public bool collidesWith(Collider collider, out CollisionResult result) { return(shape.collidesWithShape(collider.shape, out result)); }
/// <summary> /// moves the entity taking collisions into account /// </summary> /// <returns><c>true</c>, if move actor was newed, <c>false</c> otherwise.</returns> /// <param name="motion">Motion.</param> /// <param name="collisionResult">Collision result.</param> public bool move(Vector2 motion, out CollisionResult collisionResult) { collisionResult = new CollisionResult(); // no collider? just move and forget about it if (entity.colliders.Count == 0 || _triggerHelper == null) { entity.transform.position += motion; return(false); } // remove ourself from the physics system until after we are done moving entity.colliders.unregisterAllCollidersWithPhysicsSystem(); // 1. move all non-trigger Colliders and get closest collision var colliders = entity.getColliders(); for (var i = 0; i < colliders.Count; i++) { var collider = colliders[i]; // skip triggers for now. we will revisit them after we move. if (collider.isTrigger) { continue; } // fetch anything that we might collide with at our new position var bounds = collider.bounds; bounds.x += motion.X; bounds.y += motion.Y; var neighbors = Physics.boxcastBroadphase(ref bounds, collider.collidesWithLayers); foreach (var neighbor in neighbors) { // skip triggers for now. we will revisit them after we move. if (neighbor.isTrigger) { continue; } if (collider.collidesWith(neighbor, motion, out collisionResult)) { // hit. back off our motion motion -= collisionResult.minimumTranslationVector; } } } ListPool <Collider> .free(colliders); // 2. move entity to its new position if we have a collision else move the full amount. motion is updated when a collision occurs entity.transform.position += motion; // 3. do an overlap check of all Colliders that are triggers with all broadphase colliders, triggers or not. // Any overlaps result in trigger events. _triggerHelper.update(); // let Physics know about our new position entity.colliders.registerAllCollidersWithPhysicsSystem(); return(collisionResult.collider != null); }
/// <summary> /// checks to see if this Collider with motion applied (delta movement vector) collides with any collider. If it does, true will be /// returned and result will be populated with collision data. Motion will be set to the maximum distance the Collider can travel /// before colliding. /// </summary> /// <returns><c>true</c>, if with was collidesed, <c>false</c> otherwise.</returns> /// <param name="motion">Motion.</param> /// <param name="result">Result.</param> public bool collidesWithAny( ref Vector2 motion, out CollisionResult result ) { result = new CollisionResult(); // fetch anything that we might collide with at our new position var colliderBounds = bounds; colliderBounds.x += motion.X; colliderBounds.y += motion.Y; var neighbors = Physics.boxcastBroadphaseExcludingSelf( this, ref colliderBounds, collidesWithLayers ); // alter the shapes position so that it is in the place it would be after movement so we can check for overlaps var oldPosition = shape.position; shape.position += motion; var didCollide = false; foreach( var neighbor in neighbors ) { // skip triggers if( neighbor.isTrigger ) continue; if( collidesWith( neighbor, out result ) ) { // hit. back off our motion and our Shape.position motion -= result.minimumTranslationVector; shape.position -= result.minimumTranslationVector; didCollide = true; } } // return the shapes position to where it was before the check shape.position = oldPosition; return didCollide; }
/// <summary> /// checks to see if this Collider collides with any other Colliders in the Scene. The first Collider it intersects will have its collision /// data returned in the CollisionResult. /// </summary> /// <returns><c>true</c>, if with was collidesed, <c>false</c> otherwise.</returns> /// <param name="result">Result.</param> public bool collidesWithAny( out CollisionResult result ) { result = new CollisionResult(); // fetch anything that we might collide with at our new position var neighbors = Physics.boxcastBroadphaseExcludingSelf( this, collidesWithLayers ); foreach( var neighbor in neighbors ) { // skip triggers if( neighbor.isTrigger ) continue; if( collidesWith( neighbor, out result ) ) return true; } return false; }
/// <summary> /// checks to see if this Collider with motion applied (delta movement vector) collides with collider. If it does, true will be /// returned and result will be populated with collision data. /// </summary> /// <returns><c>true</c>, if with was collidesed, <c>false</c> otherwise.</returns> /// <param name="collider">Collider.</param> /// <param name="motion">Motion.</param> /// <param name="result">Result.</param> public bool collidesWith( Collider collider, Vector2 motion, out CollisionResult result ) { // alter the shapes position so that it is in the place it would be after movement so we can check for overlaps var oldPosition = shape.position; shape.position += motion; var didCollide = shape.collidesWithShape( collider.shape, out result ); if( didCollide ) result.collider = collider; // return the shapes position to where it was before the check shape.position = oldPosition; return didCollide; }
/// <summary> /// checks to see if this Collider collides with collider. If it does, true will be returned and result will be populated /// with collision data /// </summary> /// <returns><c>true</c>, if with was collidesed, <c>false</c> otherwise.</returns> /// <param name="collider">Collider.</param> /// <param name="result">Result.</param> public bool collidesWith( Collider collider, out CollisionResult result ) { if( shape.collidesWithShape( collider.shape, out result ) ) { result.collider = collider; return true; } return false; }
/// <summary> /// caculates the movement modifying the motion vector to take into account any collisions that will /// occur when moving /// </summary> /// <returns><c>true</c>, if movement was calculated, <c>false</c> otherwise.</returns> /// <param name="motion">Motion.</param> /// <param name="collisionResult">Collision result.</param> public bool CalculateMovement(ref Vector2 motion, out CollisionResult collisionResult) { collisionResult = new CollisionResult(); // no collider? just move and forget about it if (Entity.GetComponent <Collider>() == null || _triggerHelper == null) { return(false); } // 1. move all non-trigger Colliders and get closest collision var colliders = Entity.GetComponents <Collider>(); for (var i = 0; i < colliders.Count; i++) { var collider = colliders[i]; // skip triggers for now. we will revisit them after we move. if (collider.IsTrigger) { continue; } // check for any collisions along the line to the destination bool colliding = collider.CollidesWithAny(out var _); CheckRaycast(collider, ref motion, ref collisionResult); // fetch anything that we might collide with at our new position var bounds = collider.Bounds; bounds.X += motion.X; bounds.Y += motion.Y; var neighbors = Physics.BoxcastBroadphaseExcludingSelf(collider, ref bounds, collider.CollidesWithLayers); foreach (var neighbor in neighbors) { // skip triggers for now. we will revisit them after we move. if (neighbor.IsTrigger) { continue; } if (collider.CollidesWith(neighbor, motion, out CollisionResult _InternalcollisionResult)) { // hit. back off our motion motion -= _InternalcollisionResult.MinimumTranslationVector; // If we hit multiple objects, only take on the first for simplicity sake. if (_InternalcollisionResult.Collider != null) { collisionResult = _InternalcollisionResult; } } } // auxilery check just in case if (!colliding && CheckRaycast(collider, ref motion, ref collisionResult)) { motion = new Vector2(); } } ListPool <Collider> .Free(colliders); return(collisionResult.Collider != null); }
/// <summary> /// moves the entity taking collisions into account /// </summary> /// <returns><c>true</c>, if move actor was newed, <c>false</c> otherwise.</returns> /// <param name="motion">Motion.</param> /// <param name="collisionResult">Collision result.</param> public bool move( Vector2 motion, out CollisionResult collisionResult ) { collisionResult = new CollisionResult(); // no collider? just move and forget about it if( entity.colliders.Count == 0 ) { entity.transform.position += motion; return false; } // remove ourself from the physics system until after we are done moving entity.colliders.unregisterAllCollidersWithPhysicsSystem(); // 1. move all non-trigger entity.colliders and get closest collision for( var i = 0; i < entity.colliders.Count; i++ ) { var collider = entity.colliders[i]; // skip triggers for now. we will revisit them after we move. if( collider.isTrigger ) continue; // fetch anything that we might collide with at our new position var bounds = collider.bounds; bounds.x += motion.X; bounds.y += motion.Y; var neighbors = Physics.boxcastBroadphase( ref bounds, collider.collidesWithLayers ); foreach( var neighbor in neighbors ) { // skip triggers for now. we will revisit them after we move. if( neighbor.isTrigger ) continue; if( collider.collidesWith( neighbor, motion, out collisionResult ) ) { // hit. back off our motion motion -= collisionResult.minimumTranslationVector; } } } // 2. move entity to its new position if we have a collision else move the full amount. motion is updated when a collision occurs entity.transform.position += motion; // 3. do an overlap check of all entity.colliders that are triggers with all broadphase colliders, triggers or not. // Any overlaps result in trigger events. for( var i = 0; i < entity.colliders.Count; i++ ) { var collider = entity.colliders[i]; // fetch anything that we might collide with us at our new position var neighbors = Physics.boxcastBroadphase( collider.bounds, collider.collidesWithLayers ); foreach( var neighbor in neighbors ) { // we need at least one of the colliders to be a trigger if( !collider.isTrigger && !neighbor.isTrigger ) continue; if( collider.overlaps( neighbor ) ) { var pair = new Pair<Collider>( collider, neighbor ); // if we already have this pair in one of our sets (the previous or current trigger intersections) dont call the enter event var shouldReportTriggerEvent = !_activeTriggerIntersections.Contains( pair ) && !_previousTriggerIntersections.Contains( pair ); if( shouldReportTriggerEvent ) notifyTriggerListeners( pair, true ); _activeTriggerIntersections.Add( pair ); } // overlaps } // end foreach } // let Physics know about our new position entity.colliders.registerAllCollidersWithPhysicsSystem(); checkForExitedColliders(); return collisionResult.collider != null; }
/// <summary> /// moves the entity taking collisions into account /// </summary> /// <returns><c>true</c>, if move actor was newed, <c>false</c> otherwise.</returns> /// <param name="motion">Motion.</param> /// <param name="collisionResult">Collision result.</param> public bool move(Vector2 motion, out CollisionResult collisionResult) { collisionResult = new CollisionResult(); // no collider? just move and forget about it if (entity.colliders.Count == 0) { entity.transform.position += motion; return(false); } // remove ourself from the physics system until after we are done moving entity.colliders.unregisterAllCollidersWithPhysicsSystem(); // 1. move all non-trigger entity.colliders and get closest collision for (var i = 0; i < entity.colliders.Count; i++) { var collider = entity.colliders[i]; // skip triggers for now. we will revisit them after we move. if (collider.isTrigger) { continue; } // fetch anything that we might collide with at our new position var bounds = collider.bounds; bounds.x += motion.X; bounds.y += motion.Y; var neighbors = Physics.boxcastBroadphase(ref bounds, collider.collidesWithLayers); foreach (var neighbor in neighbors) { // skip triggers for now. we will revisit them after we move. if (neighbor.isTrigger) { continue; } CollisionResult tempCollisionResult; if (collider.collidesWith(neighbor, motion, out tempCollisionResult)) { // hit. compare with the previous hit (if we have one) and choose the one that is closest (smallest MTV) if (collisionResult.collider == null || collisionResult.minimumTranslationVector.LengthSquared() > tempCollisionResult.minimumTranslationVector.LengthSquared()) { collisionResult = tempCollisionResult; } } } } // 2. move entity to its new position if we have a collision else move the full amount if (collisionResult.collider != null) { entity.transform.position += motion - collisionResult.minimumTranslationVector; } else { entity.transform.position += motion; } // 3. do an overlap check of all entity.colliders that are triggers with all broadphase colliders, triggers or not. // Any overlaps result in trigger events. for (var i = 0; i < entity.colliders.Count; i++) { var collider = entity.colliders[i]; // fetch anything that we might collide with us at our new position var neighbors = Physics.boxcastBroadphase(collider.bounds, collider.collidesWithLayers); foreach (var neighbor in neighbors) { // we need at least one of the colliders to be a trigger if (!collider.isTrigger && !neighbor.isTrigger) { continue; } if (collider.overlaps(neighbor)) { var pair = new Pair <Collider>(collider, neighbor); // if we already have this pair in one of our sets (the previous or current trigger intersections) dont call the enter event var shouldReportTriggerEvent = !_activeTriggerIntersections.Contains(pair) && !_previousTriggerIntersections.Contains(pair); if (shouldReportTriggerEvent) { notifityTriggerListeners(pair, true); } _activeTriggerIntersections.Add(pair); } // overlaps } // end foreach } // let Physics know about our new position entity.colliders.registerAllCollidersWithPhysicsSystem(); checkForExitedColliders(); return(collisionResult.collider != null); }
/// <summary> /// checks to see if this Collider collides with collider. If it does, true will be returned and result will be populated /// with collision data /// </summary> /// <returns><c>true</c>, if with was collidesed, <c>false</c> otherwise.</returns> /// <param name="collider">Collider.</param> /// <param name="result">Result.</param> public bool collidesWith( Collider collider, out CollisionResult result ) { return shape.collidesWithShape( collider.shape, out result ); }