protected Vector3D GetDirection_StraightToTarget_VelocityAware2_DebugVisuals(Point3D targetPointWorld, double maxAcceleration) { if (_shouldShowDebugVisuals && _pointVisualizer_VelAware2 == null) { #region Visualizer // This method has it's own visualizer _pointVisualizer_VelAware2 = new PointVisualizer(_viewport, _sharedVisuals, 8); _pointVisualizer_VelAware2.SetCustomItemProperties(0, true, Colors.HotPink, .03d); // chase point _pointVisualizer_VelAware2.SetCustomItemProperties(1, false, Colors.Black, 1d); // direction to go _pointVisualizer_VelAware2.SetCustomItemProperties(2, false, Colors.Red, 1d); // the return vector away _pointVisualizer_VelAware2.SetCustomItemProperties(3, false, Colors.Green, .05d); // velocity along direction to go (the other visualizer's velocity is scaled the same) _pointVisualizer_VelAware2.SetCustomItemProperties(4, false, Colors.DarkGoldenrod, .05d); // this is my max acceleration _pointVisualizer_VelAware2.SetCustomItemProperties(5, false, Colors.Cyan, 1d); // the return vector toward _pointVisualizer_VelAware2.SetCustomItemProperties(6, false, Colors.DarkOrchid, 1d); // distance to stop _pointVisualizer_VelAware2.SetCustomItemProperties(7, false, Colors.DarkCyan, 1d); // attempted turn direction #endregion } // clear off intermitent visuals (the ones that don't update every frame will appear to hang if I don't clean them up) if (_shouldShowDebugVisuals) { _pointVisualizer_VelAware2.Update(2, new Point3D(), new Vector3D()); _pointVisualizer_VelAware2.Update(4, new Point3D(), new Vector3D()); _pointVisualizer_VelAware2.Update(5, new Point3D(), new Vector3D()); _pointVisualizer_VelAware2.Update(6, new Point3D(), new Vector3D()); _pointVisualizer_VelAware2.Update(7, new Point3D(), new Vector3D()); } Point3D positionWorld = _physicsBody.PositionToWorld(_physicsBody.CenterOfMass); if (_shouldShowDebugVisuals) { _pointVisualizer_VelAware2.Update(0, targetPointWorld); if (Ship.DEBUGSHOWSACCELERATION) { _pointVisualizer_VelAware2.Update(4, positionWorld, _physicsBody.DirectionToWorld(new Vector3D(maxAcceleration, 0, 0))); } } // Convert everything to local coords Point3D position = _physicsBody.CenterOfMass; Point3D targetPointLocal = _physicsBody.PositionFromWorld(targetPointWorld); Vector3D directionToGo = targetPointLocal.ToVector() - position.ToVector(); double distanceToGo = directionToGo.Length; if (_shouldShowDebugVisuals) { _pointVisualizer_VelAware2.Update(1, positionWorld, _physicsBody.DirectionToWorld(directionToGo)); } if (Math3D.IsNearZero(directionToGo)) { // Just sit here return new Vector3D(0, 0, 0); } Vector3D currentVelocity = this.VelocityWorld; if (Math1D.IsNearZero(currentVelocity.LengthSquared)) { #region Currently Stopped if (Math1D.IsNearZero(directionToGo.LengthSquared)) { // Already sitting on the target. STAY!!! return new Vector3D(0, 0, 0); } else { // I'm currently stopped. Gun it straight toward the target return directionToGo.ToUnit(); } #endregion } #region Adjust for current velocity // I think this description is too complex // I need to a few things: // Figure out how fast I can be approaching the point, and still be able to stop on it // if too fast, negate the velocity that is along the direction of the target // // If there is left over thrust, remove as much velocity as possible that is not in the direction to the target // // If there is left over thrust, use the remainder to speed up (unless I'm already at the max velocity, then just coast) // Turn this into local coords currentVelocity = _physicsBody.DirectionFromWorld(currentVelocity); Vector3D currentVelocityAlongDirectionLine = currentVelocity.GetProjectedVector(directionToGo); if (_shouldShowDebugVisuals) { _pointVisualizer_VelAware2.Update(3, positionWorld, _physicsBody.DirectionToWorld(currentVelocityAlongDirectionLine)); } double currentSpeed = currentVelocityAlongDirectionLine.Length; // If going away from the target, then there is no need to slow down double distanceToStop = -1d; if (Vector3D.DotProduct(currentVelocityAlongDirectionLine, directionToGo) > 0) { // Calculate max velocity // t = (v1 - v0) / a // v1 will need to be zero, v0 is the current velocity, a is negative. so I can just take initial velocity / acceleration double timeToStop = currentSpeed / maxAcceleration; // Now that I know how long it will take to stop, figure out how far I'll go in that time under constant acceleration // d = vt + 1/2 at^2 // I'll let the vt be zero and acceleration be positive to make things cleaner distanceToStop = .5 * maxAcceleration * timeToStop * timeToStop; if (_shouldShowDebugVisuals) { Vector3D vectToStop = directionToGo; vectToStop.Normalize(); vectToStop *= distanceToStop; _pointVisualizer_VelAware2.Update(6, positionWorld, _physicsBody.DirectionToWorld(vectToStop)); } } bool suppress5 = false; if (distanceToStop > distanceToGo) { #region Brakes directly away from the target //TODO: Take in the magnitude to use //directionToGo *= -3d; // I'll give this a higher than normal priority (I still want to keep the highest priority with obstacle avoidance) //directionToGo *= -.25d; // If the difference between stop distance and distance to go is very small, then don't use full thrust. It causes the bot to jitter back and forth double brakesPercent = GetEdgePercentAcceleration(distanceToStop - distanceToGo, maxAcceleration); // Reverse the thrust directionToGo.Normalize(); directionToGo *= -1d * brakesPercent; if (_shouldShowDebugVisuals) { suppress5 = true; _pointVisualizer_VelAware2.Update(2, positionWorld, _physicsBody.DirectionToWorld(directionToGo)); } #endregion } else { #region Accelrate toward target (negating tangent speed) // Figure out how fast I could safely be going toward the target // If I accelerate full force, will I exceed that? (who cares, speed up, and let the next frame handle that) Vector3D axis; double radians; Math3D.GetRotation(out axis, out radians, directionToGo, currentVelocity); // This is how much to rotate direction to align with current velocity, I want to go against the current velocity (if aligned, // the angle will be zero, so negating won't make a difference) radians *= -1; //if (Math3D.IsNearZero(radians) || Math3D.IsNearValue(radians, PI_DIV_TWO) || Math3D.IsNearValue(radians, Math.PI)) //{ // // No modification needed (I don't think this if statement is really needed) //} if (Math1D.IsNearValue(radians, Math.PI)) { // Flying directly away from the target. Turn around directionToGo = currentVelocity * -1d; } //else if (Math.Abs(radians) < PI_DIV_TWO) //else if (Math.Abs(radians) < PI_DIV_FOUR) // between 45 and 90 gets too extreme else if (Math.Abs(radians) < RADIANS_60DEG) { // Change the direction by the angle directionToGo = directionToGo.GetRotatedVector(axis, Math1D.RadiansToDegrees(radians)); } else { if (_shouldShowDebugVisuals) { Vector3D vectTryTurn = directionToGo.GetRotatedVector(axis, Math1D.RadiansToDegrees(radians)); vectTryTurn.Normalize(); _pointVisualizer_VelAware2.Update(7, positionWorld, _physicsBody.DirectionToWorld(vectTryTurn)); } //double actualRadians = PI_DIV_FOUR; double actualRadians = RADIANS_60DEG; if (radians < 0) { actualRadians *= -1d; } directionToGo = directionToGo.GetRotatedVector(axis, Math1D.RadiansToDegrees(actualRadians)); } //else if (Math.Abs(radians) >= PI_DIV_TWO) //{ // // I used to stop in this case. It is most efficient, but looks really odd (I want the swarmbot to flow more instead of stalling out, // // and then charging off). So I'll try rotating by 90 degrees // if (_shouldShowDebugVisuals) // { // Vector3D vectTryTurn = directionToGo.GetRotatedVector(axis, Math3D.RadiansToDegrees(radians)); // vectTryTurn.Normalize(); // _pointVisualizer_VelAware2.Update(7, positionWorld, _physicsBody.DirectionToWorld(vectTryTurn)); // } // directionToGo = currentVelocity * -1d; //} //else if (Math.Abs(radians) >= PI_DIV_TWO) //{ // // The velocity is more than 90 degrees from where I want to go. By applying a force exactly opposite of the current // // velocity, I will negate the velocity that orthogonal to the desired direction, as well as slow down the bot // //TODO: This gives an unnatural flight. Don't fully stop before charging toward the chase point // directionToGo = currentVelocity * -1d; //} double percentThrust = GetEdgePercentAcceleration(distanceToGo - distanceToStop, maxAcceleration); //TODO: Do partial thrust similar to the fly away logic directionToGo.Normalize(); directionToGo *= percentThrust; #endregion } #endregion if (_shouldShowDebugVisuals && !suppress5) { _pointVisualizer_VelAware2.Update(5, positionWorld, _physicsBody.DirectionToWorld(directionToGo)); } // Exit Function return directionToGo; }
/// <summary> /// The derived class should modify the thruster settings before calling base.WorldUpdating /// </summary> public virtual void WorldUpdating() { #region Visuals _core.Transform = _physicsBody.Transform; #endregion #region Thrust Line if (_shouldDrawThrustLine) { _thruster.DrawVisual(_thrustPercent, _physicsBody.Transform, _thrustTransform); } #endregion #region Debug Visuals if (_shouldShowDebugVisuals) { if (_pointVisualizer == null) { _pointVisualizer = new PointVisualizer(_viewport, _sharedVisuals, _physicsBody); _pointVisualizer.ShowPosition = false; _pointVisualizer.ShowVelocity = true; _pointVisualizer.ShowAcceleration = Ship.DEBUGSHOWSACCELERATION; _pointVisualizer.VelocityAccelerationLengthMultiplier = .05d; // this is the same as the ship's } _pointVisualizer.Update(); } #endregion }
/// <summary> /// This one won't let the bot come at the target too fast (and tries to match the target's velocity) /// </summary> protected Vector3D GetDirection_InterceptTarget_VelocityAware(Point3D targetPointWorld, Vector3D targetVelocityWorld, double maxAcceleration) { const double DOT_POSTOTHESIDE = .5d; const double DOT_VELORTH = .5d; const double TOOFARTIME = 4d; // if it takes longer than this to get to the point, then just chase it directly const bool SHOULDREVERSETHRUSTWHENAPPROPRIATE = true; // true: just reverse thrust, false: turn toward chase point (not as efficient, but looks more like flight) if (_shouldShowDebugVisuals && _pointVisualizer_VelAware3 == null) { #region Visualizer // This method has it's own visualizer _pointVisualizer_VelAware3 = new PointVisualizer(_viewport, _sharedVisuals, 5); _pointVisualizer_VelAware3.SetCustomItemProperties(0, true, Colors.HotPink, .03d); // chase point _pointVisualizer_VelAware3.SetCustomItemProperties(1, false, Colors.DarkGoldenrod, .05d); // this is my max acceleration _pointVisualizer_VelAware3.SetCustomItemProperties(2, false, Colors.DarkOrchid, 1d); // projected chase point1 _pointVisualizer_VelAware3.SetCustomItemProperties(3, false, Colors.Orchid, 1d); // projected chase point2 _pointVisualizer_VelAware3.SetCustomItemProperties(4, true, Colors.Red, .1d); // unchased point #endregion } // clear off intermitent visuals (the ones that don't update every frame will appear to hang if I don't clean them up) if (_shouldShowDebugVisuals) { _pointVisualizer_VelAware3.Update(1, new Point3D(), new Vector3D()); _pointVisualizer_VelAware3.Update(4, new Point3D()); } Point3D positionLocal = _physicsBody.CenterOfMass; Point3D positionWorld = _physicsBody.PositionToWorld(positionLocal); if (_shouldShowDebugVisuals) { _pointVisualizer_VelAware3.Update(0, targetPointWorld); if (Ship.DEBUGSHOWSACCELERATION) { _pointVisualizer_VelAware3.Update(1, positionWorld, _physicsBody.DirectionToWorld(new Vector3D(maxAcceleration, 0, 0))); } } // Get some general vectors Point3D targetPointLocal = _physicsBody.PositionFromWorld(targetPointWorld); Vector3D targetVelocityLocal = _physicsBody.DirectionFromWorld(targetVelocityWorld); Vector3D directionToGo = targetPointLocal.ToVector() - positionLocal.ToVector(); double distanceToGo = directionToGo.Length; Vector3D velocityLocal = _physicsBody.DirectionFromWorld(_physicsBody.VelocityCached); #region Get approximate intercept point // Get time to point double interceptTime1 = GetInterceptTime(targetPointWorld, positionWorld, _physicsBody.VelocityCached, maxAcceleration); // Project where the chase point will be at that time Point3D targetPointWorld1 = targetPointWorld + (targetVelocityWorld * interceptTime1); // Get the intercept time for this second point double interceptTime2 = GetInterceptTime(targetPointWorld1, positionWorld, _physicsBody.VelocityCached, maxAcceleration); // Project again Point3D targetPointWorld2 = targetPointWorld + (targetVelocityWorld * interceptTime2); if (_shouldShowDebugVisuals) { _pointVisualizer_VelAware3.Update(2, positionWorld, targetPointWorld1 - positionWorld); _pointVisualizer_VelAware3.Update(3, positionWorld, targetPointWorld2 - positionWorld); } #endregion if (interceptTime1 > TOOFARTIME) { // Simplifying if too far away return GetDirection_StraightToTarget_VelocityAware2(targetPointWorld2, maxAcceleration); } #region Determine relative positions/velocities // Dot product of my velocity with chase point location Vector3D velocityLocalUnit = velocityLocal.ToUnit(); Vector3D directionToGoUnit = directionToGo.ToUnit(); double velDotDir = Vector3D.DotProduct(velocityLocalUnit, directionToGoUnit); // Dot product of my velocity with chase velocity Vector3D targetVelocityLocalUnit = targetVelocityLocal.ToUnit(); double velDotVel = Vector3D.DotProduct(velocityLocalUnit, targetVelocityLocalUnit); //NOTE: In several conditions, it's a toss up whether the swarm bot should turn around, or reverse thrust. This should be a member // level boolean if (velDotDir > DOT_POSTOTHESIDE) { if (velDotVel > DOT_POSTOTHESIDE) { #region Point is in front & Traveling in the same direction // Make a modified version of speed aware 2, and head directly for the chase point, trying to match velocity // // Also may want to try to shoot for a bit in front of them #endregion } else if (velDotVel > -DOT_POSTOTHESIDE) { #region Point is in front & Traveling orthoganal // I've found when dogfighting, that I don't want to go to where they are now, I want to follow the path they've taken so I can // run up their rear. // // So project a point behind them and go for that // // I probably want to do a hybrid between going directly behind them, and going for the chase point #endregion } else { #region Point is in front & Traveling in opposite directions // Go straight for them, then reverse thrust in time so they run into me (sort of playing chicken) #endregion } } else if (velDotDir > -DOT_POSTOTHESIDE) { if (velDotVel > DOT_POSTOTHESIDE) { #region Point is to the side & Traveling in the same direction // Don't turn toward them, just slide over to them (match the velocity along their direction of travel, and use the remaining // thrust to shoot to the side #endregion } else if (velDotVel > -DOT_POSTOTHESIDE) { #region Point is to the side & Traveling orthoganal // Turn toward them (call speed aware 2 going straight for the chase point) #endregion } else { #region Point is to the side & Traveling in opposite directions // Either: // turn toward it // or reverse thrust and eventually get to the point where you can slide up to it #endregion } } else { if (velDotVel > DOT_POSTOTHESIDE) { #region Point is behind & Traveling in the same direction // Get in front of them, then either just slow down, or reverse thrust toward them until they're close enough to reverse thrust again #endregion } else if (velDotVel > -DOT_POSTOTHESIDE) { #region Point is behind & Traveling orthoganal // Turn toward them (similar case with "Point is to the side & Traveling orthoganal"?) #endregion } else { #region Point is behind & Traveling in opposite directions // Reverse thrust #endregion } } #endregion return GetDirection_StraightToTarget_VelocityAware2(targetPointWorld2, maxAcceleration); _pointVisualizer_VelAware3.Update(4, targetPointWorld); return new Vector3D(); }
/// <summary> /// This goes straight for the chase point, and tries to be going at the target's velocity when it's at the target point /// </summary> /// <remarks> /// The difference between this method and intercept is that this always goes straight for the point it's told to, fully /// turning if nessassary. Intercept tries to calculate the best way to intercept, possibly chasing after a derived point. /// </remarks> protected Vector3D GetDirection_StraightToTarget_VelocityAware2(Point3D targetPointWorld, Vector3D targetVelocityWorld, double maxAcceleration) { if (_shouldShowDebugVisuals && _pointVisualizer_VelAware2 == null) { #region Visualizer // This method has it's own visualizer _pointVisualizer_VelAware2 = new PointVisualizer(_viewport, _sharedVisuals, 4); _pointVisualizer_VelAware2.SetCustomItemProperties(0, true, Colors.HotPink, .03d); // chase point _pointVisualizer_VelAware2.SetCustomItemProperties(1, false, Colors.Black, 1d); // direction to go _pointVisualizer_VelAware2.SetCustomItemProperties(2, false, Colors.Green, .05d); // velocity along direction to go (the other visualizer's velocity is scaled the same) _pointVisualizer_VelAware2.SetCustomItemProperties(3, false, Colors.DarkOrchid, 1d); // distance to stop #endregion } if (_shouldShowDebugVisuals) { // clear intermittant lines _pointVisualizer_VelAware2.Update(3, new Point3D(), new Vector3D()); _pointVisualizer_VelAware2.Update(0, targetPointWorld); } // Convert everything to local coords Point3D position = _physicsBody.CenterOfMass; Point3D targetPointLocal = _physicsBody.PositionFromWorld(targetPointWorld); Vector3D targetVelocityLocal = _physicsBody.DirectionFromWorld(targetVelocityWorld); Vector3D directionToGo = targetPointLocal.ToVector() - position.ToVector(); double distanceToGo = directionToGo.Length; Vector3D currentVelocity = _physicsBody.DirectionFromWorld(this.VelocityWorld); if (_shouldShowDebugVisuals) { _pointVisualizer_VelAware2.Update(1, PositionWorld, _physicsBody.DirectionToWorld(directionToGo)); } if (Math3D.IsNearZero(directionToGo) && Math3D.IsNearZero(currentVelocity - targetVelocityLocal)) { // Already on the point, moving along the same vector return new Vector3D(0, 0, 0); } // I think this description is too complex // I need to a few things: // Figure out how fast I can be approaching the point, and still be able to stop on it // if too fast, negate the velocity that is along the direction of the target // // If there is left over thrust, remove as much velocity as possible that is not in the direction to the target // // If there is left over thrust, use the remainder to speed up (unless I'm already at the max velocity, then just coast) //directionToGo += targetVelocityLocal; // try adding the two, and see if that's good - this doesn't work, they units are far too different Vector3D currentVelocityAlongDirectionLine = currentVelocity.GetProjectedVector(directionToGo); double currentSpeedAlongDirectionLine = currentVelocityAlongDirectionLine.Length; //Vector3D currentVelocityAlongTargetVelocity = currentVelocity.GetProjectedVector(targetVelocityLocal); // I don't see how this helps //double currentSpeedAlongTargetVelocity = currentVelocityAlongTargetVelocity.Length; Vector3D targetVelocityAlongDirectionLine = targetVelocityLocal.GetProjectedVector(directionToGo); double targetSpeedAlongDirectionLine = targetVelocityAlongDirectionLine.Length; if (_shouldShowDebugVisuals) { _pointVisualizer_VelAware2.Update(2, PositionWorld, _physicsBody.DirectionToWorld(currentVelocityAlongDirectionLine)); } // If going away from the target, then there is no need to slow down double distanceToStop = -1d; if (Vector3D.DotProduct(currentVelocityAlongDirectionLine, directionToGo) > 0) { // Calculate max velocity // t = (v1 - v0) / a // v1 will need to be zero, v0 is the current velocity, a is negative. so I can just take initial velocity / acceleration double timeToStop = currentSpeedAlongDirectionLine / maxAcceleration; // Now including the portion of the target's velocity along the direction //double timeToStop = (currentSpeedAlongDirectionLine + targetSpeedAlongDirectionLine) / maxAcceleration; // this fails pretty badly too (try taking the greater of the two speeds?) // Now that I know how long it will take to stop, figure out how far I'll go in that time under constant acceleration // d = vt + 1/2 at^2 // I'll let the vt be zero and acceleration be positive to make things cleaner distanceToStop = .5 * maxAcceleration * timeToStop * timeToStop; if (_shouldShowDebugVisuals) { Vector3D vectToStop = directionToGo; vectToStop.Normalize(); vectToStop *= distanceToStop; _pointVisualizer_VelAware2.Update(3, PositionWorld, _physicsBody.DirectionToWorld(vectToStop)); } } // distance and time to stop are to get stopped. Now I have to leave some leeway for target velocity??? if (distanceToStop > distanceToGo) { #region Brakes directly away from the target //TODO: Take in the magnitude to use //directionToGo *= -3d; // I'll give this a higher than normal priority (I still want to keep the highest priority with obstacle avoidance) //directionToGo *= -.25d; // If the difference between stop distance and distance to go is very small, then don't use full thrust. It causes the bot to jitter back and forth double brakesPercent = GetEdgePercentAcceleration(distanceToStop - distanceToGo, maxAcceleration); // Reverse the thrust directionToGo.Normalize(); directionToGo *= -1d * brakesPercent; #endregion } else { #region Accelrate toward target (negating tangent speed) // Figure out how fast I could safely be going toward the target // If I accelerate full force, will I exceed that? (who cares, speed up, and let the next frame handle that) Vector3D axis; double radians; Math3D.GetRotation(out axis, out radians, directionToGo, currentVelocity); // This is how much to rotate direction to align with current velocity, I want to go against the current velocity (if aligned, // the angle will be zero, so negating won't make a difference) radians *= -1; //if (Math3D.IsNearZero(radians) || Math3D.IsNearValue(radians, PI_DIV_TWO) || Math3D.IsNearValue(radians, Math.PI)) //{ // // No modification needed (I don't think this if statement is really needed) //} if (Math1D.IsNearValue(radians, Math.PI)) { // Flying directly away from the target. Turn around directionToGo = currentVelocity * -1d; } else if (Math.Abs(radians) < RADIANS_60DEG) // PI_DIV_TWO is waiting too long, PI_DIV_FOUR is capping off too early { // Change the direction by the angle directionToGo = directionToGo.GetRotatedVector(axis, Math1D.RadiansToDegrees(radians)); } //else if (Math.Abs(radians) >= PI_DIV_TWO) //{ // // The velocity is more than 90 degrees from where I want to go. By applying a force exactly opposite of the current // // velocity, I will negate the velocity that's orthogonal to the desired direction, as well as slow down the bot // // // I used to stop in this case. It is most efficient, but looks really odd (I want the swarmbot to flow more instead of stalling out, // // and then charging off). So I don't rotate more than 60 degrees now // directionToGo = currentVelocity * -1d; //} else { double actualRadians = RADIANS_60DEG; if (radians < 0) { actualRadians *= -1d; } directionToGo = directionToGo.GetRotatedVector(axis, Math1D.RadiansToDegrees(actualRadians)); } // Don't jitter back and forth at full throttle when at the boundry double percentThrust = GetEdgePercentAcceleration(distanceToGo - distanceToStop, maxAcceleration); directionToGo.Normalize(); directionToGo *= percentThrust; #endregion } // Exit Function return directionToGo; }
private void ChangeSwarmBots(SwarmFormation formation) { ChangeSwarmBotsSprtRemoveAll(); if (formation == SwarmFormation.None) { _swarmbotFormation = SwarmFormation.None; return; } double startAngle, stepAngle; // 0 is straight in front of the ship int numBots; double distanceMult; switch (formation) { case SwarmFormation.AllFront: #region AllFront startAngle = 0d; stepAngle = 360d; //numBots = 20; numBots = _numSwarmbots; distanceMult = 8d; #endregion break; case SwarmFormation.AllRear: #region AllRear startAngle = 180d; stepAngle = 360d; //numBots = 20; numBots = _numSwarmbots; distanceMult = 8d; #endregion break; case SwarmFormation.Triangle: #region Triangle startAngle = 0d; stepAngle = 120d; //numBots = 10; numBots = _numSwarmbots / 3; if (numBots % 3 != 0 || numBots == 0) { numBots++; } distanceMult = 9d; #endregion break; case SwarmFormation.ReverseTriangle: #region ReverseTriangle startAngle = 180d; stepAngle = 120d; //numBots = 10; numBots = _numSwarmbots / 3; if (numBots % 3 != 0 || numBots == 0) { numBots++; } distanceMult = 9d; #endregion break; case SwarmFormation.Pentagon: #region Pentagon startAngle = 0d; stepAngle = 72d; //numBots = 7; numBots = _numSwarmbots / 5; if (numBots % 5 != 0 || numBots == 0) { numBots++; } distanceMult = 9d; #endregion break; case SwarmFormation.ReversePentagon: #region ReversePentagon startAngle = 180d; stepAngle = 72d; //numBots = 7; numBots = _numSwarmbots / 5; if (numBots % 5 != 0 || numBots == 0) { numBots++; } distanceMult = 9d; #endregion break; case SwarmFormation.SurroundShip: #region SurroundShip startAngle = 0d; stepAngle = 360d; //numBots = 30; numBots = _numSwarmbots; distanceMult = 0d; #endregion break; default: throw new ApplicationException("Unknown SwarmFormation: " + formation.ToString()); } // Figure out how far away from the ship the bots should be double chaseOffsetDistance = (_radiusX + _radiusY) / 2d; chaseOffsetDistance *= distanceMult; // Build the swarms double angle = startAngle; while (angle < startAngle + 360d) { Vector3D chasePoint = new Vector3D(0, chaseOffsetDistance, 0); chasePoint = chasePoint.GetRotatedVector(new Vector3D(0, 0, 1), angle); _swarmBots.Add(ChangeSwarmBotsSprtSwarm(numBots, chasePoint)); _swarmbotChasePoints.Add(chasePoint.ToPoint()); PointVisualizer chasePointSprite = new PointVisualizer(_map.Viewport, _sharedVisuals); chasePointSprite.PositionRadius = .1d; chasePointSprite.VelocityAccelerationLengthMultiplier = .05d; chasePointSprite.ShowPosition = _showDebugVisuals; chasePointSprite.ShowVelocity = _showDebugVisuals; chasePointSprite.ShowAcceleration = _showDebugVisuals && DEBUGSHOWSACCELERATION; _swarmbotChasePointSprites.Add(chasePointSprite); angle += stepAngle; } _swarmbotFormation = formation; }