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); }
/// <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_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); }