Monday, March 25, 2013

Back in the Triple Digits



Just truckin through my backlog, on my way to full vertical slice, and not that far off either. The shooting and jumping aren't exactly ... inspiring, but at least they work. I spent a lot of time fooling with gravity when I was making the floor and platform tiles, trying to find that right scale for the "running jump" mechanic. The way I wanted it to work, you could complete the level just walking, like if you didn't ever realize holding the fire button makes you go faster (I do change the animation, I tried to make it obvious), you should be able to get all five bus transfers just by jumping normally, although you'd have to take some circuitous routes and it would be a pain in the ass. At the same time the running jump couldn't be too powerful, or since the platforms are so close together you get this queasy thing where the player just jumps toward the side of a platform, slides up, and ends up standing on top, which isn't very jump-like. I tried adding a RigidBody component for physics jumps in the hopes of getting something springier, but the intersection of the RigidBody and character controller was causing some Exorcist-like behavior so I bailed on that one. I'm not thrilled with where it's at now, but I can live with it a while longer.

Anything the player can touch is a primitive 32x32 cube displayng a frame (via a scaled and offset material) of one of two 256x256 tile sheets. The buildings and clouds are big textures (the clouds are 4096 wide) painted on scaled up quads, and scripted to move in parallax to the player. Most of the collision volumes are cubes the size of the tiles, but platforms have scaled down collision boxes, as do some of the objects. I'm still using the old pickups but I'll probably make them tiles too eventually. The frame rate hangs reliably in the triple digits. This concludes, knock on wood, the technical implementation of the guts of the game. The rest is window dressing, oh and design.

I re-learned some things about instantiating and destroyng prefabs. I spent a little too much time re-learning that a switch/case runs on break; statements and yes, they mean it, and any code you had in that function below the switch/case is not getting run, which is probably why it is not as effective as you thought it would be. At least, I think that's what happened ... regardless, it works now. I re-learned that your first level design instincts are often too big. This level is actually pretty small for a platformer now, but only because I wanted everything to feel closer together. In a sense all the objects really are kind of tetris-jammed together, but it's really the same set of elements from the larger draft of the level, just brought in tighter, I think I only deleted like two objects. It's odd that I got a lot of stuff right the first time but I got the scale totally wrong.

The actual design of the level, given the constraints imposed by the grid, the jump tuning, and the five bus passes (plus a bus stop), was dirt simple. Figure out how to make a bus pass hard to get to, then do four variations. One is on a catwalk, another is tucked behind a roving skeleton, one is in a corner. None require run jumps but all are made easier by run jumps, run jump is frankly a little OP right now but it feels better than it did. I even started to polish a little by adding particle effects to the bus passes, but of course now I'll need particle effects for everything...


Next is the level-end bus-pickup "experience", the fail/restart, maybe some options geegaws, and another say three levels, all built with similarly small tilesets, maybe one extra enemy per level and that's about it. With my schedule the end is still months away, but I can see it, coming ever more clearly into focus. Gotta get this puppy out the door!

Tuesday, March 12, 2013

Performance Anxiety



What little rationale there was behind building a 2D tile-bsed platformer in Unity went something like this: learn the tools and workflow on something small enough where you won't have to worry about optimizing for performance. This was naive.

The tile map implementation I described previously involves painting tiles in the scene view, each tile consisting of a textured mesh. When I picked my head up from my second layout of the opening level (wonder what number that will get up to) and pressed Play, Unity thought for awhile. Twenty-one seconds, to be exact. My gameplay and scenery grids combined were holding 8087 tiles, each of which contained a single quad.

Many things were vexing about this. For one, the stats window showed 384 verts comprising 192 triangles, which didn't seem like all that many to me. For another there was the fact that after that twenty second startup, Unity seemed pleased enough to hum along at a triple-digit FPS while the playfield was traversed; there was no in-game performance hit. Without a deeper understanding, or the CPU/memory profiler Unity offers for a mere fifteen hundred bucks (along with a Pro license), there was little I could do but conclude that I was just Loading Too Many Things.

Idea #1: "Well, how many is too many?"


My Test mind kicked in. I wanted to repro the issue, isolate it from its context. I made the scene shown above, with a total of 10180 red cubes, boasting 104,800 vertices making 52,400 triangles. The whole thing loads in less than three seconds. OK, interesting. Apparently 8087 tiles is not too many. What else is going on?

Idea#2: "It's the materials."


I was doing what I thought was a really swell thing by confining my entire city scene to one 256 x 256 texture made of tiles, which were arranged for display, uv-wise, by a material unique to each tile. Maybe that's bad? Really grasping here, not even mentioning stuff I thought of before the red cubes, like stitching all the meshes together at runtime (possible, but goodbye texture data and anyways I tested it and that would happen in script after my startup problem is already come and gone, so who cares?).


