3iX

Reliable $1 Web Hosting by 3iX

Tuesday, November 23, 2010

Unity3D - Syntax Differences in C# and Javascript

 

Unity3D - Syntax Differences in C# and Javascript

 

The purpose of this answer is to provide a single point of reference for the syntactical differences between C# and JS. It is mainly for people who have already made their decision as to which language to use, and might need to know the differences (for instance, to translate a script from one language to another).

 

Unity Script Directives

Unity has a number of Script Directives, for example, AddComponentMenu.

The syntax is:

// Javascript example
@script
AddComponentMenu ("Transform/Follow Transform")
class FollowTransform extends MonoBehaviour {
}  

// C# example:
[AddComponentMenu("Transform/Follow Transform")]
class FollowTransform : MonoBehaviour {
}

Type names

A couple of the basic types are spelt differently in pure Unity C#:

  • C#: bool, Javascript: boolean
  • C#: string, Javascript: String
However, if you include System in your C# script, you can also use .NET's String and Boolean class (note the upper-case):
using System;
String foo = "testing";
Boolean bar = false;

Variable declaration

Variable declaration is different, including access and type specification:

// C#: the type is always stated when declaring a variable:

public int myPublicInt = 1;      // a public var

int myPrivateInt = 2;            // **private** access is default, if access is unspecified

public GameObject myObj;         // a type is specified, but no value assigned

// Javascript - type specification is not necessary:

var myPublicInt = 1;             // **public** access is default, if unspecified

private var myPrivateInt = 2;    // a private var

var myObj : GameObject;          // a type is specified, but no value assigned (see below)



Variables with dynamic type resolution

In Javascript only, variables can have an unspecified type. This only occurs if you do not assign a value while declaring the variable. For example:

// Javascript:

var numBullets : int;  // statically typed (because type specified)

var numLivesLeft = 3;  // statically typed (because type is inferred from value assigned)

var player;            // dynamically typed (because neither a type or value is specified)

Performance is slower with dynamically typed variables, and you can run into casting problems.


Multi-dimensional array declaration not supported

Unity's Javascript doesn't support the syntax for declaring multi-dimensional built-in arrays. Eg:

// C#:

int[,] = new int[16,16];  // 16x16 2d int array

// Javascript:

// not possible!

You can of course nest arrays in Javascript, creating what is called a "jagged array", however - strangely enough - it's also possible to work with built-in 2d arrays in Javascript, providing 2d array originates from somewhere other than being explicitly declared in in your script. This means you can use a C# helper script, like this one on the wiki to declare 2D arrays, which you can then use in Javascript.

Character literals not supported

Unity's Javascript seems to be missing the syntax to declare character literals. This means you need to get them implicitly by referencing a character index from a string. For example:

// C#

char myChar = 'a';

// Javascript:

var myChar = "a"[0];  // implicitly retrieves the first character of the string "a"



Class declarations

You can define classes in Javascript, in a similar way to C#. Here's an example of a class which inherits from MonoBehaviour // Javascript example

class MyClass extends MonoBehaviour {

    var myVar = 1;

    function Start() {

Debug.Log("hello world!");

}

}  

// C# example:

class MyClass : MonoBehaviour {

    public int myVar = 1;

    void Start() {

Debug.Log("hello world!");

}

}

However in Javascript, if you're inheriting from MonoBehaviour, you don't need to write a class body at all (see the next section).

You can also write classes which do not inherit from anything, however you can't place scripts like this on Game Objects - you have to instantiate them with the 'new' keyword:

// Javascript example

class MyClass {

    var myVar = 1;

    // constructor:

public function MyClass() {

Debug.Log("hello world!");

}

}  

// C# example:

class MyClass{

    public int myVar = 1;

    // constructor:

public MyClass() {

Debug.Log("hello world!");

}

}

If you are inheriting from MonoBehaviour, you should not use constructors or destructors. Instead, use the Event handler functions "Start", "Awake" and "OnEnabled".

 


Implicit Class declarations

Unity's Javascript has a feature whereby if you do not declare any class body, it is automatically implemented for you. For example, a script which contains only variables and functions (and no explicit class declaration) is automatically implemented as:

// Your javascript is converted to (approximately)

class TheScriptName extends MonoBehaviour {

... your script here

}

This means that any Javascript script that you write without an explicit class body, automatically inherits from MonoBehaviour, and is therefore a component which can be attached to a GameObject (which is usually what you want!).


Limited interface support

While Unity's Javascript does support inheritance and interfaces, it has the very limiting caveat that you can either inherit your class from an existing class, or declare one interface. Eg:

// C#

class Apple : MonoBehaviour, ICollectable, IEatable, IThrowable { ... }

// Javascript - only one allowed:

class Apple extends CollectableObject { ... }

// or

class Apple extends IThrowable { ... }


Generics

The C# syntax supports "Generics" which allows you to use classes and methods which do not specifically declare a type. Instead, the type is passed as a parameter when calling the method or instantiating the class at runtime. These now work in both Unity and Unity iPhone (since v1.6).

.Net comes with some useful Generic classes such as the List and Dictionary, and Unity's own API has some generic functions which remove the need for some of the verbose casting which would otherwise be necessary in C#. For example:

// In Javascript, the "GetComponent" function returns an object, which is automatically cast by Javascript to the correct type

var someScript : ExampleScript = GetComponent(ExampleScript);

