So, now that I’ve gotten the ‘HAI GAIS NEW GAME RIGHT>?” stuff out of the way, it’s time to start jumping into some specifics about the systems I’ve been working on for these past months. Considering the genre-space Null Op is in, 6DOF, literally refers to a movement modality, it seems the right place to start is to talk about the flight system.
First a little quick history on this side of the project. I’ve been working on 6DOF stuff for as long as I’ve been coding in Unity (most of that time, quite badly). My flight/control systems have gone through well over a dozen fresh-start iterations across almost as maybe project attempts/sketches/demos/beginnings. With each one I’ve tried something a bit more complex. The math has gotten more solid. I learn a bit more each time. I think I finally have something I’m really happy with now.
Oh, and one important note on everything I’m covering here. You might notice that none of this has the quiet/somber/atmospheric tone of things in the Remnants demo I showed off last week. I just want to make clear that the systems I’m building here are being built on an ‘island’, separate from the game’s main Unity project. How things look are fairly unimportant to this side of my experimentation, and I’m testing largely for extremes in terms of speed, altitude, sound volume, etc at the moment, so I can push things to their failure point and understand where these systems might break down.
No I’m not making a dog-fighting game. Yes I know these all these systems would work incredibly for one. No I don’t care really care at the moment.
So to make legible some of my design logic for the Null Op flight system, it makes sense for me to outline the constraints that I’ve been operating under, and the general goals I’ve had for the system:
A Physical, Weighty Feel
Most flight controllers, especially 6DOF, that I’ve tried feel incredibly floaty, smooth, and have 100% homogenous linear and angular movement capability. I want something that feels heavy, imperfect and substantial.
Nuanced System Failure
Wherever possible, the system’s functionality should be distributed to physical components of the ship that should be able to fail. That failure should not be binary, but occur along an axis from factory-new to slightly damaged to moderate failure to dangerously unpredictable. Failure should be modelled both in terms of loss-of-capability and failure to communicate properly with its parent system. All forms of failure should have visual feedback to the player (panels, lights, sparks, splosions).
All Dem Gs
The system should perform well both under gravity, and in zero gravity. This is a much harder challenge than making a 6DOF system work in zero-g, but absolutely critical, as making it work across this range of contexts means it can work in..
Cross-wind and Turbulence
The system should be able to handle constant/oscillating forces and torque from cross-winds, explosions, and localized gravity differences(in zero-g). By handle here I don’t mean ‘make irrelevant’, but more ‘compensate for to the degree a ship has both been built for, and is being flown to deal with’. This will make more sense in the Fly-by-wire section below.
Don’t Be A Drag
The system should not need a high drag value on the rigidbody to be stable. In general, the ‘cheat’ most folks use to keep pure-rigidbody systems controllable is to use a fairly large amount of drag. Drag both smooths out input, and essentially recenters the velocity of a rigidbody back towards zero. The problems with this are many. It makes things feel like they’re moving through molasses. It mucks with the effect of gravity on a rigidbody. Drag should be present in atmospheric situations, but I’ve found that a ‘realistic’ amount of it for say.. a large sphere, is close to 0.1, whereas the Null Op demo I produced half-a-year ago needed a drag of 1.0-1.5 to be stable/controllable.
The Why Of Things
So, you might be thinking at this point, “why build a system of this complexity when you’re not making a combat game?”. I would answer that question with the following ramble.
I think one of the reasons why, when doing high-fidelity 3D games, that we fall into centralizing around mechanics of shooting is that we as a game developer culture have simply put the most time into exploring that mechanic space. The largest bank of design work has been DONE around the gun. There’s so very much nuance between the way a rifle feels between Counter-strike, Battlefield, COD, Halo, etc. Anyone who plays shooters (I’ve played them all. Trust me I understand the possible irony of working on this project, and my position on things, when I still play CS:GO every damn day) can wax poetic about the subtle differences in aim interpolation, recoil, bullet simulation, impact, damage, hitboxes, the list goes on and on.
And so to work on a shooter means that the palette of proven design methods to chose from is staggering in size. It’s not just that you’re drawing on an existing player control literacy, you’re drawing upon an existing possibility space for movement and shooting, designed and engineered by some of the MOST capable folk in the industry. I find this space in and of itself sooo tempting to riff of as a designer, especially having been a child of the shooter era, weened on Descent, Doom, Wolfenstein, Rise of the Triad, Chex Quest (lol don’t judge, it was actually good), and the like.
But, herein lies the problem. This imbalance in collective… shall we say.. capital ‘P’ Progress of design in game mechanics is hindering our ability to broaden the scope of our favored genres in the 3d space. Let’s take Elite Dangerous, Star Citizen, and No Man’s Sky as examples here. They look FUCKIN GORGEOUS. They possess robust simulations of space craft that you can fly. They have (or will have) giant universes to explore… filled with things to commit violent actions against.
Personal note: Adding trading to your game does not make it less violent/aggressive. Embodying Capitalism through play is just another way of role-playing an individual who through ideology and action seizes power for themselves relative to others within a game-space.
Anywho, what I’m trying to say is that we have a set of mechanics and design logic to draw on here (historically) that are almost entirely about DOMINANCE. And this is largely due to the fact that we haven’t worked the other muscles well enough. We need a ‘Don’t skip Leg day’ equivalent for game-designers, where we put the exuberance and meticulous thought that has built our church-of-the-simulated-gun into filling out other aspects of the simulatory space.
We know this can be done. Rockstar adds more an more interesting activities within their simulations with each game. Portal and Portal 2 show that there’s still so much more that we can get out of rigid-body physics systems. The indie-game EXPLOSION that’s happened over the past 3 or 4 years has demonstrated that there is soooo very much to do with platforming space that’s conducive to high-skill-ceilings.
So with all that in mind, I’m approaching the process of designing my ‘ship’ (quotes because the player ‘identity’ is not yet set in stone) with an eye for simulatory complexity. I want to create a system that rewards patience, while still being more accessible than say… a straight flight simulator. Call it the ethic of a flight sim with the feel and punch of a more arcadey game. Complex but not opaque. Subtle but not onerously futzy. I know it’s going to take a ton of iteration, and what I end up with may be a niche taste. But its the type of system I want to expand upon right now, and will be one of many by the time this project is out of my system.
What’s Currently Working
So now that we’ve gone over the constraints that I’m designing in, let’s talk about what’s currently working. All of these systems are still very much works in progress, but they’re all far enough along that I can say that I’m committed to their current implementations, and they’re all talking to one another quite nicely.
Independent Linear and Angular Thrusters
Linear thrusters are in-line with the center of mass of the ship while angular thrusters are perpendicular to their displacement from the center. They each have a set of about 30 exposed parameters for thrust capability, vfx, procedural animation, etc.
Hierarchical Damage Connection System
I’ll be covering this one in its own blog post, as it’s a beast and something I’ve been fighting with for going on 3 years now on and off. Suffice it to say for now that the flight prototype I’m currently working on now is a network of ~170 individual pieces, each with their own collider. They are ‘held’ together via a connection system, wherein each piece has knowledge of its connections, and a global hierarchy manager tracks whether any group of pieces is no longer connected to the root via some quick flood-fill checking. Collision damage that severs a piece from the ship also passes ‘excess’ force along the connection network, akin to a car crumpling. Thus a high-velocity collision that only causes physical contact with a single component can actually cause catastrophic damage.
Fly-by wire Thrust System
And now, the most complex part of things, and easily the most important. The general concept of a fly-by-wire system (within a purely simulated context), is that instead of mapping the input directly from the player into something that provides force/thrust/etc., one or more intermediary layers exist to interpret that input relative to how the ship/plane/etc. is currently moving.
The early experiments I did in using ‘real’ thrust for my Null Op ships were quite disastrously uncontrollable. The reason for this is that well… stable flight is hard, enough so that near constant adjustment is needed to keep a craft fighting gravity through linear-thrusters aloft without spinning out of control. Just look at the Harrier Jet. *cough*
This system as I have it currently implemented works via the following steps:
Step 1 – The player (or AI computer) input comes in as a set of Vector3s with each axis being in the -1 to 1 range. These vectors are _not_ normalized. Note that when this input is coming from player joysticks/360 controller, the input is squared, as this tends to produce far more controllable results for fine movements while preserving top-out points.
Step 2 – This input is then transformed by an internal representation of desired maximum thrust along linear and angular axes (in the case of my current test ship, this is heavily biased in the forward direction, more like a jet fighter or missile). This is where some general tuning is done to determine how much thrust the system is asking of the ship’s thrusters (independent of their capability).
Step 3 – This ‘desired thrust’ is then compared to the current relative velocity of the ship at this frame. This output vector, let’s call it ‘target thrust’, is what is then used for all following thrust calculations.
Step 4 – The thruster array is pinged with the target thrust, with each thruster reporting back how much thrust it could theoretically contribute to the effort. This is based on upon angle, thruster output power, current condition, and proximity to surfaces (simulating the thrust over-pressure effect).
Step 5 – The results of the ping are collated, and relevant thrusters are then sent the command to fire at certain percentage of their output strength in unison.
Interesting Effects From It All Actually Working
You feel the effect of a fly-by-wire system the most when one removes one’s hands from the controller immediately after having been flying quickly. Thrusters immediately jump into action to slow you back down to stationary to the best of their ability. In my current testing ship this takes a number of seconds as the main thrusters are about 5x more powerful than the retro-thrusters.
This is one of the system features I was hoping would develop emergently and I’m super pleased that it has. Basically, in the same way that the ship is way more capable of thrusting in certain directions, it is by the same token more or less capable of counter-thrusting in certain directions. This adds significant nuance to maneuvering at high speeds, and a high skill ceiling for control virtuosity. It also means that a vtol craft like my current prototype can hold itself in the air when upright, almost do so when on its side, and plummet to the ground when upside-down.
As seen in this video of Darpa’s creepy smart missile, retaining flight stability when compensating for gravity, and dealing with the inherent asymmetries of turbulence/air pressure means that thrusters fire frequently and twitchilly during static flight. This effect occurred emergently in my system (which made me absurdly pleased when it happened for the first time). It did however immediately make me realize i need to tone down the intensity of the light emission on the thrusters so as to be less seizure-inducing.
So, if you’d like to check out the current flight demo here’s a link:
Windows Machine with Core i5+ cpu
Mid-range Discrete GPU or better
Xbox 360 Controller
Before you load it up, make sure to check out my control overview video here. Note that this video was recorded with my intertial-camera shake system disabled by accident. The actual build is a touch more… volatile 🙂
I’ll be talking about the damage system I’ve been working on and where related systems are going. Cya then!