Anyway the point is I was desperate for a simple answer. I decoupled all the materials from all the prefabs, turning everything in the level pink. My start time somehow went up to 24 seconds.

Idea #3: "It's a script"


Since this was a one-time perf hit at startup, perhaps one of the scripts was looping over the tiles at startup in some poorly thought out way. I feel like I would have noticed that earlier than I did? Whatever though. Let's comment everything out. 24 seconds.

Idea #4: "Uhh maybe ... the tile editor's Instantiation method, isn't that deprecated?"


Ugh fine whatever. Let's rebuild the level from scratch, with the same tools, and figure out where and when the perf hit starts to happen. OK looks like when we get over about a thousand of these we start to bog down. With the new version of Instantiate, and without materials. These objects are piling up at around 1000, and the cubes were loading like butter into the quintuple digits.

Idea #5: "Something about a mesh as opposed to a cube?"


Turned off shadows. Tried a cube. Tried a sphere. 


PrefabUtility.InstantiatePrefeab and it's deprecated Editor cousin allow you to do things like paint in scene view, you're painting with prefab instances, so it's hard for me to conceptualize that you would need to Instantiate all those again at runtime, because I already did that, I'm looking at them, they're right there, but I guess what I'm looking at could be a preview of some kind. It would make sense that it would take some time and resources to bring all those cubes into being, and that's really the only thing left that seperates that tower of cubes from my level: the cubes aren't prefab instances.  

That points me toward really dreadful things like asynchronous level loading (another pro feature), and eventually I arrive at

Idea #5: "I guess we'll have to find a way to render a level without loading thousands of tiles"


I guess you could, you know, use a hundred or so tiles for sidewalks and platforms, then just draw some backgrounds and put them on big quads. Rather than, you know, making a skyscraper out of hundreds of individual meshes, each uv mapped to part of a single small texture, a "solution" that somehow joins the worst aspects of all possible approaches. I was so close, though! Throw that texture in and just paint the level, so convenient! Wait, hold on, if prefabs are the problem, why not

Idea #6: Alter the editor window script to stop instantiating prefabs and instead make meshes from scratch with the appropriate materials on them!


Oh lord. All right, worth a shot. Redid the tileMap code to make a primitive again, like the demo script, instead of instantiating. Used cubes as Unity has no Quad primitve type. Rotated the cubes. Updated the custom editor to paint materials instead of prefabs. Applied a variety of textures to simulate what I'm actually doing in the level.


Bam. 7956 cubes. Feels like between three and four seconds. Now, though, even that length of load feels kind of intolerable. Eh, I think if I do the buildings as scaled-up single quads and leave the tiles for the floor and platforms I'll be OK, shouldn't be more than a second. The lesson, as far as I can tell is: prefabs are slow. That is, unless after my third buildout of the level I find out the problem is actually something else...

Saturday, March 2, 2013

bool GoodEnough == true;


I'm wrapping up my adventures in custom editor land, at least for the time being.

The EditorWindow script actually gave me some serious headaches because of the way I wanted to structure the grid system. The idea was to have three separate grids, each stacked on the z-axis with 32 pixels between them, one for gameplay objects and tiles, one for buildings and other scenery, and one for the backdrop. Problem was, the EditorWindow was set up to find the grid to edit like this when it was opened:

tMap = (tileMap)FindObjectOfType(typeof(tileMap));

which works great when there's only one grid. With multiple grids, each with a tileMap script attached to it, the EditorWindow will only ever find the first one in the list. I tried a number of ways to allow you to choose a grid from within the window, but my first several attempts caused some kind of recursive error that locked Unity up by throwing dozens of null reference errors every second. This slowed down my problem-solving workflow a bit. After a bunch of Googling and cobbling things together, I finally came up with what is perhaps the single ugliest line of code I've ever typed:

allTileMaps = (tileMap[])tileMap.FindObjectsOfType(typeof(tileMap));

Christ, look at that thing. Just look at it. I know what it does but I couldn't tell you why. For good or ill, this monstrosity turned out to be completely irrelevant anyway. After grappling with various methods to expose the members of that array in the editor window, I finally realized that all my trouble was being caused by this line:

tMap = EditorGUILayout.ObjectField("Active Grid", tMap, typeof(tileMap), false) as tileMap;

The culprit was that "false", which is setting the boolean variable "allowSceneObjects", which was keeping me from applying any of my three grid GameObjects within the editor window. This made me think I needed some kind of superstructure to hold every object with the tileMap script attached, which just wasn't true. The embarrassing takeway: just because you found some functional code to copy from somewhere doesn't mean you've solved your problem. If you don't understand exactly what the code is doing, you're as likely as not to cause yourself more problems. I guess this is one of those obvious things that you need to teach yourself the hard way, like a child touching the burner of a stove to see if it's hot.

