/// <summary> /// Constructor for collision data. /// </summary> /// <param name="sender">The shape responsible for the collision.</param> /// <param name="recipient">The recipient shape of the collision.</param> /// <param name="axis">The axis of the collision.</param> /// <param name="overlap">The overlap of the collision on the specified axis.</param> public CollisionData(Shape sender, Shape recipient, Vector2 axis, float overlap) : this() { // Set the variables. Sender = sender; Recipient = recipient; Axis = axis; Overlap = overlap; HasCollision = false; }
/// <summary> /// Check if this shape is intersecting another. /// </summary> /// <param name="shape">The other shape to check collisions with.</param> /// <returns>Whether the two shapes intersect each other.</returns> public bool Intersects(Shape shape) { // Create the two base rectangles. Rectangle rect1 = new Rectangle((int)(shape.Position.X - shape.Width / 2), (int)(shape.Position.Y - shape.Height / 2), (int)shape.Width, (int)shape.Height); Rectangle rect2 = new Rectangle((int)_Position.X, (int)_Position.Y, (int)_Width, (int)_Height); // If they intersect, continue. if (rect1.Intersects(rect2)) { return true; } // No intersection at this point. return false; }
/// <summary> /// Calculates an intersection rectangle from between the given shape and this instance. If no intersection exists null is returned. /// </summary> /// <param name="shape">The shape to get an intersection from.</param> /// <returns>The intersection rectangle.</returns> public Rectangle GetIntersection(Shape shape) { // Create the two base rectangles. Rectangle rect1 = new Rectangle((int)shape.Position.X, (int)shape.Position.Y, (int)shape.Width, (int)shape.Height); Rectangle rect2 = new Rectangle((int)_Position.X, (int)_Position.Y, (int)_Width, (int)_Height); // Return the intersection rectangle. //return rect1.Intersection(rect2); return rect1; }
/// <summary> /// Compare two shapes by their depth values. Allows margin overlap, ie. same end-point position. /// </summary> /// <param name="s1">The first shape.</param> /// <param name="s2">The second shape.</param> /// <returns>1 if the first shape is located 'higher', -1 if the second shape is 'located' higher and 0 if the shapes overlap.</returns> public static int IsOverlapping(Shape s1, Shape s2) { // The entities' depth data. Vector2 v1 = new Vector2(s1.BottomDepth, Math.Min(s1.GetTopDepth(s1.LayeredPosition), s1.GetTopDepth(s2.LayeredPosition))); Vector2 v2 = new Vector2(s2.BottomDepth, Math.Min(s2.GetTopDepth(s1.LayeredPosition), s2.GetTopDepth(s2.LayeredPosition))); // Compare the shapes to each other. if (!Calculator.IsOverlapping(v1, v2, false)) { if (s1.Position.Z < s2.Position.Z) { return -1; } else if (s1.Position.Z > s2.Position.Z) { return 1; } } // The shapes' overlap, return 0. return 0; }
/// <summary> /// Initialize the body. /// </summary> /// <param name="width">The width of the shape.</param> /// <param name="height">The height of the shape.</param> /// <param name="depth">The depth of the shape.</param> /// <param name="mass">The mass of the body.</param> /// <param name="friction">The friction of the body.</param> /// <param name="physics">The physics simulator that this body will be a part of.</param> protected void Initialize(float width, float height, float depth, float mass, float friction, PhysicsSimulator physics) { // Initialize a couple of variables. _Shape = new Shape(width, height, depth); _IsStatic = false; _IsImmaterial = false; _MaxVelocity = 8; _Mass = mass; _Velocity = new Vector3(0, 0, 0); _FrictionCoefficient = friction; _AccelerationValue = 1; _Physics = physics; _Collisions = new HashSet<Body>(); }
/// <summary> /// Convert from a centroid vector a top-right vector. /// </summary> /// <param name="shape">The shape to use.</param> /// <returns>The position of the shape converted into a top-right format, ignoring rotation.</returns> public static Vector2 ToTopRight(Shape shape) { return new Vector2(shape.Position.X + (shape.Width / 2), shape.Position.Y - (shape.Height / 2)); }
/// <summary> /// Convert from a centroid vector a bottom-left vector. /// </summary> /// <param name="shape">The shape to use.</param> /// <returns>The position of the shape converted into a bottom-left format, ignoring rotation.</returns> public static Vector2 ToBottomLeft(Shape shape) { return new Vector2(shape.Position.X - (shape.Width / 2), shape.Position.Y + (shape.Height / 2)); }
/// <summary> /// Do a narrow phase collision check between two shapes by using SAT (Separating Axis Theorem). /// If a collision has occurred, get the MTV (Minimum Translation Vector) of the two intersecting shapes. /// </summary> /// <param name="s1">The first shape to check.</param> /// <param name="s2">The second shape to check.</param> /// <returns>The MTV of the intersection.</returns> public CollisionData NarrowPhase(Shape s1, Shape s2) { // The minimum amount of overlap. Start real high. float overlap = float.MaxValue; //The collision data. CollisionData data = new CollisionData(s1, s2); // The smallest axis found. Vector2 smallest = Vector2.Zero; try { // Get the axes of both bodies. Vector2[][] axes = new Vector2[][] { s1.GetAxes(), s2.GetAxes() }; // Iterate over the axes of both bodies. foreach (Vector2[] v in axes) { // Iterate over both bodies' axes. foreach (Vector2 a in v) { // Project both bodies onto the axis. Vector2 p1 = s1.Project(a); Vector2 p2 = s2.Project(a); // Get the overlap. float o = Calculator.GetOverlap(p1, p2); // Do the projections overlap? if (o == -1) { // We can guarantee that the shapes do not overlap. return data; } else { // Check for minimum. if (o < overlap) { // Store the minimum overlap and the axis it was projected upon. Make sure that the separation vector is pointing the right way. overlap = o; smallest = a; } } } } } catch (Exception e) { Console.WriteLine(this + ": Narrow Phase Error. (" + e + ")"); } // We now know that every axis had an overlap on it, which means we can guarantee an intersection between the bodies. data.HasCollision = true; data.Axis = smallest; data.Overlap = overlap; //Return the collision data. return data; }
/// <summary> /// Constructor for collision data. /// </summary> /// <param name="sender">The shape responsible for the collision.</param> /// <param name="recipient">The recipient shape of the collision.</param> public CollisionData(Shape sender, Shape recipient) : this(sender, recipient, Vector2.Zero, 0) { }