Advertisement
Whiplash141

Whip's Missile Guidance Script

Nov 1st, 2015
2,555
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 15.13 KB | None | 0 0
  1.  
  2. /*
  3. Whip's GASP Missile Guidance Script v14 - revised: 11/1/15
  4. /// PUBLIC RELEASE ///
  5. HOWDY!
  6. ___________________________________________________________________
  7. Video Instructions:
  8. https://www.youtube.com/watch?v=B4cLBJ-D0YQ
  9. ___________________________________________________________________
  10. Setup Instructions:  
  11.  
  12. The missile must be attached to the same grid as your firing
  13. platform via merge block, connector, or rotor.
  14.    
  15.     Missile Setup
  16.      1) Name all forward thrusters "Main Thruster"
  17.      2) Name all side thrusters "Side Thruster"
  18.      3) Name all missile batteries "Missile Battery"
  19.      4) Name all missile merges "Missile Merge"
  20.      5) Make a remote with name "[Missile 1]" facing forward
  21.      6) Make a gyro with name "[Control 1]" facing forward
  22.      7) Place this program on the missile
  23.      8) Place a timer on the missile
  24.         DO NOT TRIGGER IT YET!!!
  25.          - Set to trigger now itself
  26.          - Set to start itself
  27.          - Set to run this program
  28.    
  29.     Shooter Ship Setup
  30.      1) Make a remote with name "[Shooter]" facing forward
  31. ___________________________________________________________________
  32. Firing Instructions:
  33.    
  34. Trigger the timer you made in Step 8 and aim where you want
  35. the missile to go! :)
  36. ___________________________________________________________________
  37. Author's Notes:
  38.  
  39. If you have any questions, comments, or concerns, feel free to leave a comment on          
  40. the workshop page: http://steamcommunity.com/sharedfiles/filedetails/?id=416932930        
  41.  
  42. - Whiplash141 :)  
  43. */
  44.  
  45. /*
  46. ___________________________________________________________________
  47.  
  48. ========== You can edit these variables to your liking ============
  49. ___________________________________________________________________
  50. */
  51.     string shooterReferenceName = "[Shooter]"; //name tag of shooter's remote
  52.     string missileReferenceName = "[Missile 1]"; //name tag of missile's remote
  53.     string gyroName = "[Control 1]"; //name of missile gyro
  54.     string forwardThrustName = "Main Thruster"; //name tag of forward thrust on the missile        
  55.     string maneuveringThrustersName = "Side Thruster"; //name tag of manevering thrusters on the missile
  56.     string mergeName = "Missile Merge"; //name tag of missile merge    
  57.     string batteryName = "Missile Battery"; //name tag of missile battery
  58.     double pre_launch_delay = 2; //time (in seconds) that the missile will delay guidance activation by
  59.     double max_rotation_degrees = 180; //in degrees per second (360 max for small ships, 180 max for large ships)
  60.     double max_distance = 10000; //maximum guidance distance in meters; don't enlarge it lol, 10km is super far
  61.     int tick_limit = 1; //change to higher for less precision
  62.  
  63. /*
  64. ___________________________________________________________________
  65.  
  66. ============= Don't touch anything below this :) ==================
  67. ___________________________________________________________________
  68. */
  69.     List<IMyTerminalBlock> remotes = new List<IMyTerminalBlock>();  
  70.     List<IMyTerminalBlock> shooterRefrenceList = new List<IMyTerminalBlock>();  
  71.     List<IMyTerminalBlock> missileRefrenceList = new List<IMyTerminalBlock>();  
  72.     List<IMyTerminalBlock> gyroList = new List<IMyTerminalBlock>();
  73.     List<IMyTerminalBlock> forwardThrusters = new List<IMyTerminalBlock>();                
  74.     List<IMyTerminalBlock> mergeBlocks = new List<IMyTerminalBlock>();        
  75.     List<IMyTerminalBlock> maneuveringThrusters = new List<IMyTerminalBlock>();      
  76.     List<IMyTerminalBlock> batteries = new List<IMyTerminalBlock>();      
  77.     IMyRemoteControl shooterRefrence;  
  78.     IMyRemoteControl missileRefrence;  
  79.     bool hasRun = false;
  80.     double delta_origin;
  81.     int current_tick = 0;  
  82.     int duration = 0;      
  83.     int timeElapsed = 0;      
  84.  
  85. void Main()  
  86. {  
  87.     Echo("Tick: " + current_tick.ToString());
  88.     MissileSystems();
  89.    
  90.     if (!hasRun)
  91.         GrabRemotes();
  92.    
  93.     if (duration < Math.Ceiling(pre_launch_delay * 60))
  94.     {
  95.         duration++;
  96.         return;
  97.     }
  98.     else
  99.     {
  100.         if((current_tick % tick_limit) == 0)
  101.         {
  102.             Echo("Guidance Active");  
  103.             GuideMissile();  
  104.             current_tick = 0;  
  105.         }
  106.        
  107.     }      
  108.     current_tick++;
  109.     Echo("Has run?: " + hasRun);
  110. }      
  111.  
  112. void GrabRemotes()
  113. {
  114.     GridTerminalSystem.SearchBlocksOfName(gyroName, gyroList);
  115.     GridTerminalSystem.GetBlocksOfType<IMyRemoteControl>(remotes);
  116.     for(int i = 0 ; i < remotes.Count ; i++)  
  117.         {  
  118.             var thisRemote = remotes[i] as IMyRemoteControl;
  119.             if(thisRemote.CustomName.Contains(shooterReferenceName))  
  120.             {    
  121.                 shooterRefrenceList.Add(thisRemote as IMyRemoteControl);  
  122.                 Echo("Found Shooter");  
  123.             }  
  124.  
  125.             if(thisRemote.CustomName.Contains(missileReferenceName))  
  126.             {  
  127.                 missileRefrenceList.Add(thisRemote as IMyRemoteControl);  
  128.                 Echo("Found Missile");  
  129.             }  
  130.         }
  131.  
  132. //---Check if we do not have an shooter remote
  133.     if(shooterRefrenceList.Count == 0)  
  134.     {  
  135.         Echo("No shooter refrence block found");  
  136.         hasRun = false;  
  137.         return;  
  138.     }
  139. //---Check if we do not have a missile remote
  140.     else if(missileRefrenceList.Count == 0)  
  141.     {  
  142.         Echo("No missile refrence block found");  
  143.         hasRun = false;  
  144.         return;  
  145.     }  
  146.     else if(gyroList.Count == 0)
  147.     {
  148.         Echo("No control gyro found");
  149.         hasRun = false;
  150.         return;
  151.     }
  152.     else
  153.     {    
  154.         Echo("Ready to run");
  155.         shooterRefrence = shooterRefrenceList[0] as IMyRemoteControl;  
  156.         missileRefrence = missileRefrenceList[0] as IMyRemoteControl;  
  157.         hasRun = true;  
  158.     }
  159. }
  160.  
  161. void GuideMissile()  
  162. {  
  163. //---Get positions of our blocks with relation to world center
  164.     var originPos = shooterRefrence.GetPosition();  
  165.     var missilePos = missileRefrence.GetPosition();  
  166.  
  167. //---Find current distance from shooter to missile
  168.     delta_origin = Vector3D.Distance(originPos, missilePos);
  169.  
  170. //---Check if we are in range    
  171.     if(delta_origin < max_distance) //change this later to be larger
  172.     {
  173.     //---Get forward vector from our shooter vessel
  174.         var shooterForward = shooterRefrence.Position + Base6Directions.GetIntVector(shooterRefrence.Orientation.TransformDirection(Base6Directions.Direction.Forward));  
  175.         var targetVector = shooterRefrence.CubeGrid.GridIntegerToWorld(shooterForward);  
  176.         var targetVectorNorm = Vector3D.Normalize(targetVector - shooterRefrence.GetPosition());  
  177.  
  178.     //---Find vector from shooter to missile
  179.         var missileVector = Vector3D.Subtract(missilePos, originPos);
  180.  
  181.     //---Calculate angle between shooter vector and missile vector
  182.         double dotProduct; Vector3D.Dot(ref targetVectorNorm, ref missileVector, out dotProduct);
  183.         double x = dotProduct / missileVector.Length();      
  184.         double rawDevAngle = Math.Acos(x) * 180f / Math.PI; //angle between shooter vector and missile
  185.  
  186.     //---Calculate perpendicular distance from shooter vector
  187.         var projectionVector = dotProduct * targetVectorNorm;
  188.         double deviationDistance = Vector3D.Distance(projectionVector,missileVector);
  189.         Echo("Angular Dev: " + rawDevAngle.ToString());
  190.  
  191.     //---Determine scaling factor
  192.         double scalingFactor;
  193.         if(rawDevAngle < 90)
  194.         {
  195.             if(deviationDistance > 200)
  196.             {
  197.                 scalingFactor = delta_origin; //if we are too far from the beam, dont add any more distance till we are closer
  198.             }
  199.             else
  200.             {
  201.                 scalingFactor = (delta_origin + 200); //travel approx. 200m from current position in direction of target vector
  202.             }
  203.         }
  204.         else
  205.         {
  206.             scalingFactor = 200; //if missile is behind the shooter, goes 200m directly infront of shooter for better accuracy
  207.         }
  208.         var destination = shooterRefrence.GetPosition() + scalingFactor * targetVectorNorm;  
  209.         Echo(destination.ToString()); //debug
  210.  
  211.     //---Find front left and top vectors of our missileVector
  212.         var missileGridX = missileRefrence.Position + Base6Directions.GetIntVector(missileRefrence.Orientation.TransformDirection(Base6Directions.Direction.Forward));
  213.         var missileWorldX = missileRefrence.CubeGrid.GridIntegerToWorld(missileGridX) - missilePos;
  214.  
  215.         var missileGridY = missileRefrence.Position + Base6Directions.GetIntVector(missileRefrence.Orientation.TransformDirection(Base6Directions.Direction.Left));
  216.         var missileWorldY = missileRefrence.CubeGrid.GridIntegerToWorld(missileGridY) - missilePos;
  217.  
  218.         var missileGridZ = missileRefrence.Position + Base6Directions.GetIntVector(missileRefrence.Orientation.TransformDirection(Base6Directions.Direction.Up));
  219.         var missileWorldZ = missileRefrence.CubeGrid.GridIntegerToWorld(missileGridZ) - missilePos;
  220.  
  221.     //---Find vector from missile to destination
  222.         var shipToTarget = Vector3D.Subtract(destination, missilePos);
  223.  
  224.     //---Project target vector onto our top left and up vectors
  225.         double dotX; Vector3D.Dot(ref shipToTarget, ref missileWorldX, out dotX);
  226.         double dotY; Vector3D.Dot(ref shipToTarget, ref missileWorldY, out dotY);
  227.         double dotZ; Vector3D.Dot(ref shipToTarget, ref missileWorldZ, out dotZ);
  228.         var projTargetX = dotX / (missileWorldX.Length() * missileWorldX.Length()) * missileWorldX;
  229.         var projTargetY = dotY / (missileWorldY.Length() * missileWorldY.Length()) * missileWorldY;
  230.         var projTargetZ = dotZ / (missileWorldZ.Length() * missileWorldZ.Length()) * missileWorldZ;
  231.  
  232.     //---Get Yaw and Pitch Angles
  233.         double angleYaw = Math.Atan(projTargetY.Length() / projTargetX.Length());
  234.         double anglePitch = Math.Atan(projTargetZ.Length() / projTargetX.Length());
  235.  
  236.     //---Check if x is positive or negative
  237.         double checkPositiveX; Vector3D.Dot(ref missileWorldX, ref projTargetX, out checkPositiveX); Echo("check x:" + checkPositiveX.ToString());
  238.         if(checkPositiveX < 0)
  239.         {
  240.             angleYaw += Math.PI/2; //we only change one value so it doesnt spaz
  241.         }
  242.  
  243.     //---Check if yaw angle is left or right
  244.         double checkYaw; Vector3D.Dot(ref missileWorldY, ref projTargetY, out checkYaw); Echo("check yaw:" + checkYaw.ToString());
  245.         if(checkYaw > 0) //yaw is backwards for what ever reason
  246.             angleYaw = -angleYaw;
  247.         Echo("yaw angle:" + angleYaw.ToString());
  248.  
  249.     //---Check if pitch angle is up or down
  250.         double checkPitch; Vector3D.Dot(ref missileWorldZ, ref projTargetZ, out checkPitch); Echo("check pitch:" + checkPitch.ToString());
  251.         if(checkPitch < 0)
  252.             anglePitch = -anglePitch;
  253.         Echo("pitch angle:" + anglePitch.ToString());
  254.  
  255.     //---Angle controller
  256.         double max_rotation_radians = max_rotation_degrees * (Math.PI / 180);
  257.         double yawSpeed = max_rotation_radians * angleYaw / Math.Abs(angleYaw);
  258.         double pitchSpeed = max_rotation_radians * anglePitch / Math.Abs(anglePitch);
  259.  
  260.         //Alt method 1: Proportional Control
  261.         //(small ship gyros too weak for this to be effective)
  262.         /*
  263.             double yawSpeed = angleYaw / Math.PI * max_rotation_radians;
  264.             double pitchSpeed = anglePitch / Math.PI * max_rotation_radians;
  265.         */
  266.        
  267.         //Alt method 2: Proportional Control with bounds
  268.         //(Small gyros still too weak :/)
  269.             /*if (angleYaw < Math.PI/4)
  270.             {
  271.                 yawSpeed = angleYaw * max_rotation_radians / (Math.PI/4);
  272.             }
  273.             else
  274.             {
  275.                 yawSpeed = max_rotation_radians;
  276.             }
  277.              
  278.             if (anglePitch < Math.PI/4)
  279.             {
  280.                 pitchSpeed = anglePitch * max_rotation_radians / (Math.PI/4);
  281.             }
  282.             else
  283.             {
  284.                 pitchSpeed = max_rotation_radians;
  285.             }*/
  286.  
  287.     //---Set appropriate gyro override
  288.         for(int i = 0; i < gyroList.Count; i++)
  289.         {
  290.             var thisGyro = gyroList[i] as IMyGyro;
  291.             thisGyro.SetValue<float>("Yaw", (float)yawSpeed);
  292.             thisGyro.SetValue<float>("Pitch", (float)pitchSpeed);
  293.             thisGyro.SetValue("Override", true);
  294.         }
  295.     }
  296.     else
  297.     {
  298.         Echo("Out of range");
  299.         for(int i = 0; i < gyroList.Count; i++)
  300.         {
  301.             var thisGyro = gyroList[i] as IMyGyro;
  302.             thisGyro.SetValue<float>("Yaw", 0f);
  303.             thisGyro.SetValue<float>("Pitch", 0f);
  304.             thisGyro.SetValue("Override", true);
  305.         }
  306.     }
  307. }
  308.  
  309. void MissileSystems()              
  310. {            
  311.     GridTerminalSystem.SearchBlocksOfName(mergeName,mergeBlocks);    
  312.     GridTerminalSystem.SearchBlocksOfName(batteryName,batteries);
  313.  
  314. //---Check if we have merges
  315.     if(mergeBlocks.Count == 0)
  316.         Echo("No missile merges found");
  317.  
  318. //---Check if we have batteries
  319.     if(mergeBlocks.Count == 0)
  320.         Echo("No missile batteries found");
  321.  
  322. //---Activate battery, detach merge, and activate thrust
  323.     if (timeElapsed == 0)        
  324.     {        
  325.         for(int i = 0 ; i < batteries.Count ; i++)  
  326.         {  
  327.             var thisBattery = batteries[i] as IMyBatteryBlock;    
  328.             thisBattery.ApplyAction("OnOff_On");
  329.             thisBattery.SetValue("Recharge", false);  
  330.             thisBattery.SetValue("Discharge", true);
  331.         }        
  332.     }  
  333.     else if(timeElapsed == 60) //delay release by 1 second so power systems activate  
  334.     {    
  335.         for(int i = 0 ; i < mergeBlocks.Count ; i++)  
  336.         {  
  337.             var thisMerge = mergeBlocks[i] as IMyShipMergeBlock;  
  338.             thisMerge.ApplyAction("OnOff_Off");  
  339.         }
  340.         ThrusterOverride();        
  341.         ManeuveringThrust();        
  342.         Echo("Detach Thrust Off");        
  343.         Echo("Thruster Override On");        
  344.     }          
  345.  
  346.     if (timeElapsed < 60)
  347.         timeElapsed++;        
  348. }
  349.  
  350. void ManeuveringThrust()        
  351. {        
  352.     if(maneuveringThrusters.Count == 0)
  353.         Echo("No side thrust found");
  354.    
  355.     GridTerminalSystem.SearchBlocksOfName(maneuveringThrustersName,maneuveringThrusters);        
  356.     for(int i = 0 ; i < maneuveringThrusters.Count ; i++)        
  357.     {        
  358.         IMyThrust Thrust = maneuveringThrusters[i] as IMyThrust;
  359.         Thrust.ApplyAction("OnOff_On");        
  360.     }        
  361. }        
  362.              
  363. void ThrusterOverride()        
  364. {        
  365.     if(forwardThrusters.Count == 0)
  366.         Echo("No forward thrust found");
  367.    
  368.     GridTerminalSystem.SearchBlocksOfName(forwardThrustName,forwardThrusters);              
  369.     for(int i = 0; i < forwardThrusters.Count;i++)              
  370.     {              
  371.         IMyThrust Thrust = forwardThrusters[i] as IMyThrust;
  372.         Thrust.ApplyAction("OnOff_On");
  373.         Thrust.SetValue<float>("Override", float.MaxValue);              
  374.     }          
  375. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement