/// <summary> /// Performs a ray cast on the polygon given an optional tmax value /// Only process the information in the rayHit structure if Intersection = true, /// which is specified in the gxtRayHit instance and the return value. If the ray origin is /// inside the Polygon it is not considered an intersection /// </summary> /// <param name="ray">Ray</param> /// <param name="polygon">Polygon</param> /// <param name="rayHit">Ray Hit Info</param> /// <param name="tmax">Max T Value</param> /// <returns>If Intersecting</returns> public virtual bool RayCast(gxtRay ray, ref gxtPolygon polygon, out gxtRayHit rayHit, float tmax = float.MaxValue) { rayHit = new gxtRayHit(); rayHit.Distance = tmax; // if a crossing is within tmax bool intersection = false; // temp holder for segment distance float distance; // number of crossings, regardless of tmax int crossings = 0; // log a message when we run a raycast on a very detailed polygon // to indicate that the results may not be perfect int testIterations = polygon.NumVertices; if (MaxIterations < polygon.NumVertices) { gxtLog.WriteLineV(gxtVerbosityLevel.WARNING, "Polygon vertices exceeds max collider iterations. Not all segments will be tested!"); testIterations = MaxIterations; } for (int j = polygon.NumVertices - 1, i = 0; i < testIterations; j = i, i++) { if (RayIntersectsSegment(ray, polygon.v[j], polygon.v[i], out distance)) { crossings++; if (distance <= rayHit.Distance) { intersection = true; rayHit.Distance = distance; rayHit.Point = ray.GetPoint(distance); // right perp assumes CCW polygon winding Vector2 edge = polygon.v[j] - polygon.v[i]; rayHit.Normal = Vector2.Normalize(gxtMath.RightPerp(edge)); } } } // raycast algorithm rayHit.Intersection = intersection && crossings > 0 && crossings % 2 == 0; return rayHit.Intersection; }
private bool OnOneWayPlatformCollision(gxtGeom ga, gxtGeom gb, gxtCollisionResult cr) { float tolerance = 0.5f; if (ga == geomC) { //gxtLog.WriteLineV(gxtVerbosityLevel.INFORMATIONAL, "here"); float dot = Vector2.Dot(cr.Normal, Vector2.UnitY); if (dot >= tolerance) { //if (gb.HasAttachedBody() && Vector2.Dot(gb.RigidBody.PrevAcceleration, Vector2.UnitY) <= 0.0f) return false; } else { gxtRayHit rayHit; gxtRay downRay = new gxtRay(); downRay.Origin = gb.GetWorldCentroid() - new Vector2(0.0f, geomF.LocalAABB.Height * 0.45f); downRay.Direction = Vector2.UnitY; float halfHeight = geomF.LocalAABB.Height * 0.65f; if (world.PhysicsWorld.RayCast(downRay, out rayHit, gxtCollisionGroup.ALL, halfHeight)) { gxtRay adjRay = new gxtRay(downRay.Origin * gxtPhysicsWorld.PHYSICS_SCALE, downRay.Direction); gxtDebugDrawer.Singleton.AddRay(adjRay, rayHit.Distance * gxtPhysicsWorld.PHYSICS_SCALE, Color.Green, 0.0f, TimeSpan.FromSeconds(5.0)); return false; } else { //return false; gxtRay adjRay = new gxtRay(downRay.Origin * gxtPhysicsWorld.PHYSICS_SCALE, downRay.Direction); gxtDebugDrawer.Singleton.AddRay(adjRay, halfHeight * gxtPhysicsWorld.PHYSICS_SCALE, Color.Green, 0.0f, TimeSpan.FromSeconds(5.0)); //return false; } } //else if (gb.HasAttachedBody() && Vector2.Dot(gb.RigidBody.PrevAcceleration, Vector2.UnitY)) } else { gxtDebug.Assert(false, "You didn't set up the swap properly"); } /* else if (gb == geomC) { float dot = Vector2.Dot(cr.Normal, new Vector2(0.0f, -1.0f)); if (dot >= tolerance) { if (gb.HasAttachedBody() && Vector2.Dot(gb.RigidBody.PrevAcceleration, new Vector2(0.0f, -1.0f)) >= 0.0f) return false; } } */ return true; }
private bool PerformRaycast(float t) { raycasts.Clear(); gxtRay downRay = new gxtRay(); downRay.Origin = position; downRay.Direction = Vector2.UnitY; // may want to raycast against more than just platforms bool anyHits = world.PhysicsWorld.RayCastAll(downRay, out raycasts, "traversable_world_geometry", 15.0f); gxtDebugDrawer.Singleton.CurrentScale = gxtPhysicsWorld.PHYSICS_SCALE; if (anyHits) { // insertion sort int j, i; gxtRayHit hit; for (j = 1; j < raycasts.Count - 1; ++j) { hit = raycasts[j]; i = j - 1; while ((i >= 0) && (hit.Distance < raycasts[i].Distance)) { raycasts[i + 1] = raycasts[i]; --i; } raycasts[i + 1] = hit; } gxtDebugDrawer.Singleton.AddRay(downRay, raycasts[0].Distance, Color.Red); } else { gxtDebugDrawer.Singleton.AddRay(downRay, t, Color.Green); } return anyHits; }
/// <summary> /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input, and playing audio. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Update(GameTime gameTime) { base.Update(gameTime); float xA = 0.0f, yA = 0.0f, rA = 0.0f; gxtKeyboard kb = gxtKeyboardManager.Singleton.GetKeyboard(); gxtMouse mouse = gxtMouseManager.Singleton.GetMouse(); // assume gravity off float force = 150; float torque = 300.0f; if (kb.IsDown(Keys.Left)) xA -= force; if (kb.IsDown(Keys.Right)) xA += force; if (kb.IsDown(Keys.Up)) yA -= force; if (kb.IsDown(Keys.Down)) yA += force; if (kb.IsDown(Keys.OemOpenBrackets)) rA -= torque; if (kb.IsDown(Keys.OemCloseBrackets)) rA += torque; if (xA != 0.0f || yA != 0.0f) bodyA.ApplyForce(new Vector2(xA, yA)); if (rA != 0.0f) bodyA.ApplyTorque(rA); //bodyA.Translate(new Vector2(xA, yA)); //bodyA.SetRotation(bodyA.Rotation + rA); Vector2 forceBeforeClear = bodyA.Force; world.Update(gameTime); //gxtLog.WriteLineV(gxtVerbosityLevel.INFORMATIONAL, bodyA.Acceleration.ToString()); Color geomAColor = Color.Yellow; Color geomBColor = Color.Yellow; gxtRay ray = new gxtRay(); ray.Origin = rayOrigin; if (kb.GetState(Keys.C) == gxtControlState.FIRST_PRESSED) { if (rayOrigin == new Vector2(-225, -100)) rayOrigin = new Vector2(250, 200); else rayOrigin = new Vector2(-225, -100); } Vector2 d = world.Camera.GetVirtualMousePosition(mouse.GetPosition()) - ray.Origin; ray.Direction = Vector2.Normalize(d); gxtDebugDrawer.Singleton.PtSize = 10.0f; gxtDebugDrawer.Singleton.AddPt(ray.Origin, Color.Green, 0.0f); //gxtDebugDrawer.Singleton.AddLine(ray.Origin, ray.Origin + d, Color.Green, 0.0f); //gxtDebugDrawer.Singleton.AddRay(ray, Color.Green, 0.0f); float t = 0.0f; #if NARROWPHASE_TEST Vector2 polyIntersectionPt; Vector2 polyRayNormal; if (gxtGJKCollider.RayCast(ray, geomA.Polygon, float.MaxValue, out t, out polyIntersectionPt, out polyRayNormal)) { geomAColor = Color.Red; gxtDebugDrawer.Singleton.AddLine(polyIntersectionPt, polyIntersectionPt + polyRayNormal * 50, Color.Gray, 0.0f); gxtDebugDrawer.Singleton.AddPt(polyIntersectionPt, Color.YellowGreen, 0.0f); gxtDebugDrawer.Singleton.AddRay(ray, t, Color.Green, 0.0f, System.TimeSpan.Zero); //gxtLog.WriteLineV(gxtVerbosityLevel.INFORMATIONAL, "t: {0}", t); } else { gxtDebugDrawer.Singleton.AddRay(ray, Color.Green, 0.0f); } #elif BROADPHASE_TEST Vector2 aabbIntersectionPt; if (ray.IntersectsAABB(geomA.AABB, out t, out aabbIntersectionPt, float.MaxValue, true)) { gxtLog.WriteLineV(gxtVerbosityLevel.INFORMATIONAL, "aabb intersection"); gxtDebugDrawer.Singleton.AddRay(ray, t, Color.Green, 0.0f, System.TimeSpan.Zero); gxtDebugDrawer.Singleton.AddPt(aabbIntersectionPt, Color.YellowGreen, 0.0f); } else { gxtDebugDrawer.Singleton.AddRay(ray, Color.Green, 0.0f); gxtLog.WriteLineV(gxtVerbosityLevel.INFORMATIONAL, "no intersection"); } Color aabbColor = new Color(100, 0, 0, 100); //new Color(1.0f, 0.0f, 0.0f, 1.0f); gxtDebugDrawer.Singleton.AddAABB(geomA.AABB, aabbColor, 1.0f); #endif gxtDebugDrawer.Singleton.AddPolygon(geomA.Polygon, geomAColor, 0.5f); gxtDebugDrawer.Singleton.AddPolygon(geomB.Polygon, geomBColor, 0.5f); float scalar = 0.85f; gxtDebugDrawer.Singleton.AddLine(bodyA.Position, bodyA.Position + forceBeforeClear * scalar, Color.Blue, 0.0f); //gxtDebugDrawer.Singleton.AddPolygon(geomB.Polygon, color, 0.5f); //gxtDebugDrawer.Singleton.AddString(geomB.Position.ToString(), geomB.Position, Color.White, 0.0f); //gxtLog.WriteLineV(gxtVerbosityLevel.INFORMATIONAL, "{0}", float.Epsilon); string fpsString = "FPS: " + gxtDebug.GetFPS().ToString(); Vector2 strSize = gxtDebugDrawer.Singleton.DebugFont.MeasureString(fpsString); strSize *= 0.5f; Vector2 topLeftCorner = new Vector2(-gxtDisplayManager.Singleton.ResolutionWidth * 0.5f, -gxtDisplayManager.Singleton.ResolutionHeight * 0.5f); gxtDebugDrawer.Singleton.AddString("FPS: " + gxtDebug.GetFPS(), topLeftCorner + strSize, Color.White, 0.0f); topLeftCorner += new Vector2(0.0f, strSize.Y); string infoString = "Use Arrow Keys To Move The Polygon"; strSize = gxtDebugDrawer.Singleton.DebugFont.MeasureString(infoString); strSize *= 0.5f; gxtDebugDrawer.Singleton.AddString(infoString, topLeftCorner + strSize + new Vector2(0, 1.0f), Color.White, 0.0f); topLeftCorner += new Vector2(0.0f, strSize.Y); string infoString2 = "Use Mouse To Aim the Ray, C To Change Its Position"; strSize = gxtDebugDrawer.Singleton.DebugFont.MeasureString(infoString2); strSize *= 0.5f; gxtDebugDrawer.Singleton.AddString(infoString2, topLeftCorner + strSize + new Vector2(0, 2.0f), Color.White, 0.0f); //topLeftCorner += new Vector2(0.0f, gxtDebugDrawer.Singleton.DebugFont.MeasureString("FPS").Y); //gxtDebugDrawer.Singleton.AddString("Use Mouse To Aim the Ray", topLeftCorner, Color.White, 0.0f); world.LateUpdate(gameTime); }
/// <summary> /// A ray - line segment intersection test /// Used as a support function for polygon raycasting /// </summary> /// <param name="ray">Ray</param> /// <param name="pt0">First Point of the Segment</param> /// <param name="pt1">Second Point of the Segment</param> /// <param name="t">Distance</param> /// <param name="tmax">Max Distance</param> /// <returns>If intersecting</returns> public bool RayIntersectsSegment(gxtRay ray, Vector2 pt0, Vector2 pt1, out float t, float tmax = float.MaxValue) { Vector2 seg = pt1 - pt0; Vector2 segPerp = gxtMath.LeftPerp(seg); float perpDotd = Vector2.Dot(ray.Direction, segPerp); if (gxtMath.Equals(perpDotd, 0.0f, float.Epsilon)) { t = float.MaxValue; return false; } Vector2 d = pt0 - ray.Origin; t = Vector2.Dot(segPerp, d) / perpDotd; float s = Vector2.Dot(gxtMath.LeftPerp(ray.Direction), d) / perpDotd; return t >= 0.0f && t <= tmax && s >= 0.0f && s <= 1.0f; }
public static bool RayCast(gxtRay ray, gxtPolygon polygon, float tmax, out float t, out Vector2 pt, out Vector2 normal) { t = float.MaxValue; pt = ray.Origin; normal = ray.Direction; bool intersection = false; // temp holder for segment distance float distance; int crossings = 0; for (int j = polygon.NumVertices - 1, i = 0; i < polygon.NumVertices; j = i, i++) { if (RayIntersectsSegment(ray, polygon.v[j], polygon.v[i], float.MaxValue, out distance)) { crossings++; if (distance < t && distance <= tmax) { intersection = true; t = distance; pt = ray.GetPoint(t); Vector2 edge = polygon.v[i] - polygon.v[j]; normal = Vector2.Normalize(gxtMath.RightPerp(edge)); //normal = gxtMath.GetReflection(ray.Direction, edgeNormal); } } } return intersection && crossings > 0 && crossings % 2 == 0; }
public static bool RayCast(gxtRay ray, gxtPolygon polygon, float tmax, out float t) { t = float.MaxValue; bool intersection = false; int crossings = 0; float distance; for (int j = polygon.NumVertices - 1, i = 0; i < polygon.NumVertices; j = i, i++) { if (RayIntersectsSegment(ray, polygon.v[j], polygon.v[i], float.MaxValue, out distance)) { crossings++; if (distance < tmax) intersection = true; if (distance < t) t = distance; } } return intersection && crossings > 0 && crossings % 2 == 0; }
public static bool RayCast(gxtRay ray, gxtPolygon polygon) { //if (polygon.Contains(ray.Origin)) // return false; int crossings = 0; for (int j = polygon.NumVertices - 1, i = 0; i < polygon.NumVertices; j = i, i++) { if (RayIntersectsSegment(ray, polygon.v[j], polygon.v[i])) crossings++; } return crossings > 0 && crossings % 2 == 0; }
/// <summary> /// http://objectmix.com/graphics/132701-ray-line-segment-intersection-2d.html#post460607 /// </summary> /// <param name="ray"></param> /// <param name="a"></param> /// <param name="b"></param> /// <returns></returns> public static bool RayIntersectsSegment(gxtRay ray, Vector2 pt0, Vector2 pt1) { return RayIntersectsSegment(ray, pt0, pt1, float.MaxValue); }
/// <summary> /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input, and playing audio. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Update(GameTime gameTime) { base.Update(gameTime); gxtDebugDrawer.Singleton.CurrentSceneId = debugDrawerId; foreach (gxtISceneNode r in nodes) { r.SetColor(Color.Blue); } gxtKeyboard kb = gxtKeyboardManager.Singleton.GetKeyboard(); float tx = 0.0f, ty = 0.0f; float cameraSpeed = 3.0f; if (kb.IsDown(Keys.A)) tx -= cameraSpeed; if (kb.IsDown(Keys.W)) ty -= cameraSpeed; if (kb.IsDown(Keys.D)) tx += cameraSpeed; if (kb.IsDown(Keys.S)) ty += cameraSpeed; if (kb.IsDown(Keys.Q)) camera.Rotation -= 0.005f; if (kb.IsDown(Keys.E)) camera.Rotation += 0.005f; if (kb.IsDown(Keys.Z)) camera.Zoom += 0.01f; if (kb.IsDown(Keys.C)) camera.Zoom = gxtMath.Min(gxtCamera.MIN_CAMERA_SCALE, camera.Zoom - 0.01f); if (kb.GetState(Keys.Tab) == gxtControlState.FIRST_PRESSED) gxtDisplayManager.Singleton.SetResolution(1280, 720, false); if (kb.GetState(Keys.CapsLock) == gxtControlState.FIRST_PRESSED) gxtDisplayManager.Singleton.SetResolution(800, 600, false); if (kb.GetState(Keys.T) == gxtControlState.FIRST_PRESSED) gxtLog.WriteLineV(gxtVerbosityLevel.INFORMATIONAL, drawableCollider.DebugTrace()); if (kb.GetState(Keys.I) == gxtControlState.FIRST_PRESSED) drawIntervals = !drawIntervals; if (kb.GetState(Keys.B) == gxtControlState.FIRST_PRESSED) drawBoundingBoxes = !drawBoundingBoxes; if (kb.GetState(Keys.P) == gxtControlState.FIRST_PRESSED) gxtLog.WriteLineV(gxtVerbosityLevel.INFORMATIONAL, drawableCollider.DebugTracePairs()); camera.TranslateLocal(tx, ty); gxtOBB camOBB = camera.GetViewOBB(); camOBB.Extents *= 0.95f; gxtAABB camAABB = camera.GetViewAABB(); camAABB.Extents *= 0.95f; gxtLog.WriteLineV(gxtVerbosityLevel.WARNING, "Zoom: {0}", camera.Zoom); gxtDebugDrawer.Singleton.AddOBB(camOBB, Color.Yellow, 0.0f); gxtDebugDrawer.Singleton.AddAABB(camAABB, Color.Red, 0.0f); gxtDebugDrawer.Singleton.AddAxes(camera.Position, camera.Rotation, Color.Red, Color.Green, 0.0f); //gxtLog.WriteLineV(gxtVerbosityLevel.CRITICAL, "Camera Rotation: {0}", camera.Rotation.ToString()); gxtAABB cameraAABB = camera.GetViewAABB(); float cameraYBoundary = cameraAABB.Max.Y; float cameraXBoundary = cameraAABB.Max.X; gxtMouse mouse = gxtMouseManager.Singleton.GetMouse(); Vector2 virtualMousePos = camera.GetVirtualMousePosition(mouse.GetPosition()); gxtDebugDrawer.Singleton.AddPt(virtualMousePos, Color.Yellow, 0.0f); if (mouse.GetState(gxtMouseButton.LEFT) == gxtControlState.FIRST_PRESSED) { foreach (gxtISceneNode drawable in nodes) { gxtAABB aabb = drawable.GetAABB(); if (aabb.Contains(virtualMousePos)) { currentSelection = drawable; currentSelection.SetColor(Color.Green); //currentSelection.ColorOverlay = Color.Green; //currentSelection = drawable as gxtRectangle; //currentSelection.ColorOverlay = Color.Green; } } } else if (mouse.GetState(gxtMouseButton.LEFT) == gxtControlState.DOWN) { if (currentSelection != null) { if (kb.GetState(Keys.Delete) == gxtControlState.FIRST_PRESSED) { drawableCollider.RemoveObject(currentSelection); sceneGraph.RemoveNode(currentSelection); nodes.Remove(currentSelection); currentSelection = null; //drawManager.Remove(currentSelection); //drawables.Remove(currentSelection); //currentSelection = null; } else { Vector2 prevVirtualMousePos = camera.GetVirtualMousePosition(new Vector2(mouse.PrevState.X, mouse.PrevState.Y)); Vector2 d = virtualMousePos - prevVirtualMousePos; currentSelection.Position += d; gxtAABB aabb = currentSelection.GetAABB(); drawableCollider.UpdateObject(currentSelection, ref aabb); currentSelection.SetColor(Color.Green); //currentSelection.ColorOverlay = Color.Green; } } } else if (mouse.IsUp(gxtMouseButton.LEFT)) { if (currentSelection != null) { currentSelection.SetColor(Color.Blue); currentSelection = null; } } foreach (gxtISceneNode drawable in nodes) { if (drawBoundingBoxes) gxtDebugDrawer.Singleton.AddAABB(drawable.GetAABB(), new Color(255, 0, 0, 100), 1.0f); } if (drawIntervals) drawableCollider.DebugDraw(Color.White, Color.Red, cameraYBoundary, cameraXBoundary); #if RAY_CAST_TEST Vector2 rayOrigin = new Vector2(-100.0f, 0.0f); Vector2 direction = virtualMousePos - rayOrigin; direction.Normalize(); gxtRay ray = new gxtRay(rayOrigin, direction); List<gxtISceneNode> rayHits = drawableCollider.RayCastAll(ray); if (rayHits.Count != 0) { for (int i = 0; i < rayHits.Count; i++) { rayHits[i].SetColor(Color.Orange, false); gxtLog.WriteLineV(gxtVerbosityLevel.WARNING, "Num Ray Hits: {0}", rayHits.Count); //gxtRectangle rect = rayHits[i] as gxtRectangle; //rect.ColorOverlay = Color.Orange; } gxtDebugDrawer.Singleton.AddRay(ray, float.MaxValue, Color.Green, 0.0f); } else { gxtDebugDrawer.Singleton.AddRay(ray, Color.Green, 0.0f); } #else gxtBroadphaseCollisionPair<gxtISceneNode>[] rectPairs = drawableCollider.GetCollisionPairs(); foreach (gxtBroadphaseCollisionPair<gxtISceneNode> rectPair in rectPairs) { rectPair.objA.ColorOverlay = Color.Orange; rectPair.objB.ColorOverlay = Color.Orange; gxtDebugDrawer.Singleton.AddPt(rectPair.objA.GetAABB().Position, Color.Yellow, 0.0f); } #endif //drawManager.Update(); // fps at top left /* string fpsString = "FPS: " + gxtDebug.GetFPS().ToString(); Vector2 strSize = gxtDebugDrawer.Singleton.DebugFont.MeasureString(fpsString); strSize *= 0.5f; Vector2 topLeftCorner = new Vector2(-gxtDisplayManager.Singleton.WindowWidth * 0.5f, -gxtDisplayManager.Singleton.WindowHeight * 0.5f); topLeftCorner += camera.Position; gxtDebugDrawer.Singleton.AddString("FPS: " + gxtDebug.GetFPS(), topLeftCorner + strSize, Color.White, 0.0f); */ sceneGraph.Update(gameTime); }