Created
October 31, 2015 15:18
-
-
Save lethak/633720578bce96bbf0ba to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Space Engeeneer - Whip's Rocket Guidance Script v11 - revised: 10/28/15 | |
By Joshua Banks | |
*/ | |
List<IMyTerminalBlock> remotes = new List<IMyTerminalBlock>(); | |
List<IMyTerminalBlock> shooterRefrenceList = new List<IMyTerminalBlock>(); | |
List<IMyTerminalBlock> missileRefrenceList = new List<IMyTerminalBlock>(); | |
List<IMyTerminalBlock> gyroList = new List<IMyTerminalBlock>(); | |
string shooterReferenceName = "[Shooter]"; | |
string missileReferenceName = "[Missile 2]"; | |
string gyroName = "[Control 2]"; | |
IMyRemoteControl shooterRefrence; | |
IMyRemoteControl missileRefrence; | |
bool hasRun = false; | |
double pre_launch_delay = 2; | |
double delta_origin; | |
double max_rotation_degrees = 180; //in degrees per second (360 max for small ships, 180 max for large ships) | |
double max_distance = 10000; //maximum guidance distance in meters | |
int tick_limit = 1; //change to higher for less precision | |
int current_tick = 0; | |
int duration = 0; | |
void Main(string argument) | |
{ | |
Echo("Tick: " + current_tick.ToString()); | |
if (!hasRun) | |
GrabRemotes(); | |
if((current_tick % tick_limit) == 0) | |
{ | |
if (duration < Math.Ceiling(pre_launch_delay * 60) ) | |
{ | |
duration++; | |
return; | |
} | |
else | |
{ | |
Echo("Guidance Active"); | |
GuideMissile(); | |
current_tick = 0; | |
} | |
} | |
Echo("Has run?: " + hasRun.ToString()); | |
current_tick++; | |
} | |
void GrabRemotes() | |
{ | |
GridTerminalSystem.SearchBlocksOfName(gyroName, gyroList); | |
GridTerminalSystem.GetBlocksOfType<IMyRemoteControl>(remotes); | |
for(int i = 0 ; i < remotes.Count ; i++) | |
{ | |
var thisRemote = remotes[i] as IMyRemoteControl; | |
if(thisRemote.CustomName.Contains(shooterReferenceName)) | |
{ | |
shooterRefrenceList.Add(thisRemote as IMyRemoteControl); | |
Echo("Found Shooter"); | |
} | |
if(thisRemote.CustomName.Contains(missileReferenceName)) | |
{ | |
missileRefrenceList.Add(thisRemote as IMyRemoteControl); | |
Echo("Found Missile"); | |
} | |
} | |
//---Check if we do not have an shooter remote | |
if(shooterRefrenceList.Count == 0) | |
{ | |
Echo("No shooter refrence block found"); | |
hasRun = false; | |
return; | |
} | |
//---Check if we do not have a missile remote | |
else if(missileRefrenceList.Count == 0) | |
{ | |
Echo("No missile refrence block found"); | |
hasRun = false; | |
return; | |
} | |
else if(gyroList.Count == 0) | |
{ | |
Echo("No control gyro found"); | |
hasRun = false; | |
return; | |
} | |
else | |
{ | |
Echo("Ready to run"); | |
shooterRefrence = shooterRefrenceList[0] as IMyRemoteControl; | |
missileRefrence = missileRefrenceList[0] as IMyRemoteControl; | |
hasRun = true; | |
} | |
} | |
void GuideMissile() | |
{ | |
//---Get positions of our blocks with relation to world center | |
var originPos = shooterRefrence.GetPosition(); | |
var missilePos = missileRefrence.GetPosition(); | |
//---Find current distance from shooter to missile | |
delta_origin = Vector3D.Distance(originPos, missilePos); | |
//---Check if we are in range | |
if(delta_origin < max_distance) //change this later to be larger | |
{ | |
//---Get forward vector from our shooter vessel | |
var shooterForward = shooterRefrence.Position + Base6Directions.GetIntVector(shooterRefrence.Orientation.TransformDirection(Base6Directions.Direction.Forward)); | |
var targetVector = shooterRefrence.CubeGrid.GridIntegerToWorld(shooterForward); | |
var targetVectorNorm = Vector3D.Normalize(targetVector - shooterRefrence.GetPosition()); | |
//---Find vector from shooter to missile | |
var missileVector = Vector3D.Subtract(missilePos, originPos); | |
//---Calculate angle between shooter vector and missile vector | |
double dotProduct; Vector3D.Dot(ref targetVectorNorm, ref missileVector, out dotProduct); | |
double x = dotProduct / missileVector.Length(); | |
double rawDevAngle = Math.Acos(x) * 180f / Math.PI; //angle between shooter vector and missile | |
//---Calculate perpendicular distance from shooter vector | |
var projectionVector = dotProduct * targetVectorNorm; | |
double deviationDistance = Vector3D.Distance(projectionVector,missileVector); | |
Echo("Angular Dev: " + rawDevAngle.ToString()); | |
//---Determine scaling factor | |
double scalingFactor; | |
if(rawDevAngle < 90) | |
{ | |
if(deviationDistance > 200) | |
{ | |
scalingFactor = delta_origin; //if we are too far from the beam, dont add any more distance till we are closer | |
} | |
else | |
{ | |
scalingFactor = (delta_origin + 200); //travel approx. 200m from current position in direction of target vector | |
} | |
} | |
else | |
{ | |
scalingFactor = 200; //if missile is behind the shooter, goes 200m directly infront of shooter for better accuracy | |
} | |
var destination = shooterRefrence.GetPosition() + scalingFactor * targetVectorNorm; | |
Echo(destination.ToString()); //debug | |
//---Find front left and top vectors of our missileVector | |
var missileGridX = missileRefrence.Position + Base6Directions.GetIntVector(missileRefrence.Orientation.TransformDirection(Base6Directions.Direction.Forward)); | |
var missileWorldX = missileRefrence.CubeGrid.GridIntegerToWorld(missileGridX) - missilePos; | |
var missileGridY = missileRefrence.Position + Base6Directions.GetIntVector(missileRefrence.Orientation.TransformDirection(Base6Directions.Direction.Left)); | |
var missileWorldY = missileRefrence.CubeGrid.GridIntegerToWorld(missileGridY) - missilePos; | |
var missileGridZ = missileRefrence.Position + Base6Directions.GetIntVector(missileRefrence.Orientation.TransformDirection(Base6Directions.Direction.Up)); | |
var missileWorldZ = missileRefrence.CubeGrid.GridIntegerToWorld(missileGridZ) - missilePos; | |
//---Find vector from missile to destination | |
var shipToTarget = Vector3D.Subtract(destination, missilePos); | |
//---Project target vector onto our top left and up vectors | |
double dotX; Vector3D.Dot(ref shipToTarget, ref missileWorldX, out dotX); | |
double dotY; Vector3D.Dot(ref shipToTarget, ref missileWorldY, out dotY); | |
double dotZ; Vector3D.Dot(ref shipToTarget, ref missileWorldZ, out dotZ); | |
var projTargetX = dotX / (missileWorldX.Length() * missileWorldX.Length()) * missileWorldX; | |
var projTargetY = dotY / (missileWorldY.Length() * missileWorldY.Length()) * missileWorldY; | |
var projTargetZ = dotZ / (missileWorldZ.Length() * missileWorldZ.Length()) * missileWorldZ; | |
//---Get Yaw and Pitch Angles | |
double angleYaw = Math.Atan(projTargetY.Length() / projTargetX.Length()); | |
double anglePitch = Math.Atan(projTargetZ.Length() / projTargetX.Length()); | |
//---Check if x is positive or negative | |
double checkPositiveX; Vector3D.Dot(ref missileWorldX, ref projTargetX, out checkPositiveX); Echo("check x:" + checkPositiveX.ToString()); | |
if(checkPositiveX < 0) | |
{ | |
angleYaw += Math.PI/2; //we only change one value so it doesnt spaz | |
} | |
//---Check if yaw angle is left or right | |
double checkYaw; Vector3D.Dot(ref missileWorldY, ref projTargetY, out checkYaw); Echo("check yaw:" + checkYaw.ToString()); | |
if(checkYaw > 0) //yaw is backwards for what ever reason | |
angleYaw = -angleYaw; | |
Echo("yaw angle:" + angleYaw.ToString()); | |
//---Check if pitch angle is up or down | |
double checkPitch; Vector3D.Dot(ref missileWorldZ, ref projTargetZ, out checkPitch); Echo("check pitch:" + checkPitch.ToString()); | |
if(checkPitch < 0) | |
anglePitch = -anglePitch; | |
Echo("pitch angle:" + anglePitch.ToString()); | |
//---Angle controller | |
double max_rotation_radians = max_rotation_degrees * (Math.PI / 180); | |
double yawSpeed = max_rotation_radians * angleYaw / Math.Abs(angleYaw); | |
double pitchSpeed = max_rotation_radians * anglePitch / Math.Abs(anglePitch); | |
/*if (angleYaw < Math.PI/4) | |
{ | |
yawSpeed = angleYaw * max_rotation_radians / (Math.PI/4); | |
} | |
else | |
{ | |
yawSpeed = max_rotation_radians; | |
} | |
if (anglePitch < Math.PI/4) | |
{ | |
pitchSpeed = anglePitch * max_rotation_radians / (Math.PI/4); | |
} | |
else | |
{ | |
pitchSpeed = max_rotation_radians; | |
}*/ | |
//double yawSpeed = angleYaw / Math.PI * max_rotation_radians; | |
//double pitchSpeed = anglePitch / Math.PI * max_rotation_radians; | |
for(int i = 0; i < gyroList.Count; i++) | |
{ | |
var thisGyro = gyroList[i] as IMyGyro; | |
thisGyro.SetValue<float>("Yaw", (float)yawSpeed); | |
thisGyro.SetValue<float>("Pitch", (float)pitchSpeed); | |
thisGyro.SetValue("Override", true); | |
} | |
} | |
else | |
{ | |
Echo("Out of range"); | |
for(int i = 0; i < gyroList.Count; i++) | |
{ | |
var thisGyro = gyroList[i] as IMyGyro; | |
thisGyro.SetValue<float>("Yaw", 0f); | |
thisGyro.SetValue<float>("Pitch", 0f); | |
thisGyro.SetValue("Override", true); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment