Difference between revisions of "Module code examples"

From Kerbal Space Program Wiki
Jump to: navigation, search
(Useful geometry stuff)
(Fly-by-wire)
Line 132: Line 132:
 
print("position = " + (Vector3)position);
 
print("position = " + (Vector3)position);
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 +
  
 
== Fly-by-wire ==
 
== Fly-by-wire ==
Line 160: Line 162:
 
...
 
...
 
</syntaxhighlight>
 
</syntaxhighlight>
 
 
  
 
== Modifying the available warp rates ==
 
== Modifying the available warp rates ==

Revision as of 11:56, 8 March 2012

Here is a collection of example code for various tasks you might want to perform in your module.


Debugging your code

The most important thing to be able to do! This will print to the in-game error console, which you can bring up from anywhere in the game by pressing Alt-F2:

print("hello world!");


Creating a GUI Window and Button

This module will create a new GUI window and button, on button press the part will explode, close the GUI, and be removed.

using UnityEngine;
 
/*
This module will create a new GUI window and button, on button press the part will explode, close the GUI, and be removed.
*/
	public class SelfDestruct : Part
	{
		protected Rect windowPos;
 
		private void WindowGUI(int windowID)
		{
        	GUI.DragWindow(new Rect(0, 0, 10000, 20)); //create a dragable window
       	 	GUIStyle mySty = new GUIStyle(GUI.skin.button); 
       		mySty.normal.textColor = mySty.focused.textColor = Color.white;
      		mySty.hover.textColor = mySty.active.textColor = Color.yellow;
      		mySty.onNormal.textColor = mySty.onFocused.textColor = mySty.onHover.textColor = mySty.onActive.textColor = Color.green;
      		sty.padding = new RectOffset(8, 8, 8, 8);
		 //It seems you need to put all buttons between vertical or horizontal GUILayout functions
		 //Without doing this GUILayout.Button() will only be true if you right and left click at the same time
		GUILayout.BeginVertical();
			if (GUILayout.Button("DESTROY",mySty,GUILayout.ExpandWidth(true)))//GUILayout.Button is "true" when clicked
			{	
			this.explode();
			this.onPartDestroy ();
			this.Die ();
			}
		GUILayout.EndVertical();
 
		}
		private void drawGUI()
		{
            GUI.skin = HighLogic.Skin;
            windowPos = GUILayout.Window(1, windowPos, WindowGUI, "Self Destruct", GUILayout.MinWidth(100));	 
		}
		protected override void onFlightStart()  //Called when vessel is placed on the launchpad
		{
		    RenderingManager.AddToPostDrawQueue(3, new Callback(drawGUI));//start the GUI
		}
		protected override void onPartStart()
		{
       		if ((windowPos.x == 0) && (windowPos.y == 0))//windowPos is used to position the GUI window, lets set it in the center of the screen
			{
          	  windowPos = new Rect(Screen.width / 2, Screen.height / 2, 10, 10);
   			}
		}
	 	protected override void onPartDestroy() 
		{
			RenderingManager.RemoveFromPostDrawQueue(3, new Callback(drawGUI)); //close the GUI
   		}
 
	}


Useful geometry stuff

All these vectors live in a "world" coordinate system. This coordinate system has an arbitrary orientation and an origin that is periodically shifted to keep it reasonably close to the active ship.

Vector3d has lots of useful vector manipulation methods that you should check out.

//position of the ship's center of mass:
Vector3d position = vessel.findWorldCenterOfMass();
 
//unit vectors in the up (normal to planet surface), east, and north (parallel to planet surface) directions
Vector3d eastUnit = vessel.mainBody.getRFrmVel(position).normalized; //uses the rotation of the body's frame to determine "east"
Vector3d upUnit = (position - vessel.mainBody.position).normalized;
Vector3d northUnit = Vector3d.Cross(upUnit, eastUnit); //north = up cross east
 
double altitude = vessel.mainBody.GetAltitude(position);
 
