// Check if polygon A is going to collide with polygon B for the given velocity public static PolygonCollisionResult PolygonCollision(Polygon polygonA, Polygon polygonB, Vector velocity) { // TODO - Do stuff with polygonC and polygonD - they're meant to be the bow and stern and take less damage // Get Nick to explain the for loop PolygonCollisionResult result = new PolygonCollisionResult(); result.Intersect = true; result.WillIntersect = true; int edgeCountA = polygonA.Edges.Count; int edgeCountB = polygonB.Edges.Count; float minIntervalDistance = float.PositiveInfinity; Vector translationAxis = new Vector(); Vector edge; // Loop through all the edges of both polygons for (int edgeIndex = 0; edgeIndex < edgeCountA + edgeCountB; edgeIndex++) { if (edgeIndex < edgeCountA) { edge = polygonA.Edges[edgeIndex]; } else { edge = polygonB.Edges[edgeIndex - edgeCountA]; } // ===== 1. Find if the polygons are currently intersecting ===== // Find the axis perpendicular to the current edge Vector axis = new Vector(-edge.Y, edge.X); axis.Normalize(); // Find the projection of the polygon on the current axis float minA = 0; float minB = 0; float maxA = 0; float maxB = 0; ProjectPolygon(axis, polygonA, ref minA, ref maxA); ProjectPolygon(axis, polygonB, ref minB, ref maxB); // Check if the polygon projections are currentlty intersecting if (IntervalDistance(minA, maxA, minB, maxB) > 0) { result.Intersect = false; } // ===== 2. Now find if the polygons *will* intersect ===== // Project the velocity on the current axis float velocityProjection = axis.DotProduct(velocity); // Get the projection of polygon A during the movement if (velocityProjection < 0) { minA += velocityProjection; } else { maxA += velocityProjection; } // Do the same test as above for the new projection float intervalDistance = IntervalDistance(minA, maxA, minB, maxB); if (intervalDistance > 0) { result.WillIntersect = false; } // If the polygons are not intersecting and won't intersect, exit the loop if (!result.Intersect && !result.WillIntersect) { break; } // Check if the current interval distance is the minimum one. If so store // the interval distance and the current distance. // This will be used to calculate the minimum translation vector intervalDistance = Math.Abs(intervalDistance); if (intervalDistance < minIntervalDistance) { minIntervalDistance = intervalDistance; translationAxis = axis; Vector d = polygonA.Center - polygonB.Center; if (d.DotProduct(translationAxis) < 0) { translationAxis = -translationAxis; } } } // The minimum translation vector can be used to push the polygons appart. // First moves the polygons by their velocity // then move polygonA by MinimumTranslationVector. if (result.WillIntersect) { result.MinimumTranslationVector = translationAxis * minIntervalDistance; } return(result); }
/// <summary> /// Performed before drawing to move all animations onto the next timestep. /// </summary> /// <param name="elapsedMilliseconds">Time elapsed.</param> private void PerformAnimationStep(double elapsedMilliseconds) { if (_aPressed) { _data.Ships[2].Angle -= (float)(elapsedMilliseconds / 1000) * _data.Settings.TurnSpeed; if (_data.Ships[2].Angle < 0) { _data.Ships[2].Angle += 360; } } if (_dPressed) { _data.Ships[2].Angle += (float)(elapsedMilliseconds / 1000) * _data.Settings.TurnSpeed; if (_data.Ships[2].Angle > 360) { _data.Ships[2].Angle -= 360; } } if (_wPressed) { _data.Ships[2].Speed += (float)(elapsedMilliseconds / 1000) * _data.Settings.Acceleration; if (_data.Ships[2].Speed > _data.Settings.MaxSpeed) { _data.Ships[2].Speed = _data.Settings.MaxSpeed; } } if (_sPressed) { _data.Ships[2].Speed -= (float)(elapsedMilliseconds / 1000) * _data.Settings.Deceleration; if (_data.Ships[2].Speed < -_data.Settings.MaxReverseSpeed) { _data.Ships[2].Speed = -_data.Settings.MaxReverseSpeed; } } if (_qPressed) { if (_data.Ships[2].Reload <= 0) { _data.Cannonballs.Add(_data.Ships[2].FireCannonball(_data.Settings, _data.Ships[2].Angle - 90)); } } if (_ePressed) { if (_data.Ships[2].Reload <= 0) { _data.Cannonballs.Add(_data.Ships[2].FireCannonball(_data.Settings, _data.Ships[2].Angle + 90)); } } if (_data.Ships[2].Reload > 0) { _data.Ships[2].Reload -= (float)elapsedMilliseconds / 1000F; } foreach (var ship in _data.Ships) { var originalLocation = new PointF(ship.X, ship.Y); ship.MoveShip((float)elapsedMilliseconds / 1000F); var newLocation = new PointF(ship.X, ship.Y); var velocity = new Vector(newLocation.X - originalLocation.X, newLocation.Y - originalLocation.Y); var shipPolygon_hull = new Polygon(); shipPolygon_hull.Points.Add(new Vector(-20, -20)); shipPolygon_hull.Points.Add(new Vector(20, -20)); shipPolygon_hull.Points.Add(new Vector(20, 20)); shipPolygon_hull.Points.Add(new Vector(-20, 20)); shipPolygon_hull.Rotate(ship.Angle); shipPolygon_hull.Offset(ship.X, ship.Y); shipPolygon_hull.BuildEdges(); var shipPolygon_bow = new Polygon(); shipPolygon_bow.Points.Add(new Vector(20, 20)); shipPolygon_bow.Points.Add(new Vector(0, 60)); shipPolygon_bow.Points.Add(new Vector(0, 60)); shipPolygon_bow.Points.Add(new Vector(-20, 20)); shipPolygon_bow.Rotate(ship.Angle); shipPolygon_bow.Offset(ship.X, ship.Y); shipPolygon_bow.BuildEdges(); var shipPolygon_stern = new Polygon(); shipPolygon_stern.Points.Add(new Vector(-20, -20)); shipPolygon_stern.Points.Add(new Vector(0, -50)); shipPolygon_stern.Points.Add(new Vector(0, -50)); shipPolygon_stern.Points.Add(new Vector(20, -20)); shipPolygon_stern.Rotate(ship.Angle); shipPolygon_stern.Offset(ship.X, ship.Y); shipPolygon_stern.BuildEdges(); // Check for collisions with other ships foreach (var otherShip in _data.Ships) { if (otherShip == ship) { continue; } var otherShipPolygon_hull = new Polygon(); otherShipPolygon_hull.Points.Add(new Vector(-20, -20)); otherShipPolygon_hull.Points.Add(new Vector(20, -20)); otherShipPolygon_hull.Points.Add(new Vector(20, 20)); otherShipPolygon_hull.Points.Add(new Vector(-20, 20)); otherShipPolygon_hull.Rotate(otherShip.Angle); otherShipPolygon_hull.Offset(otherShip.X, otherShip.Y); otherShipPolygon_hull.BuildEdges(); // Point(20, 20), new Point(0, 50), new Point(0, 50), new Point(-20, 20) var otherShipPolygon_bow = new Polygon(); otherShipPolygon_bow.Points.Add(new Vector(20, 20)); otherShipPolygon_bow.Points.Add(new Vector(0, 60)); otherShipPolygon_bow.Points.Add(new Vector(0, 60)); otherShipPolygon_bow.Points.Add(new Vector(-20, 20)); otherShipPolygon_bow.Rotate(otherShip.Angle); otherShipPolygon_bow.Offset(otherShip.X, otherShip.Y); otherShipPolygon_bow.BuildEdges(); var otherShipPolygon_stern = new Polygon(); otherShipPolygon_stern.Points.Add(new Vector(-20, -20)); otherShipPolygon_stern.Points.Add(new Vector(0, -50)); otherShipPolygon_stern.Points.Add(new Vector(0, -50)); otherShipPolygon_stern.Points.Add(new Vector(20, -20)); otherShipPolygon_stern.Rotate(otherShip.Angle); otherShipPolygon_stern.Offset(otherShip.X, otherShip.Y); otherShipPolygon_stern.BuildEdges(); // TODO - Make an "anypart" polygon instead of having polygons for each // TODO - reduce damage taken by otherShip's bow and stern PolygonCollisionResult h_hull = Collisions.PolygonCollision(shipPolygon_hull, otherShipPolygon_hull, velocity); PolygonCollisionResult h_bow = Collisions.PolygonCollision(shipPolygon_hull, otherShipPolygon_bow, velocity); PolygonCollisionResult h_stern = Collisions.PolygonCollision(shipPolygon_hull, otherShipPolygon_stern, velocity); PolygonCollisionResult b_hull = Collisions.PolygonCollision(shipPolygon_bow, otherShipPolygon_hull, velocity); PolygonCollisionResult b_bow = Collisions.PolygonCollision(shipPolygon_bow, otherShipPolygon_bow, velocity); PolygonCollisionResult b_stern = Collisions.PolygonCollision(shipPolygon_bow, otherShipPolygon_stern, velocity); PolygonCollisionResult s_hull = Collisions.PolygonCollision(shipPolygon_stern, otherShipPolygon_hull, velocity); PolygonCollisionResult s_bow = Collisions.PolygonCollision(shipPolygon_stern, otherShipPolygon_bow, velocity); PolygonCollisionResult s_stern = Collisions.PolygonCollision(shipPolygon_stern, otherShipPolygon_stern, velocity); if (h_hull.WillIntersect) { //playerTranslation = velocity + r.MinimumTranslationVector; ship.X += velocity.X + h_hull.MinimumTranslationVector.X / 2.0F; ship.Y += velocity.Y + h_hull.MinimumTranslationVector.Y / 2.0F; otherShip.X -= h_hull.MinimumTranslationVector.X / 2.0F; otherShip.Y -= h_hull.MinimumTranslationVector.Y / 2.0F; // Slow the ship down since it's hit it. if (ship.Speed > 0) { if (ship.Speed > _data.Settings.MaxSpeed / 2) { otherShip.Health -= (ship.Speed - (_data.Settings.MaxSpeed / 2)) * (float)(1000.0 * (elapsedMilliseconds / 100000)); } ship.Speed -= (float)(1000.0 * (elapsedMilliseconds / 1000)); if (ship.Speed < 0) { ship.Speed = 0; } } break; } if (h_bow.WillIntersect) { //playerTranslation = velocity + r.MinimumTranslationVector; ship.X += velocity.X + h_bow.MinimumTranslationVector.X / 2.0F; ship.Y += velocity.Y + h_bow.MinimumTranslationVector.Y / 2.0F; otherShip.X -= h_bow.MinimumTranslationVector.X / 2.0F; otherShip.Y -= h_bow.MinimumTranslationVector.Y / 2.0F; // Slow the ship down if (ship.Speed > 0) { if (ship.Speed > _data.Settings.MaxSpeed / 2) { otherShip.Health -= (ship.Speed - (_data.Settings.MaxSpeed / 2)) * (float)(1000.0 * (elapsedMilliseconds / 100000)); } ship.Speed -= (float)(1000.0 * (elapsedMilliseconds / 1000)); if (ship.Speed < 0) { ship.Speed = 0; } } break; } if (h_stern.WillIntersect) { //playerTranslation = velocity + r.MinimumTranslationVector; ship.X += velocity.X + h_stern.MinimumTranslationVector.X / 2.0F; ship.Y += velocity.Y + h_stern.MinimumTranslationVector.Y / 2.0F; otherShip.X -= h_stern.MinimumTranslationVector.X / 2.0F; otherShip.Y -= h_stern.MinimumTranslationVector.Y / 2.0F; // Slow the ship down if (ship.Speed > 0) { if (ship.Speed > _data.Settings.MaxSpeed / 2) { otherShip.Health -= (ship.Speed - (_data.Settings.MaxSpeed / 2)) * (float)(1000.0 * (elapsedMilliseconds / 100000)); } ship.Speed -= (float)(1000.0 * (elapsedMilliseconds / 1000)); if (ship.Speed < 0) { ship.Speed = 0; } } break; } /* shopPolygon_bow */ if (b_hull.WillIntersect) { //playerTranslation = velocity + r.MinimumTranslationVector; ship.X += velocity.X + b_hull.MinimumTranslationVector.X / 2.0F; ship.Y += velocity.Y + b_hull.MinimumTranslationVector.Y / 2.0F; otherShip.X -= b_hull.MinimumTranslationVector.X / 2.0F; otherShip.Y -= b_hull.MinimumTranslationVector.Y / 2.0F; // Slow the ship down since it's hit it. if (ship.Speed > 0) { if (ship.Speed > _data.Settings.MaxSpeed / 2) { otherShip.Health -= (ship.Speed - (_data.Settings.MaxSpeed / 2)) * (float)(1000.0 * (elapsedMilliseconds / 100000)); } ship.Speed -= (float)(1000.0 * (elapsedMilliseconds / 1000)); if (ship.Speed < 0) { ship.Speed = 0; } } break; } if (b_bow.WillIntersect) { //playerTranslation = velocity + r.MinimumTranslationVector; ship.X += velocity.X + b_bow.MinimumTranslationVector.X / 2.0F; ship.Y += velocity.Y + b_bow.MinimumTranslationVector.Y / 2.0F; otherShip.X -= b_bow.MinimumTranslationVector.X / 2.0F; otherShip.Y -= b_bow.MinimumTranslationVector.Y / 2.0F; // Slow the ship down if (ship.Speed > 0) { if (ship.Speed > _data.Settings.MaxSpeed / 2) { otherShip.Health -= (ship.Speed - (_data.Settings.MaxSpeed / 2)) * (float)(1000.0 * (elapsedMilliseconds / 100000)); } ship.Speed -= (float)(1000.0 * (elapsedMilliseconds / 1000)); if (ship.Speed < 0) { ship.Speed = 0; } } break; } if (b_stern.WillIntersect) { //playerTranslation = velocity + r.MinimumTranslationVector; ship.X += velocity.X + b_stern.MinimumTranslationVector.X / 2.0F; ship.Y += velocity.Y + b_stern.MinimumTranslationVector.Y / 2.0F; otherShip.X -= b_stern.MinimumTranslationVector.X / 2.0F; otherShip.Y -= b_stern.MinimumTranslationVector.Y / 2.0F; // Slow the ship down if (ship.Speed > 0) { if (ship.Speed > _data.Settings.MaxSpeed / 2) { otherShip.Health -= (ship.Speed - (_data.Settings.MaxSpeed / 2)) * (float)(1000.0 * (elapsedMilliseconds / 100000)); } ship.Speed -= (float)(1000.0 * (elapsedMilliseconds / 1000)); if (ship.Speed < 0) { ship.Speed = 0; } } break; } /* shipPolygon_stern */ if (s_hull.WillIntersect) { //playerTranslation = velocity + r.MinimumTranslationVector; ship.X += velocity.X + s_hull.MinimumTranslationVector.X / 2.0F; ship.Y += velocity.Y + s_hull.MinimumTranslationVector.Y / 2.0F; otherShip.X -= s_hull.MinimumTranslationVector.X / 2.0F; otherShip.Y -= s_hull.MinimumTranslationVector.Y / 2.0F; // Slow the ship down since it's hit it. if (ship.Speed > 0) { if (ship.Speed > _data.Settings.MaxSpeed / 2) { otherShip.Health -= (ship.Speed - (_data.Settings.MaxSpeed / 2)) * (float)(1000.0 * (elapsedMilliseconds / 100000)); } ship.Speed -= (float)(1000.0 * (elapsedMilliseconds / 1000)); if (ship.Speed < 0) { ship.Speed = 0; } } break; } if (s_bow.WillIntersect) { //playerTranslation = velocity + r.MinimumTranslationVector; ship.X += velocity.X + s_bow.MinimumTranslationVector.X / 2.0F; ship.Y += velocity.Y + s_bow.MinimumTranslationVector.Y / 2.0F; otherShip.X -= s_bow.MinimumTranslationVector.X / 2.0F; otherShip.Y -= s_bow.MinimumTranslationVector.Y / 2.0F; // Slow the ship down if (ship.Speed > 0) { if (ship.Speed > _data.Settings.MaxSpeed / 2) { otherShip.Health -= (ship.Speed - (_data.Settings.MaxSpeed / 2)) * (float)(1000.0 * (elapsedMilliseconds / 100000)); } ship.Speed -= (float)(1000.0 * (elapsedMilliseconds / 1000)); if (ship.Speed < 0) { ship.Speed = 0; } } break; } if (s_stern.WillIntersect) { //playerTranslation = velocity + r.MinimumTranslationVector; ship.X += velocity.X + s_stern.MinimumTranslationVector.X / 2.0F; ship.Y += velocity.Y + s_stern.MinimumTranslationVector.Y / 2.0F; otherShip.X -= s_stern.MinimumTranslationVector.X / 2.0F; otherShip.Y -= s_stern.MinimumTranslationVector.Y / 2.0F; // Slow the ship down if (ship.Speed > 0) { if (ship.Speed > _data.Settings.MaxSpeed / 2) { otherShip.Health -= (ship.Speed - (_data.Settings.MaxSpeed / 2)) * (float)(1000.0 * (elapsedMilliseconds / 100000)); } ship.Speed -= (float)(1000.0 * (elapsedMilliseconds / 1000)); if (ship.Speed < 0) { ship.Speed = 0; } } break; } } } // Check for otherShip collision with cannonballs for (var i = 0; i < _data.Cannonballs.Count; i++) { // TODO: Update required for old location var shell = _data.Cannonballs[i]; var velocity = shell.GetMovementVector((float)elapsedMilliseconds / 1000F); // Find out if this overlaps any tank except its owner foreach (var ship in _data.Ships) { if (ship == shell.Ship) { continue; } var shipPolygon_hull = new Polygon(); shipPolygon_hull.Points.Add(new Vector(-20, -20)); shipPolygon_hull.Points.Add(new Vector(20, -20)); shipPolygon_hull.Points.Add(new Vector(20, 20)); shipPolygon_hull.Points.Add(new Vector(-20, 20)); shipPolygon_hull.Rotate(ship.Angle); shipPolygon_hull.Offset(ship.X, ship.Y); shipPolygon_hull.BuildEdges(); var shipPolygon_bow = new Polygon(); shipPolygon_bow.Points.Add(new Vector(20, 20)); shipPolygon_bow.Points.Add(new Vector(0, 60)); shipPolygon_bow.Points.Add(new Vector(0, 60)); shipPolygon_bow.Points.Add(new Vector(-20, 20)); shipPolygon_bow.Rotate(ship.Angle); shipPolygon_bow.Offset(ship.X, ship.Y); shipPolygon_bow.BuildEdges(); var shipPolygon_stern = new Polygon(); shipPolygon_stern.Points.Add(new Vector(-20, -20)); shipPolygon_stern.Points.Add(new Vector(0, -50)); shipPolygon_stern.Points.Add(new Vector(0, -50)); shipPolygon_stern.Points.Add(new Vector(20, -20)); shipPolygon_stern.Rotate(ship.Angle); shipPolygon_stern.Offset(ship.X, ship.Y); shipPolygon_stern.BuildEdges(); // TODO - Add shipPolygon_bow, shipPolygon_stern, to a Polygon collision detection PolygonCollisionResult r = Collisions.PolygonCollision(shell.cannonballPolygon, shipPolygon_hull, velocity); PolygonCollisionResult r_bow = Collisions.PolygonCollision(shell.cannonballPolygon, shipPolygon_bow, velocity); PolygonCollisionResult r_stern = Collisions.PolygonCollision(shell.cannonballPolygon, shipPolygon_stern, velocity); if (r.WillIntersect) { //playerTranslation = velocity + r.MinimumTranslationVector; // No need to do a translation, this is a hit! ship.cannonballX = shell.X - 15; ship.cannonballY = shell.Y; ship.Health -= _data.Settings.HitDamage; if (ship.Health <= 0) { ship.Dead = true; } shell.Life = 0; _bang = true; ship.Hurt = true; break; } if (r_bow.WillIntersect) { ship.cannonballX = shell.X - 15; ship.cannonballY = shell.Y; ship.Health -= _data.Settings.HitDamage / 10; if (ship.Health <= 0) { ship.Dead = true; } shell.Life = 0; _bang = true; ship.Hurt = true; break; } if (r_stern.WillIntersect) { ship.cannonballX = shell.X - 15; ship.cannonballY = shell.Y; ship.Health -= _data.Settings.HitDamage / 10; if (ship.Health <= 0) { ship.Dead = true; } shell.Life = 0; _bang = true; ship.Hurt = true; break; } } shell.MoveCannonball(velocity); shell.Life -= (float)elapsedMilliseconds / 1000F; if (shell.Life <= 0) { _data.Cannonballs.RemoveAt(i); i--; } // TODO: Update required for new location } UpdateRequired(); }