Miker’s Scripting Tutorial

for Unity3D game engine

Note: this document assumes you have already done the following.

Unity keyboard control for move & turn

Now let’s learn scripting by looking at basic scripts for controlling a cube we’ve made. Here’s a sample that uses the user’s choice of fwd/bkwd keys for movement and their left/right keys for turning. (Keys are defined in menu “Edit:Project Settings:Input”) Create this script and add it to a visible cube. (You definitely want to move the camera while editing so that the cube is visible when you start playing.)

/* move.js */ /* Script for game objects that respond to key controls. */ var moveSpeed : float = 5.0; /* Block speed */ var turnSpeed : float = 90.0; /* Degrees per second. */ /* Note: MUST use “.0” or “float”!! */ function Update( ) { /* Move Forward or Backward... */ /* [default keys: w/s/fwd/bak = “Vertical” (z axis)] */ var zt = moveSpeed * Input.GetAxis("Vertical") * Time.deltaTime; transform.Translate(0, 0, zt); /* Turn Left or Right... */ /* beware: MUST do float math! */ /* [default keys: a/d/left/right = “Horizontal” (x axis)] */ var turnAngle : float = turnSpeed * Input.GetAxis("Horizontal") * Time.deltaTime; /* Input.GetAxisRaw works also. */ transform.Rotate (0, turnAngle, 0); } /* Update( ) */


Here is a move_force script that allows your player to accelerate and twist.

With this script, friction is more of an issue, so I suggest adding a jump script (below) so that you can jump a little and turn in mid-air!

/* This is move with physics. Beware: turns easily on ice but doesn’t turn on other surfaces (unless you’re moving). */ var moveForce : float = 700.0; /* works in early tests */ var turnForce : float = 45.0; /* good to give the rigidbody an angular drag of 0.25 (default is 0.05) */ function FixedUpdate( ) { if (Input.GetKey ("up")) { rigidbody.AddRelativeForce (Vector3.forward * (moveForce * Time.deltaTime ) ); } if (Input.GetKey ("down")) { rigidbody.AddRelativeForce (Vector3(0, 0, -1) * (moveForce * Time.deltaTime ) ); } /* Hmmm, the physics material of a surface seems to really interfere with turning... I’ve turned first few ramps into icy and then turning is ok. Does torque effect wear out (friction slows a spin, i.e.?) */ if (Input.GetKey ("left")) { /* slide left: rigidbody.AddRelativeForce (Vector3.left * keyForce ); or: rigidbody.AddRelativeForce (Vector3.left * keyForce * Time.deltaTime ); */ rigidbody.AddRelativeTorque (0, -1.0 * turnForce * Time.deltaTime, 0); } if (Input.GetKey ("right")) { /* slide right: rigidbody.AddRelativeForce (Vector3.right * keyForce); or: rigidbody.AddRelativeForce (Vector3.right * keyForce * Time.deltaTime ); */ rigidbody.AddRelativeTorque (0, 1.0 * turnForce * Time.deltaTime, 0); } } /* end of FixedUpdate( ) */


This move/turn script works like pacman: looks and goes in the direction chosen, rather than having to turn before you move.

var moveSpeed: float = 25; function Update( ) { /* deal with up and down arrow*/ var zt = moveSpeed * Input.GetAxis("Vertical") * Time.deltaTime; if (zt > 0) { /* up the screen*/ transform.rotation = Quaternion.identity; transform.Rotate (0, 0, 0);/* the middle number is the important one*/ transform.Translate(0, 0, zt); /* move*/ } else if (zt < 0) { /* down the screen*/ transform.rotation = Quaternion.identity; transform.Rotate (0, 180, 0); /* note 180 instead of 0!*/ transform.Translate(0, 0, -zt); /* move, with negative!*/ } var xt = moveSpeed * Input.GetAxis("Horizontal") * Time.deltaTime; if (xt > 0) { /* up the screen*/ transform.rotation = Quaternion.identity; transform.Rotate (0, 90, 0);/* the middle number is the important one*/ transform.Translate(0, 0, xt); /* move*/ } else if (xt < 0) { /* down the screen*/ transform.rotation = Quaternion.identity; transform.Rotate (0, 270, 0); /* 270 instead of 90!*/ transform.Translate(0, 0, -xt); /* move*/ } } /* Update( ) */

