Coming from ActionScript / UnityScript to c#

[tweetmeme source=”neoRiley” only_single=false]After writing iFly and Star Wars: Trench Run in UnityScript, I became painfully aware of the shortcomings associated with UnityScript.  Mainly that it has no decent event / delegate system to leverage.  Sure, you have event handler methods that exist in GameObject etc, but that’s a complete throw back to AS2/1 days.  I tried porting an old AS2 event dispatcher class to UnityScript (which I did successfully) but had pointed out to me by someone at Unity that it would be painfully slow.  He then suggested I consider c# and get involved with delegates.  He was right.

So, for a while now, I’ve been doing c# and loving it.  There were, however, some things that obviously caused me some discomfort and that’s why I’m writing this post.  I’ll be adding to it when ever I find new topics that apply.

First, here is a link that provides the majority of the “differences” between UnityScript and c# – I recommend this one as it really covers the basics very well.  I’ll be covering the not-so-obvious ones that made me scratch my head😉

http://answers.unity3d.com/questions/5507/what-are-the-syntax-differences-in-c-and-javascript

Alright then, here’s the first thing to look out for:

Number = float

Coming from AS3, you’re used to Number, int, uint and for the most part, you get what they do.  When coming over to c#, there is no “Number” type.  Instead, use float.  Just think of it in the most simple terms:  “f”loat for “fraction”.  Meaning, if you know you’re number will be fractional (like 3.16) then give it a type of float:

float myScale = .5f;

Note the “f” at the end of the declaration (.5f) – that’s how you cast it as a float.  If you don’t, Unity compiler will give you an error.  Same goes for passing floats as arguments, make sure you include the “f” cast:

Vector3 pos = new Vector3(.1f, .05f, 2);  // you can add the "f" cast after a whole number if you like, but it's not necessary

If you’re doing some division or scaling math and you know the outcome *could* be fractional, both sides of the equation need to be floats or you’ll get a whole value in return.  Simple enough you might think, but I’ll bet you scratch your head at least one time on this one where you can’t figure out *WHY* it’s not calculating a remainder for you:

float i = 15f;
float j = 10f;
float value = i / j; // 1.5f

If you want to parse a string into a float or int:

int value = int.Parse(stringValue);
float value = float.Parse(stringValue);

If you want a whole number and an int from a float, use FloorToInt() – I mention this one simply because of how AS3 just doesn’t give a crap, but c# does:

int value = Mathf.FloorToInt(float n);

Event Dispatching

In AS3, everything extends EventDispatcher practically.   Everything can dispatch events, have listeners and everyone’s happy in their little event driven world.  Then you come over to Unity and realize, we’ve taken a step back into AS1/2 land. There are event handlers on GameObjects and if you declare them, then they will receive the calls – very very onEnterFrame type of stuff here.

So, given my history and experience with AS2, I naturally dusted off an old EventDispatcher class that we used to use back in the day.  Like I said above, I converted it, it worked, but was made to realize that in a performance setting, it’d be a pretty substantial bottle neck.  Still, if you’d like to see how it’s done, here you go ( now at least, I won’t feel like the time I spent on it was wasted )

EventDispatcher.js
ListenerObject.js

But now, the real deal in c# for creating an event and dispatching goes something like this:

Declare a delegate for the event. Note that I’ve created it outside the class declaration – this is so it’s available to any class:

public delegate void LoadComplete(float value);
public class MyClass
{
    //...
}

Now, create the event in MyClass:

public delegate void LoadComplete(float value);
public class MyClass
{
public event LoadComplete LoadCompleteEvent;
}

To add a listener, you add a new delegate instance with the handler to the LoadCompleteEvent event:

public delegate void LoadComplete(float value);
public class MyClass
{
public event LoadComplete LoadCompleteEvent;
    public void Start()
    {
        LoadCompleteEvent += new LoadComplete(HandleLoadComplete);
    }

    // note how the argument signature matches the delegate declaration
    private void HandleLoadComplete(float someValue)
    {
        // event handled here
    }
}