// In C#, without the Generic version of "GetComponent" we'd have to cast it ourselves (yuck):

ExampleScript someScript = (ExampleScript) GetComponent(typeof(ExampleScript));

// But instead, we can use the generic version provided by the Unity API, like this:

ExampleScript someScript = GetComponent<ExampleScript>();

For a more complete definition of Generics: MS Introduction to C# Generics


The Foreach keyword

C# Iterators use foreach instead of for. Also notice the variable declaration within the for/foreach statement. C# requires the type of the item contained in the list to be explicitly declared.

// Javascript

for (var item in someList) {

item.DoSomething();

}

// C#

foreach (ItemType item in someList)

{

item.DoSomething();

}


The New keyword

In Javascript, you can create a new instance of an object or struct without using the 'new' keyword. In C#, using "new" is mandatory.

// Javascript:

var myPosition = Vector3(0,0,0);

var myInstance = MyClass(); // creates a new instance of script "MyClass".

var myTex = Texture2D(128,128); // creates a new texture2d object.

// C#

Vector3 myPosition = new Vector3(0,0,0);

MyClass myInstance = new MyClass();

Texture2D myTex = new Texture2D(128,128);


Yield in Unity C# versus Unity Javascript

Although Unity's documentation does (briefly) cover the syntax differences in using Yield at Writing C# Scripts(Step 4), there is also a Unity Answer that covers How do I Use Yield in C#, which has a more detailed explanation. In addition, the answer by equalsequals has a link to a Coroutine Tutorial that is worth checking out.

Unity's Yield has additional capabilities over .NET C# Yield

The above paragraph covered the differences in Unity's C# versus Javascript syntax. However, I think that it's worth explaining that the behavior of Unity's Yield statement (in both C# and Javascript), has some additional features not in Microsoft's .Net C# behavior.

Basically, Unity has added the YieldInstruction (and child classes such as WaitForSeconds) to Yield. These classes give Yield the ability to temporarily pause the function, until a condition is met. If it has zero parameters, it pauses for a single frame. If it has a parameter of WaitForSeconds:

yield return new WaitForSeconds (2.0f); // pauses for 2 seconds.

then it pauses for some number of seconds. If the parameter is another Coroutine, then it pauses until that Coroutine finishes.

Yield only works this way inside a Coroutine. To start a Coroutine in C#, you use StartCoroutine, whereas it is automatically called in Javascript.

For a good explanation of how Coroutines and the main routine interact, see Duck's Answer


Casting

Javascript automatically casts from one type to another, where possible. For example, the "Instantiate" command returns a type of "Object":

// in Javascript, there's no need to cast the result of "Instantiate" provided the variable's type is declared:

var newObject : GameObject = Instantiate(sourceObject);

// in C#, both the variable and the result of instantiate must be declared:

GameObject foo = (GameObject) Instantiate(sourceObject); // C#

GameObject foo = Instantiate(sourceObject) as GameObject; // C# second version

Also, see Murcho's answer for more information about casting, including why you would want to use the second casting method listed.


Properties with Getters/Setters

In C#, it is possible to define special functions that can be accessed as if they were variables. For instance, I could say foo.someVar = "testing";, and under the hood, there are get and set functions which process the argument "testing" and store it internally. But - they could also do any other processing on it, for instance, capitalizing the first letter before storing it. So you're not just doing a variable assignment, you're calling a function that sets the variable, and it can do - whatever functions do.

I'm not going into the syntax here, this answer is long enough :) But here are two links:



MS: Using Properties, and C# Properties Tutorial.


Changing struct properties / by value vs by reference

This is actually a bit more than a syntactical difference but nevertheless fits here quite well:

The following code does work in JavaScript/UnityScript but not in C#:

transform.position.x = 3;

The reason is because transform.position really is not just a public variable but a property, so it's actually returned by a method call - and that happens "by value" for structs (Vector3 is a struct and not a class - for performance reasons). So, to achieve the same in C#, you have to write:

Vector3 pos = transform.position;

pos.x = 3;

transform.position = pos;


Function/Method definitions

First of all, terminology - Javascript uses the term "Function", while C# calls these "Methods". They mean the same thing, and most C# coders understand the term "Function".

Javascript functions are declared with the keyword function before the function name. C# Method declarations just use the return type, and the method name. The return type is often "void" for common Unity events. Javascript functions are public by default, and you can specify them as private if required. C# methods are private by default, and you can specify that they should be public if required.

In Javascript, you can omit the parameter types and the return type from the declaration, but it's also possible to explicitly specify these (which is sometimes necessary if you run into type ambiguity problems).

Javascript function examples:

// a common Unity monobehaviour event handler:

function Start () { ...function body here... }

// a private function:

private function TakeDamage (amount) {

energy -= amount;

}

// a public function with a return type.

// the paramter type is "Transform", and the return type is "int"

function GetDistanceTo (other : Transform) : int {

return (transform.position - other.position).magnitude;

}

And the equivalent C# methods examples:

// a common Unity monobehaviour event handler:

void Start() { ...function body here... }

// a private function:

void TakeDamage(int amount) {

energy -= amount;

}

// a public function with a return type.

// the parameter type is "Transform", and the return type is "int"

public int GetDistanceTo (Transform other) {

return (transform.position - other.position).magnitude;

}

 

No comments:

Post a Comment

News