/// <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(); //if (kb.IsDown(Keys.Down)) //world.Camera.Zoom -= 0.0005f; //else if (kb.IsDown(Keys.Up)) // world.Camera.Zoom += 0.0005f; int dScroll = mouse.GetDeltaScroll(); if (dScroll != 0) { world.GameSpeed = gxtMath.Clamp(world.GameSpeed + (dScroll * 0.05f), 0.05f, 1.0f); } // assume gravity on float force = 10.5f; float torque = 3.5f; bodyA.IgnoreGravity = false; bodyF.IgnoreGravity = false; // otherwise switch if (!gravityOn) { bodyA.IgnoreGravity = true; bodyF.IgnoreGravity = true; force = 6.5f; torque = 1.25f; } if (kb.GetState(Keys.G) == gxtControlState.FIRST_PRESSED) gravityOn = !gravityOn; if (kb.GetState(Keys.C) == gxtControlState.FIRST_PRESSED) { geomA.CollisionResponseEnabled = !geomA.CollisionResponseEnabled; geomF.CollisionResponseEnabled = !geomF.CollisionResponseEnabled; } if (kb.GetState(Keys.F) == gxtControlState.FIRST_PRESSED) { bodyF.FixedRotation = !bodyF.FixedRotation; if (!bodyF.FixedRotation) { bodyF.Inertia = gxtRigidBody.GetInertiaForPolygon(geomF.Polygon, bodyF.Mass); } } Vector2 virtualMousePos = world.Camera.GetVirtualMousePosition(mouse.GetPosition()); if (kb.GetState(Keys.T) == gxtControlState.FIRST_PRESSED) { Vector2 physicsWorldPos = virtualMousePos * gxtPhysicsWorld.ONE_OVER_PHYSICS_SCALE; //physicsWorldPos = (world.Camera.Position + physicsWorldPos) * gxtPhysicsWorld.ONE_OVER_PHYSICS_SCALE; // + (physicsWorldPos * gxtPhysicsWorld.ONE_OVER_PHYSICS_SCALE); float explosionForce = 750.0f; float sphereRadius = 4.5f; List<gxtGeom> hitGeoms; gxtSphere sphere = new gxtSphere(physicsWorldPos, sphereRadius); //gxtAABB box = new gxtAABB(physicsWorldPos, new Vector2(sphereRadius)); float adjustedRadius = sphereRadius * gxtPhysicsWorld.PHYSICS_SCALE; gxtSphere adjustedSphere = new gxtSphere(virtualMousePos, adjustedRadius); Color sphereColor = Color.Blue; if (world.PhysicsWorld.PointCastAll(physicsWorldPos, out hitGeoms)) { //gxtLog.WriteLineV(gxtVerbosityLevel.INFORMATIONAL, "Something was hit..."); sphereColor = Color.Red; for (int i = 0; i < hitGeoms.Count; ++i) { if (hitGeoms[i].HasAttachedBody()) { Vector2 forceToApply = Vector2.Normalize(hitGeoms[i].GetWorldCentroid() - physicsWorldPos) * explosionForce; hitGeoms[i].RigidBody.ApplyForceAtPoint(forceToApply, physicsWorldPos); } } } gxtDebugDrawer.Singleton.AddPt(physicsWorldPos * gxtPhysicsWorld.PHYSICS_SCALE, Color.Blue, 0.0f, System.TimeSpan.FromSeconds(3.0)); gxtDebugDrawer.Singleton.AddSphere(adjustedSphere, sphereColor, 0.5f, TimeSpan.FromSeconds(3.0)); } gxtDebugDrawer.Singleton.AddPt(virtualMousePos, Color.White, 0.0f); bodyA.Damping = damping; 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); float xF = 0.0f, yF = 0.0f, rF = 0.0f; if (kb.IsDown(Keys.A)) xF -= force; if (kb.IsDown(Keys.D)) xF += force; if (kb.IsDown(Keys.W)) yF -= force; if (kb.IsDown(Keys.S)) yF += force; if (kb.IsDown(Keys.Q)) rF -= torque; if (kb.IsDown(Keys.E)) rF += torque; if (kb.GetState(Keys.Space) == gxtControlState.FIRST_PRESSED) { bodyF.Velocity -= new Vector2(0.0f, 8.0f); bodyF.ApplyForce(new Vector2(0.0f, -100.0f)); } if (xF != 0.0f || yF != 0.0f) bodyF.ApplyForce(new Vector2(xF, yF)); if (rF != 0.0f) bodyF.ApplyTorque(rF); //gxtLog.WriteLineV(gxtVerbosityLevel.INFORMATIONAL, "Velocity F: {0}", bodyF.Velocity.ToString()); //bodyA.Translate(new Vector2(xA, yA)); //bodyA.SetRotation(bodyA.Rotation + rA); Vector2 forceBeforeClearA = bodyA.Force; //Vector2 forceBeforeClearF = bodyF.Force; world.PhysicsWorld.DebugDrawGeoms(Color.Yellow, Color.Salmon, Color.Gray, Color.Blue, Color.Red, 0.5f, 0.55f, 0.5f, true, true, false); //world.PhysicsWorld.DebugDrawRigidBodies(Color.White); //gxtLog.WriteLineV(gxtVerbosityLevel.INFORMATIONAL, bodyA.Acceleration.ToString()); //float scalar = 0.85f; /* gxtDebugDrawer.Singleton.AddPolygon(geomA.Polygon, Color.Yellow, 0.5f); gxtDebugDrawer.Singleton.AddPolygon(geomB.Polygon, Color.Yellow, 0.5f); gxtDebugDrawer.Singleton.AddLine(bodyA.Position, bodyA.Position + forceBeforeClearA * scalar, Color.Blue, 0.0f); gxtDebugDrawer.Singleton.AddLine(bodyF.Position, bodyF.Position + forceBeforeClearF * scalar, Color.Blue, 0.0f); gxtDebugDrawer.Singleton.AddPolygon(geomC.Polygon, Color.Yellow, 0.0f); gxtDebugDrawer.Singleton.AddPolygon(geomD.Polygon, Color.Yellow, 0.0f); gxtDebugDrawer.Singleton.AddPolygon(geomE.Polygon, Color.Yellow, 0.0f); gxtDebugDrawer.Singleton.AddPolygon(geomF.Polygon, Color.Yellow, 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); //gxtDebugDrawer.Singleton.AddString("Velocity: " + bodyF.Velocity.ToString(), Vector2.Zero, Color.White, 0.0f); //gxtDebugDrawer.Singleton.AddString(""); //xna reach profile has no alpha transparency! //world.Physics.DebugDrawGeoms(Color.Yellow, 0.5f, new Color(0.0f, 0.0f, 1.0f, 0.25f), 0.51f, true); world.Update(gameTime); world.LateUpdate(gameTime); }
/// <summary> /// Computes a sphere given a set of vertices/points /// </summary> /// <param name="ptSet">enumerator of points</param> /// <returns>sphere for the point set</returns> public static gxtSphere ComputeSphere(IEnumerator<Vector2> ptSet) { // Find most distant points on AABB Vector2 min, max; GetMostDistantPoints(out min, out max, ptSet); // Constructs initial sphere from distant points Vector2 c = (min + max) * 0.5f; float r = Vector2.Distance(max, c); gxtSphere sphere = new gxtSphere(c, r); ptSet.Reset(); // Check to include all points in circle while (ptSet.MoveNext()) { MakeSphereIncludePt(ref sphere, ptSet.Current); } return sphere; }
/// <summary> /// Enlarges the sphere to include itself and the outside point /// if it is outside the existing sphere. /// </summary> /// <param name="sphere">sphere</param> /// <param name="pt">Pt in set</param> public static void MakeSphereIncludePt(ref gxtSphere sphere, Vector2 pt) { Vector2 diff = pt - sphere.Position; float distSq = diff.LengthSquared(); // Contains check if (distSq > sphere.Radius * sphere.Radius) { float dist = gxtMath.Sqrt(distSq); // New radius half the sum of this distance and old // Works because position will also be adjusted float adjRadius = (sphere.Radius + dist) * 0.5f; // Adjust position by component vector sphere.Position += diff * ((adjRadius - sphere.Radius) / dist); sphere.Radius = adjRadius; } }
/// <summary> /// Sphere intersection test which calculates t and the intersection point /// The normal can later be found with Normalize(pt - sphere.Position) /// </summary> /// <param name="sphere">Sphere</param> /// <param name="t">Max Distance</param> /// <param name="pt">Contact Point</param> /// <returns>If intersecting</returns> public bool IntersectsSphere(gxtSphere sphere, out float t, out Vector2 pt) { Vector2 m = origin - sphere.Position; float b = Vector2.Dot(m, direction); float c = m.LengthSquared(); if (c > 0.0f && b > 0.0f) { t = 0.0f; pt = origin; return false; } float discr = b * b - c; if (discr < 0.0f) { t = 0.0f; pt = origin; return false; } t = -b - gxtMath.Sqrt(discr); if (t < 0.0f) t = 0.0f; pt = GetPoint(t); return true; }
/// <summary> /// Computes a sphere given a set of vertices/points /// </summary> /// <param name="ptSet">array of points</param> /// <returns>sphere for the point set</returns> public static gxtSphere ComputeSphere(Vector2[] ptSet) { // Find most distant points on AABR int min, max; GetMostDistantPoints(out min, out max, ptSet); // Constructs initial circle from distant points Vector2 c = (ptSet[min] + ptSet[max]) * 0.5f; float r = Vector2.Distance(ptSet[max], c); gxtSphere sphere = new gxtSphere(c, r); // Check to include all points in circle for (int i = 0; i < ptSet.Length; i++) { MakeSphereIncludePt(ref sphere, ptSet[i]); } return sphere; }
/// <summary> /// A fast boolean intersection test that omits an expensive square root call /// However, it does not return values for t and the contact point /// </summary> /// <param name="sphere">Sphere</param> /// <returns>If intersecting</returns> public bool IntersectsSphere(gxtSphere sphere) { Vector2 m = origin - sphere.Position; float c = m.LengthSquared() - sphere.Radius * sphere.Radius; if (c <= 0.0f) return true; float b = Vector2.Dot(m, direction); if (b > 0.0f) return false; float disc = b * b - c; if (disc < 0.0f) return false; return true; }
public static bool Intersects(ref gxtPolygon polygon, Vector2 centroid, gxtSphere sphere) { if (Contains(polygon, sphere.Position)) return true; float r2 = sphere.Radius * sphere.Radius; for (int j = polygon.NumVertices - 1, i = 0; i < polygon.NumVertices; j = i, i++) { Vector2 edgeVector = polygon.v[i] - polygon.v[j]; Vector2 edgeNormal = Vector2.Normalize(gxtMath.RightPerp(edgeVector)); float edgeDistance = gxtMath.Abs(Vector2.Dot(polygon.v[j], edgeNormal)); // void PointEdgeDistance(const Vector& P, const Vector& E0, const Vector& E1, Vector& Q, float& dist2){ Vector D = P - E0; Vector E = E1 - E0; float e2 = E * E; float ed = E * D; float t = (ed / e2); t = (t < 0.0)? 0.0f : (t > 1.0f)? : 1.0f : t; Q = E0 + t * E; Vector PQ = Q - P; dist2 = PQ * PQ;} if (edgeDistance <= r2) 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> /// /// </summary> /// <param name="sphere"></param> /// <param name="hitGeom"></param> /// <param name="collisionGroupName"></param> /// <returns></returns> public bool SphereCast(gxtSphere sphere, out gxtGeom hitGeom, string collisionGroupName) { gxtDebug.Assert(collisionGroupsMap.ContainsKey(collisionGroupName), "Named Collision Group: {0} Does Not Exist In Physics World"); gxtCollisionGroup cgroup = collisionGroupsMap[collisionGroupName]; return SphereCast(sphere, out hitGeom, cgroup); }
/// <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; }