//ship velocity in an external, non-rotating frame:
Vector3d nonRotatingFrameVelocity = vessel.orbit.GetVel(); 
 
//velocity as seen in planet's rotating frame
Vector3d rotatingFrameVelocity = nonRotatingFrameVelocity - vessel.mainBody.getRFrmVel(position); 
 
//local acceleration vector due to gravity:
Vector3d geeAcceleration = FlightGlobals.getGeeForceAtPosition(position); 
 
//given currentVelocity in rotating frame, find coriolis acceleration:
//this first one becomes zero when the game switches out of the planet's reference frame
Vector3d coriolisAcceleration = FlightGlobals.getCoriolisAcc(currentVelocity, vessel.mainBody); 
//this doesn't:
Vector3d myCoriolisAcc = -2 * Vector3d.Cross(vessel.mainBody.angularVelocity, currentVelocity); 
 
//Moment of inertia of the ship around x, y, and z axes (I think y is always the roll axis):
Vector3d MOI = vessel.findLocalMOI(vessel.findWorldCenterOfMass());
 
//direction in which the ship currently points:
Vector3d heading = (Vector3d)vessel.transform.up;

It's often useful to transform a vector into a coordinate system affixed to the ship, which will in general be rotated with respect to the world coordinate system. To do this use vessel.transform.InverseTransformDirection( ):

//angular velocity of the ship around three axes,
//x-component = pitch rate, y = roll rate, z = yaw rate:
Vector3d angularVelocity = (Vector3d)vessel.transform.InverseTransformDirection(vessel.rigidbody.angularVelocity);
 
//to damp out roll (k is some gain):
roll_command = k * angularVelocity.y;
 
//to command the ship to slew towards a given direction, dir (k is some gain):
//error will be (0, 1, 0) if dir = heading:
Vector3d error = (Vector3d)vessel.transform.InverseTransformDirection((Vector3)dir);
yaw_command = k * error.x;
pitch_command = -k * error.z;

When you print vectors you may find it useful to first cast them to the Unity type Vector3, which by default only prints one digit past the decimal point, whereas Vector3d prints all the digits. Using Vector3's makes your debugging output much easier to read:

print("position = " + (Vector3)position);


Fly-by-wire

You can control the flight from code as if you were the player using w,a,s,d,q,e or a joystick. In addition to yaw, pitch, roll, and throttle as shown below, the FlightCtrlState class gives access to a few other controls that you can check out.

...
protected override void onFlightStart()  //Called when vessel is placed on the launchpad
{
    //at the beginning of the flight, register your fly-by-wire control function that will be called repeatedly during flight:
    FlightInputHandler.OnFlyByWire += new FlightInputHandler.FlightInputCallback(fly);
 
    ...
}
 
//now this function gets called every frame or something and gives you access to the flight controls
private void fly(FlightCtrlState s) {
    s.yaw = -0.2F;  //set yaw input to 20% left
    s.pitch += 0.3F; //set pitch input to whatever the player has input + 30%
    s.roll = 0.5F;   //set roll to 50% (either clockwise or counterclockwise, try it and find out)
    s.mainThrottle = 0.8F; //set throttle to 80%
 
    //the range of yaw, pitch, and roll is -1.0F to 1.0F, and the throttle goes from 0.0F to 1.0F.
    //if your code might violate that it's probably a good idea to clamp the inputs, e.g.:
    s.roll = Mathf.Clamp(s.roll, -1.0F, +1.0F);
}
...

Modifying the available warp rates

using UnityEngine;
...
TimeWarp timeWarp = (TimeWarp)FindObjectOfType(typeof(TimeWarp)); //documentation claims this function is slow
                                                                  //so call it once and store the reference
timeWarp.warpRates[3] = 45; //set the fourth warp rate to be x45
timeWarp.altitudeLimits[3] = 0.5; //set the altitude limit for the fourth warp rate. Is this measured in planetary radii?