To send out the event, first check to make sure the event is not null (has listeners), then call it like a method:

public void DoSomething()
{
    if( LoadCompleteEvent != null ) LoadCompleteEvent(1.0f);
}

To remove a listener, just remove the handler from the event:

LoadCompleteEvent -= HandleLoadComplete;

Coroutines (replacement for setTimout, setInterval, Timer object)

In AS3, we’re used to setTimeout() or the Timer object to deal with waiting and looping stuff.  In the old days, we used onEnterFrame and I can still remember the arguments over which was better – setInterval or onEnterFrame.  It was a ridiculous argument, because in reality, it just depended on *what* you were doing when that even fired.  Please don’t leave comments regarding this tired and exhausted discussion which has zero relevance these days😉

In UnityScript, you’ll be introduced to WaitForSeconds() which is really nice when coming from AS3.  In c#, however, you get a bit of a rude awakening. You begin to realize how much UnityScript lets you get away with.  Its insane.

So, here are the basics.

If you want to loop or wait a certain amount of time, you have to call a method that returns IEnumerator:

public IEnumerator DoMyBidding() {...};

Then, you have to have some sort of yield/return statement in this method or the compiler with barf all over your keyboard:

public IEnumerator DoMyBidding()
{
    yield return WaitForSeconds(1.5f);
    if( myConditionNotMet ) yield return null;  // this is how you just simply return out if you no longer wish to continue.
}

If you want to loop something:

public IEnumerator MonitorMe()
{
    while ( conditionNotMet )
    {
        // do something
        yield return WaitForSeconds(.025f);
    }
}

To call these methods, you have to use StartCoroutine():

public void Start()
{
    StartCoroutine( MonitorMe() );
}

Well, for now, that’ll get you started, and as I remember/think of things, I’ll come back and update this post with more tid-bits.  Enjoy!

  1. Seems like we’re all into C# events these days http://www.everyday3d.com/blog/index.php/2010/10/04/c-events-and-unity3d/🙂

    One thing: for timeouts it’s better to use Invoke instead of a Coroutine, and for intervals – InvokeRepeating.

  2. I would disagree depending on the circumstances. Invoke and InvokeRepeating are both slower than what I’ve suggested above. They’re easy on the eyes and easy to use, so use with caution. I’m just paranoid and I do alot of iPhone/iPad dev work so, I just done use em’.

  3. My favorite feature in C# would go to LinQ where querying a list of objects would look much like SQL. It is easier to write and understand, and it saves a lot of foreach statements.

  4. Nice article. I’m a big fan of C# events. One small thing:

    if( LoadCompleteEvent != null ) new LoadCompleteEvent(1.0f);
    

    I think there shouldn’t be “new” there because the delegate is called as a function.

    • I don’t know why I had “new” in there in first place to be honest – and you’re right of course! Edited!

  5. Also, @bartekd’s link shows newer C# event syntax that is more streamlined, less mucking about with delegates and more compiler inference.

    • adding the listener, I agree and I like in his article. Either will work, but I like streamlined code as well🙂

  6. Is there a benefit to declaring the LoadComplete instance as an event as opposed to just declaring “public LoadComplete LoadCompleteEvent” (aside from code clarity)? Also, I believe you can put the delegate declaration inside the class and still have it be used by other classes. And one more thing re: delegates, you sort of show it in the code example, but don’t mention explicitly that one of the benefits of delegates is that the listeners can remain private to their own classes so they aren’t exposed and can only be called in controlled circumstances.

    • @Francis -I’m not sure if there’s a benefit or not. And thank you for pointing out the benefit of delegates!

  7. Hi,
    I’m new in iApps developping and also I love coding with ActionScript3. Did you tried the Adobe Packager for iPhone. I just need to know who is responsible for my terrible game performance is it packager or may be I’m doing something wrong? Should I move to c#?

    • The performance issue could be many things, but to answer your question about C#, yes – I’ve really enjoyed it and now use it with all unity projects

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s