So here, below, is the final version of my built-in level editor.



That's it - a few data fields, a color picker for drawing the grid, and a Texture2D field that was supposed to show a visual preview of the selected prefab, but which I wasn't able to get working and eventually gave up on. It's more than a little pathetic, but here's the thing: it works. I can click the Active Grid field to select which grid to operate on, then select my prefab "brush", then press 'a' to paint tiles at the mouse location. It's much faster than my old way, and it keeps everything aligned properly, which allows me to get on with building the levels.

I recently listened to a fantastic talk by Jonathan Blow called "How to Program Independent Games" . There's a lot of good advice in there that really brought the dangers of premature optimization home to me in a way I hadn't really grasped before. The key quote, to me, was this:

"I'm a big fan of 'good enough for now', because 'good enough for now' often ends up being 'good enough to ship the thing.'"

We all want our projects to be elegant, sharp, and impressive to our peers. We all respect and want to emulate those heroes of old who had to bend over backwards to cram every possible byte into primitive cartridges and arcade cabinets. We all want to feel smart and capable and professionally ingenious. These are not bad things to want. Ultimately though, as Blow points out in that talk, there are only so many hours in each human lifetime, and there are only so many projects that you or I will ever complete. At the end of your time as a game developer, however that end comes about, which would you rather have: a few completed projects that emphasize clean, correct, bulletproof code, or a bunch of completed projects that emphasize fun, storytelling, cool levels, innovative gameplay and all the other things that motivated you to get started in the first place? It's not a trick question, and it's not a hard choice.

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.

Thursday, January 24, 2013

I Feel So Dirty


I wanted to make note here of a new milestone in cheap hacks, which coming from me is saying a lot. So, apparently, you can't destroy an instantiated prefab from within a coroutine. This poor S.O.B. had the same problem I was facing, and nobody had a good answer for him. I fully grant that this could be just a knowledge failure on my part, but I have not been able to determine why Destroy(thisThing) works perfectly well from inside a standard function, but fails silently from inside a coroutine, even though the code after it executes perfectly well. I'm sure one could track this down to some intersection of Unity's particular object system, the way its prefabs work, and its use of C#'s IEnumerator returning functions as the basis for coroutines (for instance, I suspect it might work fine in Javascript), but I don't think I'm that someone, at least not this evening. When I find someone else has encountered the issue that's blocking me, and has appealed to the Greater Internet about it, and has received no succor, I tip my hat to that brave pioneer and then I reach for my hacking axe.

So, when you need an object destroyed at an exact point in a coroutine, but you can't do it from within that coroutine, what do you do? If you're me, you make a new C# script called cloneKiller, and when you instantiate the prefab you also add the script to the clone with

ck = clone.AddComponent<cloneKiller>();

cloneKiller contains a single function, called KillMe:

public void KillMe()
{
if (gameObject!=null)
{
Destroy(gameObject);
}
}

and in the middle of the coroutine, I simply call

ck.KillMe();

 I know, that's absolutely ridiculous, and I should be ashamed of myself, but it works. . . actually I'm going to go ahead and make that statement the official motto of this blog.

Monday, January 21, 2013

Down With OOP

While my job slowed this project way down, I do manage to fire up Unity at least every few days and I'm still making progress on this game, although at this point it would be hard to tell from looking at subsequent builds, because I've finally decided to refactor some code.

I feel like I've been through a small level-up experience. It started about two weeks ago, trying to finish the interaction between the player and the first enemy. I had a small "Kick" function in both playerControls.cs and enemyControls.cs that would apply an impulse to either character when they came in contact with a "bad" object. The function was slightly different for each, but contained some repeated code. I then got into making a "Flash" function to flip a character's sprite renderer off and back on, separated by a tenth of a second coroutine yield, to give that classic effect of a character strobing to indicate they've been injured. I realized that this function would be identical between the characters, which made me look closer at the animation functions for each and realize I was basically writing a really long, complex script twice, simultaneously, changing a few variables and conditionals each time. It had to stop.

Thankfully, Lynda.com's Prof. Allerdice had provided me with the answer: Inheritance. I made an abstract  "Character" class that implemented all the major functions for all characters, then subclasses "Enemy" and "Player" to break out specific behaviors like patrolling, etc. by overriding virtual functions. The result is a much cleaner working environment, where the Player and Enemy scripts are both clear and compact, and I never really have to touch the Character script. Also much lower bug rate and general stress rate from trying to implement the same thing twice each time.

I have all the bits and pieces of Death together, save for the enemy's "crumbling into bones" animation, so next it's time to tie all that together, then move on to loot and pickups. I can't see the end yet but I think maybe I see the middle out there somewhere.