/// <summary> /// /// </summary> /// <param name="sphere"></param> /// <param name="hitGeom"></param> /// <param name="collisionGroup"></param> /// <returns></returns> public bool SphereCast(gxtSphere sphere, out gxtGeom hitGeom, gxtCollisionGroup collisionGroup = gxtCollisionGroup.ALL) { hitGeom = null; List<gxtGeom> geoms; if (SphereCastAll(sphere, out geoms, collisionGroup)) { float minDist = float.MaxValue; float tmpDist; for (int i = 0; i < geoms.Count; i++) { tmpDist = (sphere.Position - geoms[i].GetWorldCentroid()).LengthSquared(); if (tmpDist < minDist) { hitGeom = geoms[i]; minDist = tmpDist; } } return true; } return false; }
/// <summary> /// /// </summary> /// <param name="sphere"></param> /// <param name="hitGeoms"></param> /// <param name="collisionGroup"></param> /// <returns></returns> public bool SphereCastAll(gxtSphere sphere, out List<gxtGeom> hitGeoms, gxtCollisionGroup collisionGroup = gxtCollisionGroup.ALL) { if (collisionGroup == gxtCollisionGroup.NONE) { hitGeoms = new List<gxtGeom>(); return false; } // we pass an aabb of the sphere thru the broadphase collider...for now // narrowphase tests use the actual sphere gxtAABB aabb = new gxtAABB(sphere.Position, new Vector2(sphere.Radius)); hitGeoms = broadphaseCollider.AABBCastAll(aabb); if (hitGeoms.Count == 0) return false; gxtPolygon geomPolygon; for (int i = hitGeoms.Count - 1; i >= 0; i--) { if (!CanCollide(collisionGroup, hitGeoms[i])) hitGeoms.RemoveAt(i); else { geomPolygon = hitGeoms[i].Polygon; // must ue the guranteed world centroid to ensure an accurate test // http://www.gamedev.net/topic/308060-circle-polygon-intersection-more-2d-collisions/ if (!gxtGJKCollider.Intersects(ref geomPolygon, hitGeoms[i].GetWorldCentroid(), sphere)) hitGeoms.RemoveAt(i); } } return hitGeoms.Count != 0; }
/// <summary> /// Casts a ray into the world with the given max distance and collision filter /// Packages the nearest hit object and information on the ray cast into the rayHit structure /// Returns true if an object is intersected by the ray, false otherwise /// </summary> /// <param name="ray">Ray</param> /// <param name="rayHit">Ray Hit</param> /// <param name="tmax">Max Ray Distance</param> /// <param name="collisionGroup">Collision Groups</param> /// <returns>If an object was hit</returns> public bool RayCast(gxtRay ray, out gxtRayHit rayHit, gxtCollisionGroup collisionGroup = gxtCollisionGroup.ALL, float tmax = float.MaxValue) { rayHit = new gxtRayHit(); if (collisionGroup == gxtCollisionGroup.NONE) return false; List<gxtGeom> geoms = broadphaseCollider.RayCastAll(ray, tmax, true); if (geoms.Count == 0) return false; float t; float minDist = tmax; Vector2 pt, normal; for (int i = 0; i < geoms.Count; i++) { if (CanCollide(collisionGroup, geoms[i])) { if (gxtGJKCollider.RayCast(ray, geoms[i].Polygon, tmax, out t, out pt, out normal)) { if (t <= minDist) { rayHit.Intersection = true; rayHit.Distance = t; rayHit.Normal = normal; rayHit.Point = pt; rayHit.Geom = geoms[i]; minDist = t; } } } } return rayHit.Intersection; }
/// <summary> /// Similar to RayCast() but all intersections, not just the nearest one, is processed and /// added to the passed in list of ray hits. Said list is not sorted by distance. If you /// require a sorted list you must do this yourself in the calling function. /// Returns true if at least one geom is intersected. /// </summary> /// <param name="ray">Ray</param> /// <param name="rayHits">List of Ray Hits</param> /// <param name="collisionGroup">Collision Group</param> /// <param name="tmax">Max Ray Distance</param> /// <returns>If any geoms are intersected</returns> public bool RayCastAll(gxtRay ray, out List<gxtRayHit> rayHits, gxtCollisionGroup collisionGroup = gxtCollisionGroup.ALL, float tmax = float.MaxValue) { rayHits = new List<gxtRayHit>(); if (collisionGroup == gxtCollisionGroup.NONE) return false; List<gxtGeom> geoms = broadphaseCollider.RayCastAll(ray, tmax); if (geoms.Count == 0) return false; // variables in ray hit float t; Vector2 pt, normal; for (int i = 0; i < geoms.Count; i++) { if (CanCollide(collisionGroup, geoms[i])) { if (gxtGJKCollider.RayCast(ray, geoms[i].Polygon, tmax, out t, out pt, out normal)) { gxtRayHit rayHit = new gxtRayHit(); rayHit.Intersection = true; rayHit.Distance = t; rayHit.Normal = normal; rayHit.Point = pt; rayHit.Geom = geoms[i]; rayHits.Add(rayHit); } } } return rayHits.Count > 0; }
/// <summary> /// Returns all the geoms intersected by the point which collide with the given collision group /// </summary> /// <param name="pt">Pt</param> /// <param name="hitGeoms">Intersected Geoms</param> /// <param name="collisionGroup">Collision Group</param> /// <returns>Returns true if at least 1 geom is intersected by the point</returns> public bool PointCastAll(Vector2 pt, out List<gxtGeom> hitGeoms, gxtCollisionGroup collisionGroup = gxtCollisionGroup.ALL) { if (collisionGroup == gxtCollisionGroup.NONE) { hitGeoms = new List<gxtGeom>(); return false; } hitGeoms = broadphaseCollider.PointCastAll(pt); for (int i = hitGeoms.Count - 1; i >= 0; i--) { if (!CanCollide(collisionGroup, hitGeoms[i])) hitGeoms.RemoveAt(i); else if (!gxtGJKCollider.Contains(hitGeoms[i].Polygon, pt)) hitGeoms.RemoveAt(i); } return hitGeoms.Count != 0; }
/// <summary> /// Returns one geom intersected by the pt which will collide with the given collision group /// In cases where multiple geoms are intersected by the point, the geom is chosen whose centroid /// is closest to the passed in point /// </summary> /// <param name="pt">Pt</param> /// <param name="hitGeom">Intersected Geom</param> /// <param name="collisionGroup">Collision Group</param> /// <returns>Returns true if a geom is intersected by the point</returns> public bool PointCast(Vector2 pt, out gxtGeom hitGeom, gxtCollisionGroup collisionGroup = gxtCollisionGroup.ALL) { hitGeom = null; List<gxtGeom> geoms; if (PointCastAll(pt, out geoms, collisionGroup)) { float minDist = float.MaxValue; float tmpDist; for (int i = 0; i < geoms.Count; i++) { // should really be by the world centroid instead tmpDist = (pt - geoms[i].GetWorldCentroid()).LengthSquared(); if (tmpDist < minDist) { hitGeom = geoms[i]; minDist = tmpDist; } } return true; } return false; }
/// <summary> /// Determines if an object with the given collision group can collide with the geom /// </summary> /// <param name="collisionGroup">Collision Group</param> /// <param name="geom">Geom</param> /// <returns>If object and geom can collide</returns> public bool CanCollide(gxtCollisionGroup collisionGroup, gxtGeom geom) { if (!geom.CollisionEnabled) return false; if ((collisionGroup & geom.CollisionGroups) == gxtCollisionGroup.NONE) return false; return true; }
public void AddCollisionGroupName(string name, gxtCollisionGroup collisionGroup) { /* if (collisionGroupsMap.ContainsValue(collisionGroup)) { gxtLog.WriteLineV(gxtVerbosityLevel.WARNING, "Collision group exists under another name"); } */ collisionGroupsMap.Add(name, collisionGroup); }
/// <summary> /// /// </summary> /// <param name="aabb"></param> /// <param name="hitGeoms"></param> /// <param name="collisionGroup"></param> /// <returns></returns> public bool AABBCastAll(gxtAABB aabb, out List<gxtGeom> hitGeoms, gxtCollisionGroup collisionGroup = gxtCollisionGroup.ALL) { gxtDebug.Assert(aabb.Extents.X >= 0.0f && aabb.Extents.Y >= 0.0f, "An AABB with negative extents will not intersect anything"); if (collisionGroup == gxtCollisionGroup.NONE) { hitGeoms = new List<gxtGeom>(); return false; } hitGeoms = broadphaseCollider.AABBCastAll(aabb); if (hitGeoms.Count == 0) return false; gxtPolygon boxPolygon = gxtGeometry.ComputePolygonFromAABB(aabb); gxtPolygon geomPolygon; for (int i = hitGeoms.Count - 1; i >= 0; i--) { if (!CanCollide(collisionGroup, hitGeoms[i])) hitGeoms.RemoveAt(i); else { geomPolygon = hitGeoms[i].Polygon; if (!gxtGJKCollider.Intersects(ref boxPolygon, aabb.Position, ref geomPolygon, hitGeoms[i].Position)) hitGeoms.RemoveAt(i); } } return hitGeoms.Count != 0; }