private void ChangeSwarmBotsSprtSizeProps(out double radius, out double mass, out double thrustForce, out int numClosestBotsToLookAt, out double visionLimit, double sizeMultiplier) { const double RADIUS = .125d; const double DENSITY = 61.115d; // I want the mass to be .5 when radius is .125: d = m / (4/3 * pi * r^3) const double ACCEL_HALF = 190d; // note that these don't scale evenly with mass. I don't want the acceleration affected that much (I want the acceleration to be 160 when size multiplier is 1) const double ACCEL_FOUR = 130d; const double VISIONLIMIT_HALF = 12d; // middle is 20 const double VISIONLIMIT_FOUR = 28d; const double CLOSECOUNT_HALF = 2d; const double CLOSECOUNT_TWICE = 4d; radius = RADIUS * sizeMultiplier; // v = 4/3 * pi * r^3 // m = d * v // m = d * 4/3 * pi * r^3 mass = DENSITY * 4 / 3 * Math.PI * Math.Pow(radius, 3); // f = ma // a = f / m double accel = UtilityCore.GetScaledValue(ACCEL_HALF, ACCEL_FOUR, .5d, 4d, sizeMultiplier); //NOTE: not capping it, the min/max are just for scaling thrustForce = mass * accel; visionLimit = UtilityCore.GetScaledValue(VISIONLIMIT_HALF, VISIONLIMIT_FOUR, .5d, 4d, sizeMultiplier); numClosestBotsToLookAt = Convert.ToInt32(Math.Round(UtilityCore.GetScaledValue(CLOSECOUNT_HALF, CLOSECOUNT_TWICE, .5d, 2d, sizeMultiplier))); if (numClosestBotsToLookAt < 2) { numClosestBotsToLookAt = 2; } }
private void trkWestMass_Scroll(object sender, EventArgs e) { _west.Mass = UtilityCore.GetScaledValue(MINMASS, MAXMASS, trkWestMass.Minimum, trkWestMass.Maximum, trkWestMass.Maximum - trkWestMass.Value); if (!_isProgramaticPointMass1D && chkCoupledXMass.Checked) { _isProgramaticPointMass1D = true; // Align 1D trkEastMass.Value = trkWestMass.Maximum - trkWestMass.Value; trkEastMass_Scroll(this, new EventArgs()); _isProgramaticPointMass1D = false; if (!_isProgramaticPointMass2D && chkCoupledBothMass.Checked) { _isProgramaticPointMass2D = true; // Align 2D trkSouthMass.Value = trkEastMass.Value; trkSouthMass_Scroll(this, new EventArgs()); _isProgramaticPointMass2D = false; } } }
private void trkSouthPos_Scroll(object sender, EventArgs e) { _south.Y = -1d * UtilityCore.GetScaledValue(MINRADIUS, MAXRADIUS, trkSouthPos.Minimum, trkSouthPos.Maximum, trkSouthPos.Value); if (!_isProgramaticPointMass1D && chkCoupledYPos.Checked) { _isProgramaticPointMass1D = true; // Align 1D trkNorthPos.Value = trkSouthPos.Maximum - trkSouthPos.Value; trkNorthPos_Scroll(this, new EventArgs()); _isProgramaticPointMass1D = false; if (!_isProgramaticPointMass2D && chkCoupledBothPos.Checked) { _isProgramaticPointMass2D = true; // Align 2D trkEastPos.Value = trkSouthPos.Value; trkEastPos_Scroll(this, new EventArgs()); _isProgramaticPointMass2D = false; } } }
private void trkAngularMomentum_Scroll(object sender, EventArgs e) { double magnitude = UtilityCore.GetScaledValue(MINMOMENTUM, MAXMOMENTUM, trkAngularMomentum.Minimum, trkAngularMomentum.Maximum, trkAngularMomentum.Value); _rigidBody.AngularMomentum.StoreNewValues(new MyVector(0, 0, magnitude)); txtAngularMomentum.Text = _rigidBody.AngularMomentum.Z.ToString(); }
private void trkElapsedTime_Scroll(object sender, EventArgs e) { const double MINTIME = .01d; const double MAXTIME = 10d; _elapsedTime = UtilityCore.GetScaledValue(MINTIME, MAXTIME, trkElapsedTime.Minimum, trkElapsedTime.Maximum, trkElapsedTime.Value); txtElapsedTime.Text = Math.Round(_elapsedTime, 2).ToString(); }
private void trkThreshold_Scroll(object sender, EventArgs e) { const double MINPERCENT = .001d; const double MAXPERCENT = .999d; _map.CollisionHandler.PenetrationThresholdPercent = UtilityCore.GetScaledValue(MINPERCENT, MAXPERCENT, trkThreshold.Minimum, trkThreshold.Maximum, trkThreshold.Value); txtThreshold.Text = Math.Round(_map.CollisionHandler.PenetrationThresholdPercent * 100d, 1).ToString() + "%"; }
private void trkPullApartSpring_Scroll(object sender, EventArgs e) { const double MINVELOCITY = .01d; const double MAXVELOCITY = 30d; _map.CollisionHandler.PullApartSpringVelocity = UtilityCore.GetScaledValue(MINVELOCITY, MAXVELOCITY, trkPullApartSpring.Minimum, trkPullApartSpring.Maximum, trkPullApartSpring.Value); txtPullApartSpring.Text = _map.CollisionHandler.PullApartSpringVelocity.ToString(); }
private void trkVectorFieldSize_Scroll(object sender, EventArgs e) { const double MINSIZE = 10; const double MAXSIZE = 10000; double size = UtilityCore.GetScaledValue(MINSIZE, MAXSIZE, trkVectorFieldSize.Minimum, trkVectorFieldSize.Maximum, trkVectorFieldSize.Value); _vectorField.SizeX = size; _vectorField.SizeY = size; }
private void trkAngularVelocity_Scroll(object sender, EventArgs e) { // Calculate the trackbar value double scaledValue = UtilityCore.GetScaledValue(_exposedProps.MinRandAngularVelocity, _exposedProps.MaxRandAngularVelocity, trkAngularVelocity.Minimum, trkAngularVelocity.Maximum, trkAngularVelocity.Maximum - trkAngularVelocity.Value); toolTip1.SetToolTip(trkAngularVelocity, Math.Round(scaledValue, 2).ToString()); // I present angular velocity in rotations/frame. But the torqueball wants it in radians/frame _exposedProps.AngularVelocityIfFixed = scaledValue * Math.PI * 2; OnValueChanged(); }
private void trkGravityForce_Scroll(object sender, EventArgs e) { if (_gravController == null) { return; } const double MINGRAVITY = 0d; const double MAXGRAVITY = 10d; _gravController.GravityMultiplier = UtilityCore.GetScaledValue(MINGRAVITY, MAXGRAVITY, trkGravityForce.Minimum, trkGravityForce.Maximum, trkGravityForce.Value); }
private static double SetBotConstraints_Mult(double slope, double value, double center = 1d) { // y=mx+b // y=mx + (1-m) double minX = center / 2d; double maxX = center * 2d; double minY = (slope * minX) + (center - slope); double maxY = (slope * maxX) + (center - slope); return(UtilityCore.GetScaledValue(minY, maxY, minX, maxX, value)); }
private static BitmapSource DrawStrokes(IEnumerable <EncogOCR_StrokeDefinition> strokes, int width, int height, double origWidth, double origHeight) { //NOTE: InkCanvas draws lines smoother than this method. This is a crude way to approximate the thickness/darkeness of the lines double scale = Math1D.Avg(width, height) / Math1D.Avg(origWidth, origHeight); double reduce = 1; if (scale < .2) { reduce = UtilityCore.GetScaledValue(.8, 1, .05, .2, scale); } RenderTargetBitmap retVal = new RenderTargetBitmap(width, height, UtilityWPF.DPI, UtilityWPF.DPI, PixelFormats.Pbgra32); DrawingVisual dv = new DrawingVisual(); using (DrawingContext ctx = dv.RenderOpen()) { foreach (EncogOCR_StrokeDefinition stroke in strokes) { SolidColorBrush brush = new SolidColorBrush(UtilityWPF.ColorFromHex(stroke.Color)); if (stroke.Points.Length == 1) { // Single Point double radius = stroke.Thickness / 2d; radius *= reduce; ctx.DrawEllipse(brush, null, stroke.Points[0], radius, radius); } else { // Multiple Points Pen pen = new Pen(brush, stroke.Thickness * reduce) { StartLineCap = PenLineCap.Round, EndLineCap = PenLineCap.Round, }; for (int cntr = 0; cntr < stroke.Points.Length - 1; cntr++) { ctx.DrawLine(pen, stroke.Points[cntr], stroke.Points[cntr + 1]); } } } } dv.Transform = new ScaleTransform(width / origWidth, height / origHeight); retVal.Render(dv); return(retVal); }
private void trkSize_Scroll(object sender, EventArgs e) { if (_exposedProps == null) { return; } // Store the value _exposedProps.SizeIfFixed = UtilityCore.GetScaledValue(_exposedProps.MinRandSize, _exposedProps.MaxRandSize, trkSize.Minimum, trkSize.Maximum, trkSize.Value); toolTip1.SetToolTip(trkSize, _exposedProps.SizeIfFixed.ToString()); // Raise Event OnValueChanged(); }
private Color GetGreenRedColor(double minTarget, double maxTarget, double actualValue, double sizePercent) { if (sizePercent < .9d) { return(Color.OliveDrab); } else { double derivedMinTarget = UtilityCore.GetScaledValue(minTarget, maxTarget, 0d, 1d, .9d); double colorPercent = UtilityCore.GetScaledValue_Capped(0d, 1d, derivedMinTarget, maxTarget * 3d, actualValue); return(UtilityGDI.AlphaBlend(Color.Firebrick, Color.OliveDrab, colorPercent)); } }
private void trkStrengthFar_Scroll(object sender, EventArgs e) { _strengthFar = UtilityCore.GetScaledValue(0, _strengthMax, trkStrengthFar.Minimum, trkStrengthFar.Maximum, trkStrengthFar.Value); toolTip1.SetToolTip(trkStrengthFar, _strengthFar.ToString()); // Apply to tractor beams foreach (TractorBeamCone tractor in _shipController.TractorBeams) { tractor.ForceAtMax = _strengthFar; } ShipController_ChangeTractorBeamPower(this, new EventArgs()); }
private void trkHeight_Scroll(object sender, EventArgs e) { double size = UtilityCore.GetScaledValue(0, BOUNDRYMAX, trkHeight.Minimum, trkHeight.Maximum, trkHeight.Value); _boundryLower.Y = size * -1d; _boundryUpper.Y = size; if (chkForceSquare.Checked && trkWidth.Value != trkHeight.Value) { trkWidth.Value = trkHeight.Value; trkWidth_Scroll(this, new EventArgs()); } ShowDimensions(); }
private void trkPullApartPercent_Scroll(object sender, EventArgs e) { const double MINPERCENT = 1d; const double MAXPERCENT = 1.25d; try { _map.CollisionHandler.PullApartInstantPercent = UtilityCore.GetScaledValue(MINPERCENT, MAXPERCENT, trkPullApartPercent.Minimum, trkPullApartPercent.Maximum, trkPullApartPercent.Value); txtPullApartPercent.Text = Math.Round(_map.CollisionHandler.PullApartInstantPercent * 100d, 1).ToString() + "%"; } catch (Exception ex) { // I added caps in the property set MessageBox.Show("Had trouble setting property\n\n" + ex.Message, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Warning); } }
private void StoreMouseMove(int x, int y) { MyVector safe = new MyVector(); safe.X = UtilityCore.GetScaledValue(_multiplier * -1d, _multiplier, 0, this.Width, x); safe.Y = UtilityCore.GetScaledValue(_multiplier * -1d, _multiplier, 0, this.Height, y); double safeMultiplier = _multiplier * SAFEPERCENT; // I don't want to butt up against the multiplier, or store value will increase it on me if (safe.GetMagnitudeSquared() > safeMultiplier * safeMultiplier) { safe.BecomeUnitVector(); safe.Multiply(safeMultiplier); } StoreNewValue(safe.X, safe.Y, 0d); }
private static GradientEntry[] TransformValues(GradientEntry[] orig, double fromDist, double toDist, double fromPerc, double toPerc, bool isUpGraph) { double percentMinRange = 0; double percentMaxRange = 1; if (!isUpGraph) { // The slope is going down, so reverse the min/max percentMinRange = 1; percentMaxRange = 0; } return(orig.Select(o => new GradientEntry ( UtilityCore.GetScaledValue(fromDist, toDist, 0, 1, o.Distance), UtilityCore.GetScaledValue(fromPerc, toPerc, percentMinRange, percentMaxRange, o.Percent) )). ToArray()); }
private void CreateFields() { _gravityField = new GravityFieldSpace(_map); // These two can't deviate too far from each other. Too much gravity with no swirl will just make a big blob. Too much swirl with no gravity // isn't as bad, but more gravity makes it more interesting double gravitationalConstant = UtilityCore.GetScaledValue(.0001d, .0005d, 0d, 1d, StaticRandom.NextDouble()); double swirlStrength = UtilityCore.GetScaledValue(50d, 600d, 0d, 1d, StaticRandom.NextDouble()); double percent = UtilityCore.GetScaledValue(.1d, 1.5d, 0d, 1d, StaticRandom.NextDouble()); gravitationalConstant *= percent; swirlStrength *= percent; _gravityField.GravitationalConstant = gravitationalConstant; _gravityField.Swirl = new GravityFieldSpace.SwirlField(swirlStrength, new Vector3D(0, 0, 1), 10d); _gravityField.Boundry = new GravityFieldSpace.BoundryField(.85d, 5000d, 2d, _boundryMin, _boundryMax); }
/// <summary> /// Each hit line should create a cone of probability to place control points onto /// Once a point on the surface of a cone is chosen, choose a couple more on that circle /// </summary> private static Point3D[] GetVoronoiCtrlPoints_AroundLine_Cone(Point3D lineStart, Point3D lineStop, int count, double entryRadius, double exitRadius, double maxAxisLength) { // Figure out where on the axis the control point ring should go (the bell has a spike around 30% in) double axisPercent = StaticRandomWPF.NextBell(_coneAxisBell.Value); Vector3D axis = lineStop - lineStart; double axisLength = axis.Length; Point3D ringCenter = lineStart + (axis * axisPercent); // Figure out the radius of the cone at this point double exitRadiusAdjusted = (axisLength / maxAxisLength) * exitRadius; double ringRadius = UtilityCore.GetScaledValue(entryRadius, exitRadiusAdjusted, 0, 1, axisPercent); // Get some points var points = Enumerable.Range(0, count). Select(o => Math3D.GetRandomVector_Circular_Shell(ringRadius).ToPoint()); //TODO: Figure out the minimum to shift by //double shiftRadius = Math.Max(.01, ringRadius / 20); double shiftRadius = ringRadius / 20; points = points.Select(o => o + Math3D.GetRandomVector_Spherical(shiftRadius)); // the voronoi can't handle coplanar input // Rotate/Translate Quaternion roation = Math3D.GetRotation(new Vector3D(0, 0, 1), axis); Transform3DGroup transform = new Transform3DGroup(); transform.Children.Add(new RotateTransform3D(new QuaternionRotation3D(roation))); transform.Children.Add(new TranslateTransform3D(ringCenter.X, ringCenter.Y, ringCenter.Z)); points = points.Select(o => transform.Transform(o)); return(points.ToArray()); }
public void Update_AnyThread(double elapsedTime) { double distance = (this.Bot.PositionWorld - _center).Length; double score; if (distance < _maxSafeDistance) { score = 1d; } else if (distance > _maxUnsafeDistance) { score = 0d; } else { score = 1 - UtilityCore.GetScaledValue(0, 1, _maxSafeDistance, _maxUnsafeDistance, distance); } _score = (double)_score + (score * elapsedTime); }
private static double[] ConvertToVector_Text_Normalize(int[] number, double numUniqueChars) { const double WHITESPACEGAP = .15; double[] retVal = new double[number.Length]; for (int cntr = 0; cntr < number.Length; cntr++) { if (number[cntr] == 0) { // Leave it zero continue; } double percent = number[cntr] / numUniqueChars; //NOTE: 1 is actually the smallest value, so the range is from 1/numunique to 1 (so all the values in retVal will be 0 or greater than WHITESPACEGAP) retVal[cntr] = UtilityCore.GetScaledValue(WHITESPACEGAP, 1d, 0d, 1d, percent); } return(retVal); }
private static Tuple <int, double>[] GetFieldCircle(Point point, double radiusX, double radiusY, double valueCenter, double valueEdge, FluidField2D field) { // Get the box that contains the return circle var center = GetFieldPoint_XY(new Point(point.X, point.Y), field); var min = GetFieldPoint_XY(new Point(point.X - radiusX, point.Y - radiusY), field); var max = GetFieldPoint_XY(new Point(point.X + radiusX, point.Y + radiusY), field); // Get points that are inside the circle List <Tuple <int, double> > retVal = new List <Tuple <int, double> >(); Vector radius = new Vector(radiusX * field.XSize, radiusY * field.YSize); double maxDistance = ((radiusX * field.XSize) + (radiusY * field.YSize)) * .5d; // just take the average. TODO: see if inside the ellipse double maxDistanceSquared = maxDistance * maxDistance; for (int x = min.Item1; x <= max.Item1; x++) { for (int y = min.Item2; y <= max.Item2; y++) { double dx = x - center.Item1; double dy = y - center.Item2; double distanceSquared = (dx * dx) + (dy * dy); if (distanceSquared <= maxDistanceSquared) { double distance = Math.Sqrt(distanceSquared); retVal.Add(Tuple.Create( field.GetK(x, y), // coordinates that the field wants UtilityCore.GetScaledValue(valueCenter, valueEdge, 0, maxDistance, distance) // LERP )); } } } // Exit Function return(retVal.ToArray()); }
public static double GetGradientPercent(double distance, GradientEntry[] gradient) { // See if they are outside the gradient (if so, use that cap's %) if (distance <= gradient[0].Distance) { return(gradient[0].Percent); } else if (distance >= gradient[gradient.Length - 1].Distance) { return(gradient[gradient.Length - 1].Percent); } // It is inside the gradient. Find the two stops that are on either side for (int cntr = 0; cntr < gradient.Length - 1; cntr++) { if (distance > gradient[cntr].Distance && distance <= gradient[cntr + 1].Distance) { // LERP between the from % and to % return(UtilityCore.GetScaledValue(gradient[cntr].Percent, gradient[cntr + 1].Percent, gradient[cntr].Distance, gradient[cntr + 1].Distance, distance)); //NOTE: Not calling the capped overload, because max could be smaller than min (and capped would fail) } } throw new ApplicationException("Execution should never get here"); }
// these were copied from the 1.53 collision shapes tester private void GetRatiosMass(out double x, out double y, out double z, out double mass, CollisionShapeType shape) { // Ratios if (chkRandomRatios.IsChecked.Value) { x = UtilityCore.GetScaledValue(MINRATIO, MAXRATIO, 0d, 1d, _rand.NextDouble()); // reused as radius y = UtilityCore.GetScaledValue(MINRATIO, MAXRATIO, 0d, 1d, _rand.NextDouble()); // reused as height z = UtilityCore.GetScaledValue(MINRATIO, MAXRATIO, 0d, 1d, _rand.NextDouble()); } else { x = UtilityCore.GetScaledValue(MINRATIO, MAXRATIO, trkX.Minimum, trkX.Maximum, trkX.Value); y = UtilityCore.GetScaledValue(MINRATIO, MAXRATIO, trkY.Minimum, trkY.Maximum, trkY.Value); z = UtilityCore.GetScaledValue(MINRATIO, MAXRATIO, trkZ.Minimum, trkZ.Maximum, trkZ.Value); } switch (shape) { case CollisionShapeType.Box: x *= 2d; // sphere treats x as a radius. box thinks of it as width y *= 2d; z *= 2d; mass = x * y * z; break; case CollisionShapeType.Sphere: mass = (4d / 3d) * Math.PI * x * y * z; break; default: throw new ApplicationException("Unexpected CollisionShapeType: " + shape.ToString()); } // If I try to be realistic, then it's boring, so I'll scale the result. (density shrinks a bit as things get larger) mass = UtilityCore.GetScaledValue(MINMASS, MAXMASS, Math.Pow(MINRATIO, 3), Math.Pow(MAXRATIO, 3), mass); }
private void trkSize_Scroll(object sender, EventArgs e) { this.ExposedProps.SizeIfFixed = UtilityCore.GetScaledValue(this.ExposedProps.MinRandSize, this.ExposedProps.MaxRandSize, trkSize.Minimum, trkSize.Maximum, trkSize.Value); toolTip1.SetToolTip(trkSize, this.ExposedProps.SizeIfFixed.ToString()); }
/// <summary> /// This method will adjust the force to keep the relative velocity relativaly small /// </summary> /// <remarks> /// This method needs work. It would help if I exposed velocity and force lines to be drawn for debugging /// </remarks> private double GetForceForSoft(ref AngularVelocityInfo angularInfo, double maxForce, MyVector forceDirection, double distance, Ball ball, MyVector dirFacingWorld) { const double MINVELOCITY = 20d; double minVelocity = UtilityCore.GetScaledValue(0, MINVELOCITY, 0, _maxDistance, distance); MyVector dummy; MyVector tractorVelocity = GetSpinVelocityAtPoint(ref angularInfo, out dummy, dirFacingWorld, _offset, _ship.Ball.Position + _offset); tractorVelocity = tractorVelocity + _ship.Ball.Velocity; double relativeVelocity = MyVector.Dot(forceDirection, ball.Velocity - tractorVelocity); double retVal = maxForce; if (maxForce > 0) { #region Pulling In // Positive force means the relative velocity will need to be negative (pulling the object in) if (Utility3D.IsNearValue(relativeVelocity, minVelocity * -1d)) { // It's going the right speed. No force needed return(0); } else if (relativeVelocity < (minVelocity * -1d)) { // It's coming in too fast. Slow it down retVal = Math.Abs(relativeVelocity) - Math.Abs(minVelocity) * ball.Mass; // Velocity * Mass is impulse force } #endregion } else { #region Pushing Away // Negative force means the relative velocity will need to be positive (pushing the object away) if (Utility3D.IsNearValue(relativeVelocity, minVelocity)) { // It's going the right speed. No force needed return(0); } else if (relativeVelocity > minVelocity) { // It's going away too fast. Slow it down retVal = Math.Abs(relativeVelocity) - Math.Abs(minVelocity) * ball.Mass; // Velocity * Mass is impulse force retVal *= -1d; } //if (relativeVelocity > MINVELOCITY) //{ // // It's going fast enough, no need to apply any more force // return 0; //} // Figure out how much force is required to make this relative velocity equal MINVELOCITY //retVal = (relativeVelocity - MINVELOCITY) * ball.Mass; // Velocity * Mass is impulse force #endregion } // Cap the return the max force if (Math.Abs(retVal) > Math.Abs(maxForce)) { if (retVal > 0) { retVal = Math.Abs(maxForce); } else { retVal = Math.Abs(maxForce) * -1d; } } // Exit Function return(retVal); }
private List <Interaction> GetInteractions_Static(out double totalForce, MyVector centerWorld, MyVector dirFacingWorld) { totalForce = 0d; List <Interaction> retVal = new List <Interaction>(); // This is only used for left/right modes (lazy initialization) AngularVelocityInfo angularInfo = null; // Scan for objects in my path foreach (BallBlip blip in FindBlipsInCone(centerWorld, dirFacingWorld)) { // Get a vector from me to the ball MyVector lineBetween = blip.Ball.Position - centerWorld; double distance = lineBetween.GetMagnitude(); switch (_mode) { case BeamMode.PushPull: #region Push Pull if (!Utility3D.IsNearZero(distance)) { lineBetween.BecomeUnitVector(); lineBetween.Multiply(-1); double relativeVelocity = MyVector.Dot(lineBetween, blip.Ball.Velocity - _ship.Ball.Velocity); // Figure out how much force is required to make this relative velocity equal zero double force = relativeVelocity * blip.Ball.Mass; // Velocity * Mass is impulse force // See if force needs to be limited by the tractor's max force double maxForce = UtilityCore.GetScaledValue(_forceAtZero, _forceAtMax, 0d, _maxDistance, distance); if (Math.Abs(force) > maxForce) { if (force > 0d) { force = maxForce; } else { force = maxForce * -1d; } } // Add to results retVal.Add(new Interaction(blip, lineBetween, force)); totalForce += Math.Abs(force); } #endregion break; case BeamMode.LeftRight: #region Left Right // Only do something if the lines aren't sitting directly on top of each other (even if they want to repel, // I'd be hesitant to just repel in any random direction) if (!Utility3D.IsNearValue(MyVector.Dot(lineBetween, dirFacingWorld, true), 1d)) { // Figure out how fast the ship is spinning where the blip is MyVector dirToCenterLine; MyVector spinVelocity = GetSpinVelocityAtPoint(ref angularInfo, out dirToCenterLine, dirFacingWorld, lineBetween, blip.Ball.Position); // Figure out the relative velocity (between blip and my spin) double relativeVelocity1 = MyVector.Dot(dirToCenterLine, blip.Ball.Velocity - spinVelocity); // Figure out how much force is required to make this relative velocity equal zero double force1 = relativeVelocity1 * blip.Ball.Mass; // Velocity * Mass is impulse force // See if force needs to be limited by the tractor's max force double maxForce1 = UtilityCore.GetScaledValue(_forceAtZero, _forceAtMax, 0d, _maxDistance, distance); if (Math.Abs(force1) > maxForce1) { if (force1 > 0d) { force1 = maxForce1; } else { force1 = maxForce1 * -1d; } } // Add to results retVal.Add(new Interaction(blip, dirToCenterLine, force1)); totalForce += force1; } #endregion break; default: throw new ApplicationException("Unknown BeamMode: " + _mode.ToString()); } } // Exit Function return(retVal); }
private List <Interaction> GetInteractions_Standard(out double totalForce, MyVector centerWorld, MyVector dirFacingWorld) { totalForce = 0d; List <Interaction> retVal = new List <Interaction>(); AngularVelocityInfo tractorAngularInfo = null; // Scan for objects in my path foreach (BallBlip blip in FindBlipsInCone(centerWorld, dirFacingWorld)) { // Get the distance MyVector lineBetween = blip.Sphere.Position - centerWorld; double distance = lineBetween.GetMagnitude(); // Figure out the force to apply double force = UtilityCore.GetScaledValue(_forceAtZero, _forceAtMax, 0d, _maxDistance, distance); force *= _percent; switch (_mode) { case BeamMode.PushPull: #region Push Pull if (!Utility3D.IsNearZero(distance)) { // Turn lineBetween into a unit vector (it will be multiplied by force later) lineBetween.BecomeUnitVector(); if (_isSoft) { force = GetForceForSoft(ref tractorAngularInfo, force, lineBetween, distance, blip.Ball, dirFacingWorld); } // Add this to the return list retVal.Add(new Interaction(blip, lineBetween, force)); totalForce += Math.Abs(force); // percent is negative when in repulse mode } #endregion break; case BeamMode.LeftRight: #region Left Right // Only do something if the lines aren't sitting directly on top of each other (even if they want to repel, // I'd be hesitant to just repel in any random direction) if (!Utility3D.IsNearValue(MyVector.Dot(lineBetween, dirFacingWorld, true), 1d)) { // Get a line that's orthogonal to lineBetween, and always points toward the dirFacingWorld vector MyVector dirToCenterLine = MyVector.Cross(lineBetween, MyVector.Cross(lineBetween, dirFacingWorld)); dirToCenterLine.BecomeUnitVector(); // Add to the return list retVal.Add(new Interaction(blip, dirToCenterLine, force)); totalForce += Math.Abs(force); // percent is negative when in repulse mode } #endregion break; default: throw new ApplicationException("Unknown BeamMode: " + _mode.ToString()); } } // Exit Function return(retVal); }