If you’re anything like me, when approaching Unity3D for the first time you asked yourself a crucial question: Which programming language should I write in? As a Flash developer experienced in ActionScripts 1, 2 & 3, the temptation for me was to go for JavaScript. Syntactically, JavaScript and ActionScript are very similar. And from my point of view, JavaScript is the more popular language of the three Unity offers. I figured that whilst many experts may be using C#, most of the tutorials and sample code would be written in JavaScript, and I didn’t want to spend my time transposing code when I was trying to learn the fundamentals.
If that’s what you’re thinking, be you a Flash developer or not, I suggest you reconsider. I always knew I’d turn to C# eventually, but I was surprised by how quickly I found a need to do it. And what’s more, I discovered this: ActionScript 3.0 is more similar to C# than it is to JavaScript. There, I said it.
OK, syntactically speaking, what I just wrote is a load of balls. But in terms of functionality, I honestly think it’s true. Coming from AS3, when using JavaScript you’ll quickly find yourself wondering to where certain functions and keywords have disappeared. It seems like they should be there, I mean the code looks the same, but they ain’t there.
Anyway, that choice aside, this post is going to highlight some of the things I’ve discovered whilst converting an incomplete space invaders game from JS to C#. Note: part of the reason it was incomplete is because I couldn’t manage things the way I wanted to without the use of C#, particularly its better native Array(List) object and events.
Unitialised variables
Unitialised variables in C# are not allowed. Fields are, variables are not. This means you can write:
{
int i; //i will equal 0
}
But you cannot write:
{
//Do something. Or not, as ‘i’ will be uninitialised!
}
Pity, as I became quite used to doing that in ActionScript. Then again, and without going into too much detail, in ActionScript the temptation was then to apply the same trick to a nested loop, which would be a mistake. A very unfortunate mistake. So, maybe it’s for the best.
Null objects do not evaluate to false
Here’s another trick I got used to. Want to know if an Array element contains an object? How about:
Fine in ActionScript, I assume JavaScript as well. But that’s not going to help you in C#. You’ll have to be explicit and write:
You can’t add to only one of a Vector’s properties
This is Unity-specific, but it seems that rather than writing:
You’ll have to add a whole new Vector3 object, like so:
Interfaces. Oh boy.
Look, this one is hard for me. I have spent years now building extensible, component-driven frameworks, mostly for e-learning, and I got into the habit of, basically, putting an interface on everything. If SomeClass doesn’t have an ISomeClass interface, IDon’tWantToKnowAboutIt. Using interfaces in Unity however quickly got out of control, and I’m now of the opinion that, for the time being at least, they are best avoided.
It started like this: We’ve got a space invaders type game, and in this game several elements can be destroyed. There are the enemy ships, the player ships, and the shields, all of which we want to affect when a shot collides with them. So having detected the shot collision with something, we need to pull out a reference to thing with which it has collided. Was it an enemy, the player, or a shield?
Well quite frankly, it shouldn’t matter. I don’t know, and I don’t wanna know. The glory of object oriented programming is that we can relate to each other all the objects which should take damage. This could be in the form of a common interface, say ITakeDamage, or we could define a base class which the enemy, player, and shield extend. In either case, our base class or our interface will expose a function called TakeDamage( float strength ).
Here’s where the trouble begins. You’ve got the object with which the shot collided, and you want to find all ITakeDamage components in that object. Well bad news, buster, you can’t. Well, not without a lot of casting and some warnings. The problem is that GetComponent, and its related methods, all return an object, or stack of objects, of type Component. As the ITakeDamage interface is not the Component class, this is going to draw the ire of whichever code editor you’re using (in my case Visual C# Express).
There’s a little forum discussion on this very issue, at the end of which is a post by myself explaining that, faced with this problem, I ended up doing this:
foreach (Component obj in components)
{
if (obj is ITakeDamage)
{
(obj as ITakeDamage).TakeDamage(strength);
health -= (obj as ITakeDamage).Resistance;
}
}
So fine, we’ve got our interface in. It’s a little clumsy, but it’s there. So what’s the problem? Well, you can see that there’s another property in that interface, called ‘Resistance’. The thing is, an interface cannot define fields, only properties. Put another way, that Resistance field is going to need a getter/setter pair; it cannot just be a public field in whichever classes implement our ITakeDamage interface. (Well, not if you want it to be defined by the interface.)
And here, dear reader, is where the final, Earth-shattering blow comes in: The Unity Inspector panel helpfully exposes all public fields, allowing you to modify their default values within Unity, and give unique default values to unique instances of the same object in your scene. Do you think the Inspector exposes public properties (with getters and setters) also? The hint here is that if the answer were ‘Yes,’ I wouldn’t be going on like this
No, it can’t. Maybe one day, maybe not. For now your only option, if you really, really, wanted to use an interface, would be to link your getter/setter pair to …a public field. Quite frankly folks, if you go that far just to implement an interface, you’ve gone stark raving mad, and I’m having none of it. Now in truth, I think I’m better served by a base class in this scenario anyway, as there’s lots of shared functionality. And I think my old habits are dying hard. Look, we’re not here to create frameworks; we’re here to make games!
For the curious, here’s the base class in all its glory:
public class TakesDamage : MonoBehaviour
{
public float Health = 1;
public float Resistance = 1;
public bool IsAlive = true;
public delegate void DeadHandler(TakesDamage sender);
public event DeadHandler Dead;
public void TakeDamage(float strength)
{
Health -= strength;
}
protected virtual void Update()
{
if (Health <= 0) HealthDepleted();
}
protected virtual void HealthDepleted()
{
IsAlive = false;
if (Dead != null) Dead(this);
}
}