Sunday, February 24, 2013

Level Zero



I am deep in the twisty passages of Unity's custom editor GUI system.
It is pitch black; I am likely to be eaten by something or other.

It is fortunate that I am also learning C# concurrently from another source so that I didn't totally freak out when I started seeing things like

tMap = (tileMap)target;

in tutorials and wikis, I mean, what is that, is something being multiplied here? I guess it's an explicit typecast, casting the object this editor script is acting on into a reference shaped like a custom class? I started to get the picture from the bracketed line above the class definition:

[CustomEditor (typeof(tileMap))]

So it seems Unity, at least on the C# side, is using metadata in a fundamentally similar way to the .Net examples I've seen elsewhere, to extend functionality. I'm right on the dim verge of some related concepts like reflection and generics / templates, but I still honestly don't have a good grasp on what's going on under the hood here, which makes me nervous because when I see new syntax I want to know not only what it is, but why I haven't seen it until now.

Editor scripting is still a kind of menacing mirror-world to me, for example I'm used to

obj = Instantiate(foo) as GameObject;

but apparently that won't work in some contexts, to get the same effect you sometimes need

obj = (GameObject)Instantiate(foo);

and I have no idea why. It's also sort of vexing to be manipulating layout height, width and margin values in a text document like I'm designing a web page in 1992. Of course, this being Unity, such complaints are easily answered by the many plugins available on the asset store for a small fee, and it's a great business model. I'd learn more rolling my own, but I'm already several levels deep in Tool Building Hell, and how much deeper do we want to go exactly? I'm here to make games, or at least I thought I was.

I recently watched this amazing GDC talk by Jordan Mechner about Prince of Persia, detailing the tools workflow he built to create the ahead-of-their-time animations for that game. I won't spoil it here, but the lengths he went to for those effects look like the Labors of Hercules compared to anything one might do to extend a modern game engine or its editor. Still, it's a powerful lesson in how quickly a game's complexity can expand, how quickly a three month schedule can turn into a three year schedule. You have to invest exactly the right amount of time and effort into tool building, to walk that tightrope between burning out doing repetitive, easily automated tasks, and falling down the rabbit hole of attempting to craft the perfect tool for every job; it's impossible. Vigilance must be maintained.

Shout out to Daniel Branicki for the tutorial.

Post Script: A little while after I wrote this I made some sort of change to one of the editor scripts and crashed Unity, a full-on, auto-bug-report-wizard crash. Then whenever I opened Unity it would work OK until I selected the tile map object, then crash violently again. I commented out the lines it seemed to be crashing on, and it stopped crashing .. and responding altogether, to any kind of input. Eventually I was able to restore the editor to life by commenting out the entire OnDrawGizmos function, so now I guess I'll start commenting stuff back in until it starts to crash again. Just another example of Here There be Dragons in extending the editor. You're outside the safety zone, proceed at your own risk.


Sunday, February 10, 2013

Putting It Off No Longer



One of this project's many ironies is that while one of my initial motivating factors for making this game was that I would get to design a bunch of classic platformer levels, now that it's time to do just that the prospect looks like a terrible chore. This is easy to explain; I never invested in making any tools, I just have a bunch of scenery pieces I'm throwing down with no respect for any kind of grid... I do have "level/tile editor" as a future project, I suppose we could bump that up on the schedule.

I spent most of this week's time stitching together the initial screen and the character creation screen with the first gameplay level. I used a plain empty gameObject created in the main menu scene tagged, so cleverly, "BIG_BROTHER", then gave it a script with some values like currentLevel, currentPlayer(as there are three possible choices), and the key line

DontDestroyOnLoad(transform.gameObject);

allowing this all-seeing-eye to remain as each scene is dropped from memory in favor of the next one. Fine and good until I noticed I was relying on those values in the gameplay scene and thus if I ran that scene alone I'd crash with a bunch of null references. The only way to avoid them was to run the start menu scene so that the gameObject BIGBRO would get created before scene_level1 loaded in.

This is a mini-micro version of a really common real-world problem. Developers have to be able to make frequent iterative changes to, say, level six, without having to boot the entire game and watch the intro and logo screens every time. My solution, in this case, was to have the level scene manager script check at startup whether BIGBRO was null. If not, fine, continue on. If so, create a new gameObject (FAKEBRO) and give it some default attributes with the same names as the ones the level scripts will be looking for later. Instant debug mode, that doesn't need to be switched on and off, and displays visual info in the Editor via the name of the object as to whether I'm in it or not.

The catch .. it feels like I'm veering awfully close to breaking the commandment of "thou shalt have no God Objects", I mean I have BIGBRO and then a scene manager that controls game phases, and I'll probably combine those at some point, how much is too much? It's a given that something has to survive between scenes, I'm just wary of all the other parts of the scene becoming too dependent on that on thing ... wonderful, my game somehow found a way to have a religious crisis.

So, time to forget about it and get to finalizing the first level, which will involve further wrangling with those "wavestoppers" I thought were such a brilliant idea around mid December but now don't look so quite brilliant anymore, seeing as how they only work about half the time. I think it has something to do with an unintentional intersection of box colliders, which is another argument for getting that level editor done now. That's it, I'm calling a meeting with my Producer.