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.

Sunday, December 23, 2012

Low Power Mode

I got a job! It is in the industry, but I'm not sure what I can say about it online so the best option is to say nothing. I will be continuing to work on this game with however many cycles I can allocate to it, and I'll try to  post here when I can, but updates will be less frequent for the foreseeable future.

Sunday, December 16, 2012

Have Mercy


Let's see, what did I do this week. Just now changed some code which allows the player to fire weapons in mid-air, exposing some other weird animation issues. The state system for character poses and moves is a little fragile, but I think I can shore up the weak spots, it's just going to take going over the file with a fine toothed comb. Also started placing what I call "Mercy Caps", little invisible two-unit wide box colliders at the edge of platforms. One function of these is that they do give the player a little mercy when wandering close to the edge of a platform, for some reason having the player fall off right at the platform's edge doesn't "feel right", it's harsh and kind of frustrating, that little buffer seems to help. The other thing with these is that platforms are supposed to kill "acoustic wave" projectiles, this is so when the projectile has grown enough it will naturally intersect with the floor or ceiling and disappear, creating a kind of cone of fire in front of the player. I do this by tagging every platform tile as a "wavestopper", searching for that tag on collisions and using it to destroy projectiles. Works great, but if you are standing off to one side of a platform and shoot at it, the platform shouldn't just eat the projectile. By tagging the Mercy Caps as "bouncer", I solve this - the projectile hits the cap, which doesn't register as a wavestopper, and bounces off without touching the platform. Thus platforms will only kill projectiles if hit as a floor or ceiling.

I also see here in my notes that I "solved a problem with physics by ignoring it". I think the gist is, I was reversing "bullets" as they struck scenery objects by using AddForce on the rigidbody, addding an opposite amount of force from what the bullet already had. This resulted in some really off behaviors, things getting stuck, general bad mojo. I eventually stopped mucking about with phsyics, and when the bullet hits an object I just flip its velocity.x. Now it's traveling with the same velocity, under the same force, in the opposite direction! When you set up a simulation system like physics it's easy to forget that you can just reach in there under the hood and perform an Act of Dev if you feel like it. I'll try not to let the power go to my head. In fact I think I wrote something a while ago about why you should never override your own physics simulation like this, I'll have to look that up when I get time...

Much of my time this week was spent watching and taking notes on a multi-hour presentation on Object Oriented Design. This has been really eye-opening to me in terms of the Big Gap between knowing how to write a few lines of code and knowing how to write an application. It walks through several accepted ways to architect software, starting with requirements, use cases, and user stories, moving on through use case diagrams to domain modeling and UML class diagrams. I was surprised (and much relieved) to learn that if this process is done right, by the time you sit down to code you are more or less transcribing your functions and variables from the diagrams you already created, and your mind is free to solve the individual math or data handling problems that will crop up in your individual functions, rather than desperately trying to keep one eye on your code and the other on the big picture.

This is light years away from my current "cowboy style" development methodology, and I am definitely going to approach my next project from this perspective and save myself a lot of hassles. As for my current one, I think I've already hacked in the majority of the objects and features I'm going to want. It was interesting to see some intuitive stuff I arrived at explained to me with some knowledge behind it. For instance, I was originally controlling bullet movement from a script that lived on the "weaponSocketController", the object that instantiates bullets when the trigger is pulled. I realized after having to reach across scripts too many times that the bullet's behavior should live in a "bulletBehavior" script on the bullet itself. Had I watched the design presentation first, I would have learned that it is always best practice for an object to contain the methods and variables required to control its own movement and behviors whenever possible. Well, I know that now.

I have a bunch of other videos lined up that aren't strictly game related, starting with an in-depth C# course, some ASP.NET and MVC stuff, and the ever-popular PhP with MySQL. I don't know how much of this stuff I will realistically be able to absorb and how fast, but that's definitely the path I'm headed down. I will continue to plug away at this project, and of course I have some other ideas I'd like to get to, but I have to spend more time working directly on code. Being able to write a user-facing or i/o or back-end feature, from scratch, within a significant existing codebase ... well, that's where Dice is telling me the jobs are, and not just in games. Code or die is the order of the day. I don't make the rules, I just gotta live by them...