Head First into Unity with UnityScript

Written by Tonio Loewald (a.k.a. podperson)

Also see this article which outlines the technical differences: UnityScript_versus_JavaScript (it's a helpful article, but in places outdated or wrong).

"Note: this tutorial assumes you know the basics of JavaScript and programming. We're not going to go over all that stuff from scratch. If you don't know anything at all about programming, well ... you should probably get a book oriented at learning to program (DON'T learn JavaScript expecting it to help you program in UnityScript — it's more of a cross between JavaScript and Java or C#. Indeed, if you don't want to learn JavaScript you're probably better off learning C#), or take a class (or perhaps check this thread). The fundamentals of programming are a major topic in and of themselves."

Use #pragma strict
It's a good habit to get into and required for iOS development. #pragma strict will enforce stricter type checking, generate more useful error messages sooner, and will encourage good programming habits.

Use enum
This is a much more economical and less error-prone method than using strings.

It's different
Although Unity's JavaScript tries to be like the ECMAScript standard at least somewhat, it varies in many ways from other implementations of JavaScript that are based on the same standard. It is perhaps most similar to Microsoft's JScript, especially in that both are .NET languages. However, Unity's version was developed independently and there are a number of differences between the two.

It's fast
Unity JavaScript is compiled (and fast, which is excellent) but not so dynamic as JavaScript in browsers (which is interpreted).

Seriously, there is no speed difference between JavaScript, C#, and Boo (in Unity, that is). There are other pros and cons to each, but not speed.

Note: if you've been following recent developments in the browser wars you'll know that it's not strictly true that browser JavaScript is interpreted. JavaScript is in fact JIT compiled on all modern browsers, and rather impressively fast on some (FireFox, Safari, and Opera). Even so, it doesn't support strict typing (even as an option) which is very costly for performance (every time you perform arithmetic operations you need to check what your operands are and convert them if necessary). If the ECMAScript standard is modified (as Adobe has lobbied for) to allow for explicit type declarations, it's possible that appropriately written JavaScript will be able to execute an order of magnitude faster.

Even so, as things stand, "real" JavaScript is still about two orders of magnitude slower than Unity's UnityScript, even on Squirrelfish Extreme.

The var keyword is required
In JavaScript, if you don't use the var keyword when defining a variable, that variable is scoped as a global one.

To avoid this ambiguity for long-time JS users, the var keyword is required when defining variables, and that automatically restricts the variable's scope to the current scope.

UnityScript is classical, not prototypal
There's no messing around with .prototype in UnityScript. To make a class, you simply do this:

The compiler essentially adds some padding code to this (to make it a class definition) before it gets compiled. It effectively becomes something like:

Note the name of the class comes from the name of the file.

Here's a subclass:

Virtual functions can be used to override functions
In Unity's javascript you can create virtual functions.

If you want to call the parent class's method then you can use the keyword super. We could get SubFoo to call the function in Foo by writing:

Consider Writing Mixins and Helpers Instead of Subclassing
It's very easy to write classes that know about one another and cooperate, and this is probably a better and more maintainable way of specializing objects in Unity than subclassing.

E.g.

It's String (Mono's String class) and not string
var x : String;

Most of the string functionality you know and love from JavaScript is still there, but it's differently capitalized.

A note on how to "Split" Strings

You have to use the following syntax for splitting with characters : name[1] will contain "myInt" after the split.

For a list of available string functions, see Mono's documentation on the String class (http://go-mono.com/docs/monodoc.ashx?link=T%3aSystem.String%2f*)

You Must Declare Variables Before Using Them
You must declare variables before using them.

a) You can (and often should) explicitly scope variables as private, public, etc. If you leave out the scope, public is the default.

b) Unity will implicitly type a variable if you assign it a value when you declare it. So:

But:

Method (and Class) Names are Generally Capitalized
Method (and class) names are generally capitalized, except when they aren't. (It's confusing.) Basically, Unity's JavaScript is living in a .NET naming convention world (where methods are CamelCase and properties are camelCase), but is also trying to be like JavaScript (which, like C, is strongly biased towards lowercase and camelCase for everything).

e.g. in JavaScript typeof("fred") == 'string', but in Unity the type you write var a: String;

Lots More Types, Two Kinds of Array, No Object Syntax Sugar
JavaScript has, in essence, three types: number, string, and Object (with functions and arrays in essence being Objects). Unity's JavaScript has many more types, including:

Objects, which are NOT interchangeable with arrays, or Arrays (which are somewhat like JavaScript's objects, but not dynamic):

native arrays (which are not associative or dynamic):

If you want to make an array of a specific type:

UnityScript Arrays (which are associative and dynamic):

You can convert UnityScript Arrays to native arrays (which are faster but less flexible) using ToBuiltIn(ArrayType), e.g.:

Integer types (including int, uint32, etc.):

Unity supports a large number of special case variations of the integer type. In general you'll know if you need them and don't need to worry otherwise.

Unity has many built-in classes (e.g. Vector3):

You'll become familiar with these as you work with Unity, in much the same way you become familiar with the DOM classes as you work with browsers. (Except Unity's classes suck much less than the DOM.)

One of the things that makes Unity a lot of fun to work with is that it uses a very liberal "mixin" strategy for classes. Usually you can "get at" the classes you need very quickly and easily. The most common example is the Transform class which quickly gets you to any associated class that's "attached" to the same object you're dealing with very quickly and easily.

