Saturday, February 21, 2015

Always Crashing In The Same Car

It’s dangerous to go alone. The total freedom of solo game development can be its own worst enemy. With no one around to say “hey, maybe rough in feature X and move on”, you can end up caught between your best judgment and the stubborn, dogged perseverance that got you into this mess in the first place. The more of this I do, the more I find that the ability to scope from within a problem, to decide which solutions are good enough for now, to basically Produce oneself as mercilessly as a corporate publisher, that constantly updating self-reflection is the key difference between solo games that are in some way concluded and others that are simply abandoned.

I spent most evenings and weekends of the dark months on project_petrov, often spinning my wheels, or more accurately watching a small model car flip onto its side over and over again.

This whole racing project is a derail in itself. I’ve been working through this (really excellent) Unity textbook which mostly consists of little example game projects where they give you some starter bits and then you complete the game. Everything was going great until I got to the "generic racing game" project. I got into it, then started getting irritated by things like the terrain being inappropriately mountainous (making camera movement in scene view difficult and lighting a chore), the track being punishingly long for the size of the models (making iteration on things like win condition code a chore) and various other minor annoyances. I decided the only way to complete the project to my satisfaction would be to remake it from the ground up, including all the assets. I figured I could whip up some new scripts, hit Turbosquid for some free cars, and maybe put some twists on it so I could have another minor portfolio piece. Expected turnaround time: a few days? This was in November.

My first hack at the track was an interesting idea, I found some outline images of famous race tracks at this cool site, and attempted to use some as height map files on Unity terrain objects. The primary problem with this was the dismal sense of racing in a WWI trench, but there were other problems, for instance I had no easy way to tell whether the cars were on the track or not. Eventually I realized I would need to use some kind of road objects that could send messages about whether a car was touching them. So, the racing trench and its associated materials went into the bin.

Making modular track pieces with Blender was straightforward enough after watching a few relevant YouTubes. My UV mapping skills are still pretty basic, so the road curves look a little stretched and blurry, but I was able to make myself move on from that (which wasn’t hard, because another few nights in Blender was nothing to look forward to).

The muscle car model itself was also simple enough to work with, although the artist “posed” it with the front wheels turned insouciantly to the left, so I was constantly having to adjust them by around 9.6 units of rotation, a figure which grew to haunt me. It didn’t make much difference in the end as I wound up chopping the model into body, glass and wheel meshes and placing each individually as child nodes of either the car body or the car wheels, so I had an invisible cube and some invisible cylinders “wearing” the good meshes like a second skin. I painted each mesh with some basic colored materials, entertaining various dreams of a rainbow panoply of AI opponent cars, and a cel-shaded “Saturday morning cartoon” effect in post-processing, but both of these features turned out to be, thank Christ, out of scope.

Then it came time to make the car go. The book example propels the vehicle by using AddForce on the car’s RigidBody, which works well enough, but as a physical simulation is somewhat like towing the car along behind another car with a cable – the movement force doesn’t come from the wheels, so the simulation is not very car-like. I was determined to do things “the right way”, which meant controlling the car with four WheelCollider objects by applying MotorTorque and BrakeTorque. This was actually fairly intuitive and even fun to implement, and the simulated springs gave the car a delightfully realistic bounciness when dropped onto the terrain. Everything worked beautifully until I attempted to turn the vehicle, at which point it flipped over. Repeatedly. Every single time, in fact.

Anyone who has done time in the murky woods of Unity vehicle physics is probably familiar with self-described Hardcore Developer Edy, a towering genius of video game automobiles who has published some fascinating posts on the Unity forums, describing, among other things, how to keep a car from flipping over. The answer he proposes is simulating stabilizer bars. The idea is, you read data from the WheelCollider to determine how far the spring is extended. When the car takes a turn, the springs on the inner wheels will compress, while those on the outer wheels expand. So, as a spring expands, you impose a downward force on the car body at the wheel location, and the more the wheel threatens to leave the ground, the harder you push down on it. Elegant in theory, but in practice there are more than a few things that can go wrong, and in my case all of them did.

