Feb 102012
 

This Megabite, the 20th in the series, will focus on a question asked by a reader.  D Hunter asks:

… I’d love to know how to script a player-controlled ship you can walk around while it’s moving (like on autopilot). I’ve been struggling with this and it’s hard to find resources on that particular issue. If you can find a way to generalize it to the principal, that would be sweet too; if its not in your interest, no worries either :) I’m still pretty new to Unity

Well, D Hunter, I’m happy to say that this will be an easy one for you – assuming your autopilot is already functional.  What we’re going to do here is set up a rigidbody for the “ship”, switch it to isKinematic = true, and add some constraints for the demo.

For my ship, I just made a cube.  I added a rigidbody component like so:

Take note of the constraints – We don’t want it flipping around for any reason, and we don’t want it being affected by gravity to fall into the planet.  For motion, I simply added a RotateAround .js file, but if yours uses AddForce or ConstantForce, that should work just as well.

function Update () {
transform.RotateAround(Vector3.zero, Vector3.up, 10 * Time.deltaTime);
}

It’s rotating around the vector of 0,0,0.  When I added my standard character controller, I made sure to add it as a CHILD of the ship itself, so it rotates along with the parent.  Input and movement are now relative to the parent.  Which means you don’t want to simply jump off of the ship and hit the ground – the character, if attached as a child, would continue to move with the ship.  If you wanted something like that, you would need to have something added to set the parent to null given a certain scenario.

Because of this, I added some invisible walls to make sure the character stays on the ship at all times.  The collision detection isn’t as strong as it should be, so if you were to jump against them a few times your character will fall from the ship and you can see how bad that could get :)

Of course, you want to make sure those walls are children of that parent ship as well.  They will all move together that way and everything runs smooth.  Below, I’ll add the demonstration scene and a download link for the package itself so it might help anyone else struggling with this issue

Use WSAD controls to move around :)


Download Package

Nov 042011
 

In the last article, we set up a basic framework that used the accelerometers of our device to manipulate our little cube.  Obviously if our game was more finalized we would want to hide all the debugging numbers and such completely, but for now, lets simply toggle them on and off by using the “back” button on the device.

Android registers this button as “escape”, which is effectively like pushing the escape button on your keyboard.  This is handy because it will allow us to test our functionality quickly.

To begin, let’s use our existing script for movement (mine was called “cubemover”), and set up a private variable called overlayOn.  Because this is an off/on variable (this is called a “boolean”), we will set it to false by default, like this:

private var overlayOn = false;

Next, we just need a way to toggle it.  This script will go into the Update() section of the script to listen for our key press.

//Making use of the Android "Back" Button
if (Input.GetKeyDown(KeyCode.Escape)) {
	if (overlayOn == false ) {
	overlayOn = true;
	} else {
	overlayOn = false;
	}
}

The last thing to do is simply encase our GUI script elements in an IF statement.  With everything together, the whole script should end up like this:

var dir : Vector3 = Vector3.zero;
private var calibrateX : float = 0;
private var calibrateY : float = 0;
private var overlayOn = false;

function Update () {
		//In landscape mode, +X is up, -X is down, +Y is left and -Y is right
	dir.x = Input.acceleration.x;
	dir.y = Input.acceleration.y;
	dir.z = Input.acceleration.z;

	if (dir.sqrMagnitude > 1) {
		dir.Normalize();
	}
	//left/right
	transform.position.x = (transform.position.x - (dir.y - calibrateY));
	//up/down
	transform.position.y = (transform.position.y + (dir.x - calibrateX));
//Making use of the Android "Back" Button
if (Input.GetKeyDown(KeyCode.Escape)) {
	if (overlayOn == false ) {
	overlayOn = true;
	} else {
	overlayOn = false;
	}
}
}
function OnGUI() {
if (overlayOn == true) {  // only display if Overlay is toggled on.
	GUI.Label(Rect(4,4,300,30), "dir.x: " + dir.x);
	GUI.Label(Rect(4,44,300,30), "dir.y: " + dir.y);
	GUI.Label(Rect(4,84,300,30), "dir.z: " + dir.z);
	//Button to Reset to center position
	if (GUI.Button (Rect(Screen.width /2 - 60, Screen.height /2 - 120, 120, 50), "Reset")) {
	transform.position = Vector3(0,0,0);
	}
	//Button to recalibrate Zeroed control center
	if (GUI.Button (Rect(Screen.width /2  - 60, Screen.height /2 - 65, 120, 50), "Calibrate")) {
	calibrateX = dir.x;
	calibrateY = dir.y;
	}
	//Button to exit program
	if (GUI.Button (Rect(Screen.width /2  - 60, Screen.height /2 - 10, 120, 50), "Exit Game")) {
	Application.Quit();
	}
}
}

As an added bonus, I added in a third button that will actually exit the program as well.  When saved and run, everything will disappear until we hit our escape key.  after we do, we see this:

On the next page, we’re going to import some assets to use for the first time and get rid of that blue background. :)