Almost everything you can do with the graphical editor you can do with scripts in C#. It's not always obvious how to do it, but a combination of reading Unity Documentation and searching in community forums will usually turn up some examples.
GameObject>3D Object>Cube
or right-click in the window)Add Component
and type MyTestScript
then click New Script
and click Create and Add
(you should now see that script attached to your Cube in the Inspector and appear in your Project window)MyTestScript
file - this should open a text editor (by default it is Monodevelop
but you can change it in the menu Edit>Preferences>External Tools
, though you may want to make sure you can get C# code completion in your favorite editor before changing it since it's one of the fastest ways to learn)In C#, functions take the following form:
<optional-scope> <return-type> <FunctionName>(<optional-args>){
// some awesome stuff
return <return type>; // if the return-type is not void
}
In practice, that looks like:
public float MultByOnePointSeven(int n){
return n * 1.7f;
}
By default, scripts extend the Monobehaviour
class which gives you a number of useful functions (<optional-scope> class <classname> {}
is how classes are declared in C# and :
is used after the classname to inherit from a parent class). We can build an understanding of those functions by observing their behavior in the Console.
// Use this for initialization
void Start(){
Debug.Log("MyTestScript>Start");
}
// Update is called once per frame
void Update(){
Debug.Log("MyTestScript>Update");
}
Now, switch back to the editor and hit play. If you Console tab is visible, you should see one message from Start
and hundreds from Update
. When you are getting a lot of repeat messages, you can collapse them into a single message by toggling Collapse
on the Console tab.
To get a sense of how Update
can be used, lets introduce a counter variable. Declare a simple counter variable:
float myVariable = 0;
Modify function to increment myVariable
and the Log statement to display the counter variable (it is possible to use +
to concatenate string values in C# but better form to use string.Format
)
void Update(){
myVariable += 1;
Debug.Log(string.Format("MyTestScript>Update myVariable: {0}", myVariable));
}
The complete list of functions available to Monobehaviours is available in the documentation but here's a few more you may see:
Awake is for things that should happen when a script is first loaded but do not need to be run every time it is enabled. Try adding an Awake function to your test script with its own Debug statement. In the editor, click run, then in the Inspector window, click the checkbox to disable and re-enable your object. Observe when the different functions execute.
Like Update
but it runs every so many milliseconds rather than every frame. This can be important if you are trying to do realistic physics simulations.
These functions are both used for collision detection. (we'll use this a little later).
This function is used for post-processing (we'll use this a little later).
One of the features of C# as a language is that you can you 'attributes' to provide metadata about your functions using square bracket notation. Unity leverages this to provide paths for users to customize the editor in several different ways. Here are a couple that come in handy and will give you a sense how to interpret this kind of code when you see it. The full list of function attributes is listed in the Unity Documentation: Attributes
Expose a variable to be changed in the editor.
[SerializableField]
float myVariable = 0;
Before this syntax, the easiest way to expose variables in the editor was to make them public
. A lot of us got in a bad habit of doing that, but you should probably make them public only if you intend for other scripts to access them. In general, this looks like myGameObject.GetComponent<SomeScriptName>().FunctionToRun()
Sometimes when you write a script, you want it to control other Components attached to the GameObject. This attribute will tell the compiler to throw an error if the Component isn't there as expected. This keeps you from writing if (ThingIsAttached) {} else {}
type statements.
[RequireComponent(typeof(Rigidbody))]
public class DoSomethingAwesome(){
// awesome stuff with rigid body
}
The standard method of setting up user controls is to use the InputManager found via Edit > Project Settings > Input
, however if you want to set up some controls just for testing, writing yourself some keyboard shortcuts is a great way to do it.
To trigger actions from the keyboard, create an Empty GameObject and name it KeyboardManager
. Then create a new script called MyKeyboardController and attach it to the KeyboardManager. In the Update
function, add a simple check and a debug statement.
if (Input.GetKeyDown (KeyCode.A)) {
Debug.Log ("KeyDown A");
}
You should see log statements in your Console whenever you press a
on the keyboard
Input.GetKeyUp
and Input.GetKey
- how to their behaviors differ?Let's try something more useful - how about something that fades to black when you hit spacebar? A nice fade is especially useful for VR applications since hard cuts between views can be jarring to users.
In the assets folder, look for a prefab (that's the blue cube symbol) and drag it into the scene. Position it so that your camera is in the center of the cube. In your keyboard script, create a GameObject variable with a SerializeField decorator called fadeCube
, then return to the editor.
// in MyKeyboardController.cs
[SerializeField]
GameObject fadeCube;
If you don't immediately see a GameObject slot appear in the inspector window with your script, hit Play (Ctrl+P) and it should force the script to reload. When you see it, drag your fadeCube prefab onto it. Now you've got a variable in your script that points to a object in the scene.
In the Hierarchy view, click on the FadeCube and examine it in the Inspector. You should see a script Component attached to it called AlphaFader.cs
. Double-click on that to load it in a text editor. You should see the familiar Start()
and Update()
functions along with OnRenderImage()
and some public functions. Since they are public, they can be called from other contexts.
To trigger a fade from MyKeyboardController
, we'll use the reference that we made to fadeCube
and call GetComponent
to look up its script, AlphaFader
. Once we have a reference to the script, we can call any of its public functions. If your editor has code suggestions, you should see StartFadeOut()
and StartFadeIn()
appear as options when you type .
after the script object.
fadeCube.GetComponent<AlphaFader>().StartFadeOut ();
The <
and >
surrounding AlphaFader
indicate the type of component we are asking the fadeCube GameComponent for. If you didn't specify the type, Unity wouldn't know what functions it has available.
StartFadeOut
to a key of your choice and test itStartFadeIn
Before we move on, let's add one more keyboard shortcut. This time, we'll take the sword we painstakingly imported before and make it easy for us to pick it up.
awesomeSword
variable to your MyKeyboardController
script and connect the sword instance in the Hierarchy to the script variable in the inspectorIf you need a hint, the inside of your function will probably look something like this:sword.transform.position = new Vector3 (3.2f, 1.5f, 1.0f);
Once you've got the sword magically flying to your 'hands' at will:
sword.transform.parent = mainCamera.transform;
... but how can we figure out the Camera's position?)