I could not get the damned car to stop flipping over. Some reasons my stabilizer bars might have failed:
  • The car may have been out of scale to the Unity physics system
  • The car’s rigidbody mass and center of gravity settings may not be compatible with the stabilizer code
  • The car model exported from Blender may have some qualities that don’t play well with the physics system and/or the stabilizer code
  • My WheelCollider settings may be incompatible with how the stabilizers work
  • I may not be applying the downward force effectively, with the right amount and at the right location
  • Despite extensive visual debugging to make sure X really is X, I may be misunderstanding what the stabilizer code is actually doing
  • My math deficiencies may have gotten the best of me (the stabilizer code uses Transform.InverseTransformPoint, which I can’t honestly claim to completely understand)
  • The WheelColliders themselves may be in some way suspect. I have nowhere near the knowledge to takes sides on Edy’s post about a purported scandal in wheel town, but nobody from the Unity dev community has come along to tell him he’s wrong, so who can really say?

All interesting lines of inquiry, for someone with half a dozen spare lifetimes to spend faffing about with wheel physics, but I had already squandered too much time on the problem. Finally, I found a brutal hack and wielded it like a hatchet. Behold my shame:

downforce = -veloMag * rigidbody.mass * 3f; //sSHHH it's a MAGIC NUMBER son
downvector = new Vector3(0.0f, downforce, 0.0f);
rigidbody.AddForceAtPosition(downvector, transform.position);

The faster the car goes (veloMag is the rigidbody’s velocity.magnitude), the harder I press down on it at the center. It’s like racing with the veritable Thumb of God on the car roof the whole time. Now, any future development work would surely start here: I’m confident that I could lower that value and tweak various other parameters until I reached a compromise where the car would resist flipping, but retain some of the car-like bounciness the WheelColliders provide. As it is, I’ve more or less come all the way back around in terms of realistic simulation. This solution is hardly more “car-like” than just applying force directly to the car, all the interesting wheel spring behavior is getting squeezed out of existence, like the dynamic range on a Red Hot Chili Peppers album.

Regardless, this allows me to glue the car to the ground, finish the scenery and UI, put some basic game logic in place, and close the loop on the project as a portfolio tech demo. It’s a racer, just not a very compelling or well-realized one, and it’s not exactly meant to be. Although I have some interesting ideas on where it could go, and I may spend more time on it later, I’m not taking this thing to Early Access.

Here's where I confess to not particularly loving racing games. Oh, don't get me wrong. Pole Position is just as iconic to me as Galaga or Moon Patrol, and the arrivals of the Stun Runner and Hard Drivin' cabinets at my local arcade were earth-shaking events at the time. I just mean to say that I never planted a stake in any modern racing franchises, never had a Forza career or bought a faux steering wheel. So why make one? Primarily due to being at the racing chapter in the textbook I was working from, but just as importantly out of a self-imposed need for portfolio diversity. For some dumb reason I feel like a proper game designer should be able to whip up anything from a shooter to a stealther to platformer, in 2 or 3D, in enough detail and with enough quality so that it could convey whatever the cool new twist is without stumbling over the set dressing. It's a fine notion, but it turns out that maybe racing is one of the less trivial genres, from a gameplay design point of view.

And, without getting too grim, this work is hard enough to justify as it is. When I wasn’t day jobbing on the fringes of the industry, I spent the dark months flitting from studio to studio whenever a designer role came open on the job boards, shaking hands and telling my life story over and over, trying to convince someone, anyone, that yes, I am actually competent as a game content designer, and not being able to convey that impression in the slightest. I’m hoping that all this portfolio work will pay off, but it’s hard to believe that anyone will care. The studios want, and in most cases can afford to wait for, a designer with years of commercial experience on the exact subgenre they’re putting out. I’ve been rejected on the basis that “we’re looking for someone who lives and breathes subgenre X”, which, I suppose I’d want that too in their position, but it points to a pretty dark future for someone whose resume looks like it was written with a shotgun. I’m slowly trying to find a way to accept that I may never be employed as a creator again, that the rest of my career may be an endless string of exploitative and unrewarding QA contracts. I have to make a conscious decision every day to not believe this, because the feeling of believing it is like the feeling of being on fire. Nobody likes being on fire.

Coming Up
  • more prototypes
  • project_catalan upgrades
  • some non-Unity experiements
  • some game design docs for larger projects 

No comments:

Post a Comment