Here’s a Jump Script...

Beware, not tested much

(Attach this script to your main character, not to the camera!)

var forceVal : float = 100.0; /* 10 wasn’t enough, */ var jumpHangTime = 1.0; var nextJumpTime = 0.0; function Update( ) { /* if (Input.GetKeyDown("x")){ // easier but lame */ if (Input.GetAxis ("Jump")) { /* print("x"); // for debug */ if (Time.time > nextJumpTime) { rigidbody.AddForce(0, forceVal, 0); print("jump"); nextJumpTime = Time.time + jumpHangTime; } /* if time legit */ } /* if input */ } /* Update */ /* is this getting called? Doesn’t seem to be happening */ function OnCollisionStay(collisionInfo : Collision) { if (Input.GetAxis ("Jump")) { /* rigidbody.AddForce(0, forceVal, 0); */ rigidbody.AddRelativeForce(0, forceVal, 0); /* Jump UP or jump away from self bottom? */ } /* if input */ } /* onCollisionStay( ) */

Camera following the target

You could merely parent the target onto the camera, but then the camera is glued to the target and tips over when the target tips over. Instead you could try adding a script to the camera that tells the camera to “follow” a target.

Here is a simple “follow” script that you could attach to the camera...

(And then tell the camera who to focus on, by dragging your main moving piece onto this script’s “target”.)

This camera stays in one place and swivels to look at the target. See other followers below.

/* Simple camera 1 that looks at the “whoToLookAt” target. */ var whoToLookAt : Transform; function LateUpdate( ) { /* Look at the target */ transform.LookAt( whoToLookAt ); } /* LateUpdate */


This camera tries to a fixed distance from the “whoToLookAt” target, and doesn’t turn when the target turns.

/* Simple camera 2 that stays near the “whoToLookAt” target. */ var whoToLookAt : Transform; var smoothTime : float = 0.3; private var yVelocity = 0.0; var distanceAbove: float = 3.0; var distanceAway = 5.0; function LateUpdate( ) { /* transform the camera so it is a distance away from target */ transform.position = whoToLookAt.position + Vector3(0, distanceAbove, -distanceAway); /* Look at the target */ transform.LookAt( whoToLookAt ); } /* LateUpdate */


This camera 3 is the fanciest and smoothest. It tries to stay behind the target, and slightly above it, and doesn’t tip onto its side if the target tips over.

/* A simple smooth follow camera, that follows the “whoToLookAt” target’s forward direction. From unity script reference (re SmoothDampAngle). */ var whoToLookAt : Transform; var smoothTime : float = 0.3; private var yVelocity = 0.0; var distanceAbove: float = 3.0; var distanceAway = 5.0; function LateUpdate( ) { /* Damp angle from current y-angle towards target y-angle */ var yAngle : float = Mathf.SmoothDampAngle( transform.eulerAngles.y, whoToLookAt.eulerAngles.y, yVelocity, smoothTime); /* Position at the target */ var newPosition : Vector3 = whoToLookAt.position; /* Then offset by distance behind the new angle */ newPosition += Quaternion.Euler(0, yAngle, 0) * Vector3(0, distanceAbove, -distanceAway); /* originally: newPosition += Quaternion.Euler(0, yAngle, 0) * Vector3 (0, 0, -distanceAway); */ transform.position = newPosition; /* move the camera */ transform.LookAt( whoToLookAt ); } /* LateUpdate */

Here is a GUI head-up display