E.g. in a typical behavior you'll have access to a variable named "transform" (referring to the instance of Transform associated with the object to which the behavior is attached). If you need the associated position (a Vector3) it's transform.position; if you need its GameObject it's transform.gameObject. If you need its renderer, it's transform.renderer. And so on. Generally, in Unity if you have one of an object's major properties you can quickly get at all its others.

a) Unity's String class lacks many of the nicer features of JavaScript's strings.

b) Unity's internal arrays are far less flexible than JavaScript's arrays or objects. However, various collection types such as List, Dictionary, Queue and so on are available. Internal arrays always have the advantage of the best speed.

Each .js File Implements A Class (By Default)
In general, sticking a bunch of variable and function definitions such as:

and saving it in Foo.js Is exactly equivalent to putting something like this in the same file:

But, you can also declare more than one class in the same file, which is particularly useful where you need utility classes which aren't descended from MonoBehaviour.

e.g.

If you do something like declare a subclass of MonoBehaviour in a file with a mismatched name (including different capitalization) you're asking for trouble.

It's important to understand that when you write a behavior script in JavaScript you are actually writing a class implementation, where:

a) The name of the class is the name of the script file (so if it's foo.js you can instance it elsewhere by saying var x = new foo).

b) Certain "magic" method names will in fact implement event handlers (e.g. Start, FixedUpdate etc.). In any event, a function declaration is a method of the class you've written.

c) Code written outside function definitions inside your file are executing in the class's body. Variables declared in it are members of the class.

d) static functions and variables in a class are, in essence, class functions and variables.

This is all FAR more elegant than implementing classes in "real" JavaScript, but also somewhat restrictive ... mostly in a good way (you can't arbitrarily wire objects together the way you can in "real" JavaScript).

For example, if I create a new behavior and name it foo, the file will be named foo.js. Let's suppose foo.js looks like this:

Calling Inherited Methods

super is the inherited constructor, and super is "this" treated as a member of the superclass (so super.foo calls the superclass's version of foo).

Semicolons Are Not Optional
Semicolons are generally optional in JavaScript (which has some ferocious logic to determine when a statement ends) but very much not optional in Unity.

Math is Mathf; Math.abs is Mathf.Abs
JavaScript's annoying Math library (because, really, stuff like abs should just be in the language) becomes Unity's (also annoying) Mathf library. And remember, method names are usually capitalized (in Unity) so Math.abs becomes Mathf.Abs.

Using Mono (.NET)
The UnityScript runtime environment makes extensive use of Mono (the open source clone of .NET). In fact, UnityScript is implemented in Boo, which is a language that runs on the Mono virtual machine and compiles to its native code. Many of a typical JavaScript runtime environment (e.g. String and Math libraries) are provided by Mono. You can tell when you're using Mono classes because their capitalization convention is CamelCase for class names (e.g. String) and methods (e.g. Mathf.Sin) but camelCase for properties vs. JavaScript's which is camelCase for everything.

In order to use the Mono libraries it's most convenient to import them, e.g.

Otherwise you need to specify the full namespace when calling functions, e.g. System.IO.File.Open instead of just File.Open. To find documentation on the libraries, the best place is probably http://msdn.microsoft.com/en-us/library/w0x726c2(v=VS.90).aspx The Mono documentation (http://docs.go-mono.com/) is technically more accurate for what's included with Unity, but is fairly incomplete at this time.

Mono Types
When a Mono function requires a char as an input, you can obtain one by simply indexing a string. E.g. if you wanted to pass the lowercase a as a char, you'd write:

E.g. when using the String.Replace function, you would use:

When working with Javascript Arrays (which are more flexible than builtins) you can easily convert them to the faster builtin arrays using ToBuiltIn(Type):

UnityScript has access to generics (like in C#), so when using dynamically-sized arrays, you're better off using List instead of Javascript arrays. There's essentially no reason to use Javascript Arrays; Lists are faster and more functional in all cases. If you need an array of mixed types, you can use a List of Object, and then cast Object to the appropriate type when retrieving values. The syntax for generics in UnityScript is nearly identical to C#, except for an extra "." before the <> part. For example, "var myList = new List ;" in C# would become "var myList = new List. ;" in UnityScript.

Using 3rd Party .NET Libraries
3rd Party .NET libraries (e.g. XML-RPC.net) can be used by importing the .dll file as a new asset.

Debugging
Scripting errors will show in Unity as a "red x icon" in the window status bar. Click on the icon to bring up the console, showing a list of errors, which should be both informative and lead you to the line in the script that caused the problem.

Unity also generates useful warnings (with a "yellow ! icon") e.g. telling you a variable you've declared isn't used anywhere. Striving to write code that never generates warnings is a very useful habit.

The print function will produce messages in the status bar and console, but only in MonoBehaviour classes. It's better to use Debug.Log("insert message here");. This does the same thing as print, but everywhere. You can also use Debug.LogWarning and Debug.LogError to generate your own warning and error messages.

Debug.Break; pauses the game in the editor at that exact point. It's very useful if you want to examine the state of objects when a particular situation occurs (e.g. you're trying to figure out what's going wrong when a particular object collides with another).

The editing GUI is completely live when running projects in the development environment (e.g. instances created at runtime appear in the browsers and you can click on them and look at their internal state).