(Attach this script to your main player, not to the camera! This puts buttons on the screen. One of the buttons lets you teleport your player to another place. (Make another cube that will be the other place for your main player. Put that other cube on the “otherPlace”.)

var otherPlace : Transform; function OnGUI( ) { GUI.Box(Rect(10, 0, 120, 30),"Hi There!"); /* Rect( HowFarFromLeftEdgeOfScreen=10, HowFarDownFromTop=0, Width=120, Height=30 */ if (GUI.Button(Rect(10, 70, 50, 25),"Go Home")) { /* Debug.Log("Clicked the button with text"); */ transform.position = otherPlace.position; /* go to otherPlace */ transform.Translate( Vector3(0,1,0) ); /* go a little above the spike */ transform.rotation = otherPlace.rotation; } /* end of button */ if (GUI.Button(Rect(10,100,85,25),"Block Start")) { /* Debug.Log("Clicked the button with text"); */ transform.position = Vector3(223, 120, 157); /* specific place */ transform.rotation = Quaternion.identity; /* be non-rotated */ } /* end of button */ } /* end of OnGUI( ) */

You have to assign this script to an object before you can drag targets onto it. We went crazy while inspecting an un-assigned script because the “target” field wouldn’t accept objects. Also, whatever you do, don’t name a script “GUI” because that is a reserved unity word and breaks the script.

Here are some helper functions to stop moving and spinning. You may add them to your head-up-display script.

function stopMoving( ) { this.rigidbody.velocity = Vector3(0,0,0); } /* end stopMoving( ) */ /* can stop part of the movement, e.g.: rigidbody.velocity.x = 0; */ function stopSpinning( ) { rigidbody.angularVelocity = Vector3(0,0,0); } /* end stopSpinning( ) */ /* Keeps whichever orientation you ended up with (might end up sideways or upside down). PS: "transform"s don’t have angularVelocity */ function standUp( ) { var myEuler = transform.rotation.eulerAngles; transform.rotation = Quaternion.Euler( Vector3(0, myEuler.y, 0) ); } /* end standUp( ) */ /* Stand up but keep pointed in current direction, like a surfer… keeps moving and spinning. Note: Rotations are stored as Quaternions by unity. The "eulerAngles" re-expresses the rotations as turnX, turnY, turnZ. Suppose my current rotation of eulerAngles is 30,45,22 ... To stand up but keep pointed in the same direction, I want to zero the first and third (30,45,22) but keep the 2nd (y) rotation: 0,45,0 Note: to put your orientation back to how you started (including the direction you faced at first) instead use: transform.rotation = Quaternion.identity; */

You can make these functions happen by saying their names in OnGUI( ). Example (inside OnGui( )):

if (GUI.Button( Rect(10,100,100,25),"Be flat")) { stopMoving( ); stopSpinning( ); standUp( ); } /* end of button */

PS: If you want keyboard commands that make these things happen, add the following to your hud script. You can add this to your move script, if you want, but then you also need to copy in the “standup( )” and “stopMoving( )” and “stopSpinning( )” functions from above.

function Update( ) {
/* Makes character stand up when "Fire1" key is pressed. 
"Fire1" is control key, usually, on mac. Check menu “Edit:Project Settings:Input” 
Fire2 key is stronger, stopping spinning and motion before standing up. */
   if (Input.GetAxis("Fire1")) { 
      standUp( );
   } else if (Input.GetAxis("Fire2")) { 
         /* option key, usually, on mac */
        stopMoving( );
        stopSpinning( );
        standUp( );
   } /* if input */
} /* end Update( ) */

Here’s a fancier version of the OnGui script that has a delayed command...

function OnGUI( ) { /* Left=10, Top=0, Width=120, Height=30 */ if (GUI.Button(Rect(10,120,75,25),"Pause then Home")) { waitSec( 1.2 /* how many seconds */ ); } /* end of button */ } /* end of OnGUI( ) */ function waitSec( X ) { print ("hi, at "+ Time.time + " waitSec starts to wait " + X + " seconds."); /* suspend execution for X seconds */ yield WaitForSeconds( X ); transform.position = Vector3(4.3, 0.63, 1.49); /* specific place */ transform.rotation = otherPlace.rotation; print ("At "+ Time.time + " waitSec is done waiting."); } /* end of waitSec( ) */

Note: the commands after “yield waitForSeconds( );” will be delayed, and the the “yield waitForSeconds( );” has to be in its own function, not in onGUI( )!

Here is score-keeper that reacts to “triggers” you hit, by raising your score and destroying the trigger.

(Attach this script to your main player. You can also attach a similar script to a trigger.)

(Note: Triggers are ordinary game objects with “[x]Is Trigger” turned on in their BoxCollider info. Triggers shouldn’t have rigid bodies since triggers don’t do physics. PS: you can easily hide triggers by turning their "Mesh Render" off, but I think the trigger is still active.)

var score = 0; function OnTriggerEnter( otherGuy : Collider ) { score++; Destroy( otherGuy.gameObject ); }/* OnTriggerEnter */ function OnGUI( ) { GUI.Box(Rect(10, 35, 120, 30),"Score:" + score); /* Rect( HowFarFromLeftEdgeOfScreen=10, HowFarDownFromTop=35, Width=120, Height=30 */ } /* OnGUI( ) */

You can use global scores by making a script that has “static” variables in it. (In our scripts, “static” means unique and global.) Suppose the script is called “scores.js” and looks like the following.
static var player1 = 0;
static var player2 = 0;

From any of your scripts you’ll be able to say things like scores.player2++ and if (scores.player2 > 17) { ...

Here is another score-keeper that reacts to “triggers:” to raise your score, raise your score more quickly, or increase your health.

(Attach this script to your main player)

(Note: This is the same as above, except you must use tags. If you copy this script exactly then your tags must be named the following (case sensitive): “coin”, “pinkcoin”, “apple”) To make a tag go to the ‘tag’ selector for any object and click the toggle menu that says ‘untagged.’ Choose ‘add tag.’ Find the tag section in the next inspector (click the arrow at the top next to tags). Then click a blank spot right below the last tag name at Element#. (See the picture.) adding a tag
Once you’ve added a tag, assign it to any game object that you want to be a coin, pinkcoin, or apple, using the same “tag:” toggle menu.
Also note: for this script to play a sound effect (when you get a ‘pinkcoin’ ) you must attach an audio source to your 3rd or 1st person controller, import an ‘.mp3’ or ‘.wav’ sound file into your project, and add the sound to the audio source (drag into ‘Audio Clip’). (Otherwise, the “GetComponent(AudioSource)” function won’t find anything.)
Get_coins_Demo_project.zip (92 Mbyte)

var score = 0; var health = 2; var someaudio : AudioSource; function Awake( ) { someaudio = GetComponent(AudioSource); } function OnTriggerEnter( otherGuy : Collider ) { if (otherGuy.transform.tag == "coin") { score++; Destroy( otherGuy.gameObject ); } else if (otherGuy.transform.tag == "pinkcoin") { score = score + 22; someaudio.Play(); Destroy( otherGuy.gameObject ); } else if (otherGuy.transform.tag == "apple" ) { health = 3 + health; Destroy ( otherGuy.gameObject ); } } function OnGUI( ) { GUI.Box(Rect(10, 35, 120, 30),"Score: " + score); GUI.Box(Rect(130, 35, 120, 30), "Health: " + health); }

Thanks to Matthew P. for this article.

How to be dead when you fall off the world...

(Attach this script to your main player)

var lives: int = 3;

function Update( ) {
    /* If you’ve 100 below the world... */
    if (this.transform.position.y < -100) {
        lives--;
        if (lives < 1) {
            Debug.Log("You’ve used up all your lives!");
            /* Application.LoadLevel( "dork" ); /* untested */
            /* Note: create levels using File:Build Settings (Add Current) */
            /* which turns current scene into a named level */
            /* Thanks to Angus J. for the tip! */
        } /* end if run out of lives */
        this.transform.position = Vector3( 200, -4, -13);
        this.rigidbody.velocity = Vector3( 0,0,0);
        /* rotation wants to turn off too */
    } /* end if below the world */
}/* Update( ) */


function OnGUI( ) {
    GUI.Box(Rect(10, 60, 120, 30),"Lives:" + lives);
    /* Rect( HowFarFromLeftEdgeOfScreen=10, HowFarDownFromTop=70, Width=120, Height=30 */
} /* OnGUI( ) */

Mouse Clicks

Good news: our gameObjects (cubes, spheres, etc) can easily respond to mouseClicks that cause things to happen. Merely attach a script like this to the sphere or cube or whatever. (Note: there are some nifty scripts in unity3D’s scripting folder that you can also try.)

function OnMouseDown( ) { Debug.Log( "You clicked me!" ); this.renderer.material.color = Color.red; this.transform.Rotate(Vector3( 45, 0 , 0)); this.transform.localScale.x = 0.75 * this.transform.localScale.x; this.transform.localScale = Vector3( 0.8, 0.75, 2); /* if the thing you click has rigidbody then you could make it start spinning or moving: this.rigidbody.AddRelativeTorque (4, 10, 0); */ /* We can control other objects! suppose there is another cube called “cube2”: */ var othercube = GameObject.Find("cube2"); othercube.renderer.material.color = Color.yellow; /* othercube.transform.Translate(0, 1, 0); */ }

Hide and Show Objects

(from http://answers.unity3d.com/questions/14165/show-and-hide-a-prefab-or-gameobject.html)
this script could be put onto multiple objects, and they’ll all disappear when you press the ‘Z’ key, and will reappear when you press the ‘X’ key.

function Update( ) { if (Input.GetKeyDown(KeyCode.Z)) { this.renderer.enabled = true; /* show */ } if (Input.GetKeyDown(KeyCode.X)) { this.renderer.enabled = false; /* hide */ } } /* Update */

Here’s a fancier version, for hiding all the children of an object that is a parent. The script uses a “for…” loop and uses the “!” symbol (which means “NOT” in the C, Java, Javascript family of languages).

function Update( ) { if (Input.GetKeyDown(KeyCode.Z)) { ToggleVisibility(); } } /* Update */ function ToggleVisibility() { /* toggles the visibility of this gameobject and all its children */ var myRenderers = gameObject.GetComponentsInChildren.( ); for (var r : Renderer in myRenderers) { r.enabled = !r.enabled; } } /* ToggleVisibility */

Finding all the gameObjects that have a particular tag.

Gus B. found the following in the scripting manual under GameObject.FindGameObjectsWithTag("enemy");, which has the following example

function findClosestEnemy( ) { var gos : GameObject[]; gos = GameObject.FindGameObjectsWithTag("Enemy"); var closest : GameObject; var distance = Mathf.Infinity; var position = transform.position; /* Iterate through them and find the closest one */ for (var go : GameObject in gos) { var diff = (go.transform.position - position); var curDistance = diff.sqrMagnitude; if (curDistance < distance) { closest = go; distance = curDistance; } } }

Hit Trigger and Light Changes Color!

Put this script on your main character and run into tagged triggers. (See how to make tags, above.)

var score : float = 0; /* Tagged triggers change the color of the “myGlow” light called “myGlow” */ function OnTriggerEnter( otherGuy : Collider ) { if (otherGuy.transform.tag == "colorizerGreen") { var theLight = GameObject.Find("myGlow"); theLight.light.color = Color.green; /* Note: if “myGlow” is a child (parented) then we can say transform.Find("myGlow").light.color = Color.green; */ } score++; if (otherGuy.transform.tag == "coin") { Destroy( otherGuy.gameObject ); } }/* OnTriggerEnter */

Rotating Children

Suppose you want to rotate the turret of a military tank and have the muzzle swing too. If the tank or turret have been stretched then the rotation will be crazy. Simple fix: make an empty game object that is the parent, and rotate it (with the tank and muzzle and turret all children of it). If the muzzle swings up and down, then it may need to have an empty game object parent, too.

If you’re building a game object from unity cubes and cylinders, you probably want to move the pieces to 0,0,0 before assembling them! Easiest way to get them back to some special place: put a named cube at that place, then focus the editor screen on that place, then select the far-away assembly and use menu “move to view.”

Missiles

AKA How to throw basketballs (if you’re less-violent)

This script gets installed onto the shooter. You must have a prefab in the hierarchy named “bullet” or you can drag a different prefab onto the script if you want.

#pragma strict var bullet : GameObject; var speed = 30.0; /* 30 works with bullet mass:0.01, angular drag: 0.001 Use trial and error to find good number(s). */ /* Update happens frequently, ctrl or mouse cause FireBullet( ) */ function Update( ) { if (Input.GetButtonDown("Fire1")) { FireBullet(); } } /* end of Update( ) */ function FireBullet( ) { if (bullet == null) { bullet = GameObject.Find("bullet"); if (bullet == null) { Debug.Log("Darn, I can't find a GameObject named “bullet”"); return; } } /* First, make a new bullet at shooter’s position & rotation... */ var bulletClone : GameObject = Instantiate(bullet, transform.position, transform.rotation); /* Now move the bullet slightly ahead of the launcher. Depending how your shooter is built, you might need to translate on x or y or z. For the third person controller I had to use (0,-1,0) but for a cylinder I had to use (0,2,0). The axes on the gameobject have color Red,Green,Blue in order X,Y,Z */ bulletClone.transform.Translate( Vector3(0,-1,0) ); /* in the Y direction */ /* Now give the bullet’s rigidbody some speed. For the third person controller I had to use negative speed. */ bulletClone.rigidbody.AddRelativeForce(0, -speed, 0); Destroy(bulletClone, 2.0 /* seconds of lifetime */ ); /* You can also acccess other components & scripts of the clone: */ /* bulletClone.GetComponent(MyBulletScript).DoSomething(); */ } /* end of FireBullet( ) */

But what happens if the projectile hits something? You can put the following script onto the bullet prefab and onto other things that get damaged by colliding with anything. See explode for fancier explosion. */

function OnCollisionEnter(collisionInfo : Collision) { /* see unity script manual re “Collider.OnCollisionEnter” for grenade example */ /* explode( ); */ Destroy( /* me! */ gameObject); }

Older, crazier idea, before I knew about OnCollisionEnter( ): I’ve got a working system in which bullet prefabs carry the following “Hah hah I Hit You” script, or see “explode” script below. The targets have rigidbody and also are parent to an invisible trigger which surrounds them like clothes. (Triggers can’t be rigidbody, and you can make things invisible by turning off their “[ ]Mesh Renderer”.)

function OnTriggerEnter( otherGuy : Collider ) { /* global score++; */ if (otherGuy.transform.tag == "ai") { var aiSpawn : GameObject = GameObject.Find("aiSpawnPlace"); /* I assume there’s only one aiSpawnPlace */ var ai : Transform = otherGuy.transform.parent; if (ai == null) { /* has no parent, so just hide */ otherGuy.renderer.enabled = false; } else { ai.transform.position = aiSpawn.transform.position; ai.rigidbody.velocity = Vector3( 0,0,0); } } else { Destroy( otherGuy.gameObject ); } }/* OnTriggerEnter */

splitscreen.png

2 Cameras Sharing the Screen

Here’s how, (thanks, Mars!):

gui map

Easy GUI Map with 2 Cameras and a Custom Layer

First, make a second camera using the first two steps in the tip above this one. (Create a second camera and turn off its audio listener.)

AI characters chase characters

Put the following script onto a character to make the character chase somebody else.

#pragma strict var target : Transform; /* the enemy’s target */ var moveSpeed = 3; /* move speed */ var rotationSpeed = 3; /* speed of turning */ function Start( ) { /* hmmm, the following is unnecessary if target has been assigned by dragging in the editor... Note: this looks for TAG “Player”, not name! If you want to search by name, use target = GameObject.Find("Player"); */ if (target == null) { target = GameObject.FindWithTag("Player").transform; /* target the player */ } } function Update( ) { /* rotate to look at the player */ /* Note: the manual for Quaternion.LookRotation says “Most of the time you can instead use: transform.LookAt( );” */ var relativePos : Vector3 = target.position - transform.position; var turnMe : Quaternion = Quaternion.LookRotation(relativePos); transform.rotation = Quaternion.Slerp( transform.rotation, turnMe , rotationSpeed*Time.deltaTime); /* move towards the player (If ai has rigid body then ai moves along the ground. Without rigidbody, the ai flies.) */ var howMuchToMove: Vector3 = transform.forward * moveSpeed * Time.deltaTime; transform.position = transform.position + howMuchToMove; }

Gravity not just down!

Unity has gravity that goes straight down, but thanks to Gus B, here’s a script for gravity between objects. This script gets installed onto the mover(s), which should have rigid body and have gravity turned off in inspector (or else unity’s gravity down the screen will take over).

#pragma strict var target : GameObject; /* = GameObject.Find("planet"); */ var gravity : float = 5000.0; /* adjust this until we’re happy */ function Update( ) { var vectorToward : Vector3 = transform.position - target.transform.position; var sqrLen = vectorToward.sqrMagnitude; rigidbody.AddForce( vectorToward.normalized * (( gravity * rigidbody.mass * target.rigidbody.mass ) / sqrLen) ); /* Note: using the mass of both bodies! */ /* We were using addRelativeForce but it moves in direction of object’s coord sys */ }

ps: It is better to check whether the target exists. You can use code like the following at the top of Update( ):

if (target == null) { target = GameObject.Find("planet"); if (target == null) { Debug.Log("Darn, can’t find “planet” for target. Can you make one?"); return; } }

Explosions

The following script can go onto things that explode. The object will explode if it hits anything solid, and can also have a timer so it explodes after some number of seconds if it hasn’t already hit something. (Here’s how.) Be careful that the armed bomb doesn’t touch the launcher! Some student are thinking about having a “safe timer” also, so it isn’t dangerous at first.

var shrapName = "cubeShrapnel"; var shrap : GameObject; /* if user doesn’t specify, we’ll use “cubeShrapnel” by default */ var speed : double = 10.0; var howManyShrapnelPieces = 5; var shrapnelLifeTime = 2; /* seconds */ var alreadyExploded : boolean = false; function OnCollisionEnter(collisionInfo : Collision) { /* see unity script manual re “Collider.OnCollisionEnter” for grenade example */ explode( ); Destroy( /* me! */ gameObject); /* trying to prevent multiple explosions */ } function setExplodeTimer( X ) { /* suspend execution for X seconds */ yield WaitForSeconds( X ); explode( ); Destroy( gameObject ); /* note "Destroy(this)" merely means kill this script! */ } /* end of setExplodeTimer( ) */ function explode( ) { if (alreadyExploded) { Debug.Log("I’m already exploded, can’t again!"); } else { alreadyExploded = true; Destroy( gameObject ); } if (shrap == null) { shrap = GameObject.Find(shrapName); /* Would be better to use some kind of load asset. Currently the prefab has to have an instance on the hierarchy, so I end up with stray missiles and shrapnel hanging around. */ if (shrap == null) { Debug.Log("Darn, can’t find “" + shrapName + "” game object!"); return; } } Destroy( /* this rocket’s */ rigidbody ); /* so shrapnel doesn’t bump into rocket? */ var shrapClone : GameObject; /* gonna build a bunch of these in loop */ var randomRotation : Quaternion = transform.rotation; /* will be diff for each shrap */ for (var fire = 0.0; fire < howManyShrapnelPieces ; fire++){ /* calculate a random rotation by rotating euler.z degrees around the z axis, euler.x degrees around the x axis, and euler.y degrees around the y axis (in that order). */ var rotateOnXAxis = 50.0 * fire * Random.Range(0.0,1.0); /* degrees */ var rotateOnYAxis = 50.0 * fire * Random.Range(0.0,1.0); var rotateOnZAxis = 50.0 * fire * Random.Range(0.0,1.0); /* Assign the rotation */ randomRotation.eulerAngles = Vector3(rotateOnXAxis, rotateOnYAxis /* degrees */, rotateOnZAxis); shrapClone = Instantiate(shrap, transform.position, randomRotation ); if (shrapClone == null) { Debug.Log("Darn, shrapClone is null!!!"); return; } var shrapCloneRigid : Rigidbody = shrapClone.rigidbody; if (shrapCloneRigid == null) { Debug.Log("Darn, shrapCloneRigid is null!!!"); } /* blast away */ shrapCloneRigid.AddRelativeForce(speed, speed, 0.0 ); Destroy( shrapClone, shrapnelLifeTime /* seconds */ ); /* alternative: Destroy( shrapClone, shrapnelLifeTime * Random.Range(0.0,2.0) ); */ } Destroy (gameObject ); } /* explode( ); */

Timer

Here’s how to set the timer in the script of whoever launches the rocket or bomb. Note: this assumes the explode script is called exactly “explode.js”.

var otherScript = rocketClone.GetComponent(explode); if (otherScript == null ) { print ("dang, didn’t find rocketExplode script"); return; } else { otherScript.setExplodeTimer( 2 /* seconds */); }

Using Sketchup Models

Sending Sketchup Models to Unity (instructions from Asher, 2013 April):

  1. In Sketchup: Export as Collada DAE.
  2. Be sure the “[x]Two Sided Faces” is clicked on!
  3. In Unity: drag the DAE file onto assets window.
  4. In the component inspector window for the new asset, look at Meshes and click “[x]Generate Colliders”!
  5. Might have to change Rigidbody of your player to Interpolate:(Extrapolate) OR Collision:(Continuous) or maybe even Collision:(Continuous Dynamic)!

Notes, miscellaneous

Leaving trails: the "Trail Renderer" can have various colors. Teddy figured out that to change the color you have to make a material and apply it to the trail renderer.