Losing the first version of this post due to webhosting problems kind of sucked.. it was looooong!
So, let’s see.. what have we been up to?
The lost post concerned all of the stuff we’ve added to the simulator; the two big-ticket items are conveyor-belts and moving platforms — both physics-driven, obviously. We actually ended up implementing both of them twice — once we had everything working the first time, we realized that the way we were modeling motors was totally screwed (it made it impossible to impose force limits on the motors), and so we ended up having to rewrite everything to use the new motor formulation. That was a time-waster.
On the plus side, we ended up also re-designing how constraint geometry (used to describe the belt and path shapes) is represented, and the second time around feels a lot better — for one thing, we can now support paths containing circular arcs! Anyway, conveyor belts and moving platforms work the way we want them to, so hooray.
We also worked out a new approach for friction using the new motors; unfortunately it isn’t working so well, so we’re probably going to revert to using the “old motor” version because it behaved nicely, even if it was “wrong” in terms of physical realism. Hopefully that will be the end of major functionality added to the simulator; stuff that we’ve overlooked will no doubt come up as we implement other parts of the game, and there’s of course about a hundred or more small items on the “to clean-up/maintenance” list, but things are looking pretty good as-is.
Post-website-crash, we’ve been working on the player’s “character controller”, which is all the code that describes how movement/etc works. Character control is actually one of the first things we mocked up when we started this project a couple years ago; our experiments used a simple ad-hoc physics model where only the player could move, but they were enough to convince us that what we wanted to achieve would be possible. Now that we’ve got a proper simulation working we’re ready to pick up where we left off and get the same sorts of movements happening in our more-fleshed-out simulation.
At this point it feels a lot like alchemy, in that we’re just brainstorming and trying all sorts of different ideas, hoping to stumble upon the “best” solution. It’s unclear whether or not there’s a better way to approach this — the player’s control logic is pretty much the core of any platformer, and there are an endless number of ways to program any of the various little behavioural nuances. For instance we’ve tried 3 or 4 different ways of limiting the player’s maximum velocity, each of which feels a bit different.
Considering the fact that changing one little piece tends to affect every other part of the damn thing, you quickly end up with an overwhelmingly complicated problem! Hence the sense of alchemy, not unlike blindly groping in the dark for something you think should be in the room.
Quite possibly there are some fundamental gaming principals at work here, but damned if we know what they are! We’re still waiting to read Game Feel 🙂
The real fear in trying to juggle all of these interacting minutia is that something important will fall through the cracks and be lost. For instance, a large part of what makes N work is the jumping model.
When you press jump in most platformers, you get something like [velocity.y = 10] — jumping results in the same upward velocity regardless of your current state. One of the first ideas we had was to try [velocity.y += 10], so rather than overriding your current velocity, jumping builds on it. This turned out to suck, because it meant that if you pressed jump while running downhill, you ended up with a very weak, or non-existent jump — your downward velocity would cancel out the jump’s upward velocity. But it suggested the obvious solution, which is what we ended up using: [velocity.y = Max(0, velocity.y) + 10]
So as it turns out, minutia matter. Occasionally, a whole lot.
Two things which we’re trying to do differently in Robotology, relative to other platformers, is to make the player’s shape feel “soft”, and to allow the player to move along arbitrarily-oriented surfaces (i.e player orientation is independent of gravity).
Both are things which have been done in more explicitly simulation-based games, like Elasto Mania, Gish, and Loco Roco, but we’re looking to meld that sort of movement and feeling with a more immediate, traditional-platformer type of control.
“Soft” player movement is something we’ve been experimenting with for a long time; one of our first webgame contracts years ago was for a skateboarding game that modeled the player’s internal body movement, with knees which would compress or extend based on the body’s inertia and the slope of the terrain — similar to how automobile suspensions are sometimes simulated. We’re hoping to extend this approach, so that the player can seamlessly move over varying terrain without slowing down or “bumping” into things as a rigid shape might, instead smoothly stepping up onto or over smaller obstacles. In fact, we have a nice prototype of this working, with the caveat that the player’s orientation is fixed “upright” along the world’s y-axis — which brings us to the second problem.
In N, as in most platformers, the various types of surface the player can move along are rigidly demarcated: floors are, well, floors; walls are perfectly vertical; and ceilings are anything that’s neither floor nor wall. The player interacts with each of the three discrete surface types in three corresponding ways: running and jumping on floors, walljumpings/wallsliding along walls, and passively colliding with ceilings.
The problem with such an approach is that it precludes allowing the player to run up vertical walls a-la parkour. While some platformers (Sonic, Silhouette Mirage) have allowed the player to run vertically or even along the ceiling, they’ve handled it in a very limited, rigidly-programmed way. We want our player to be able to run and jump along any surface — and any enemy — as if it was “the ground”, blurring the lines between walls, floors, and ceilings. Aside from enabling smoother, more acrobatic movement, this would also make features such as zero-gravity areas, or “magnetic boots” (which we’ve toyed with before in Ultramagnetic, a game which ended up lacklustre and so remains unreleased), trivial to support.
The problem becomes one of determining which direction is “down”, given information about the nearby geometry, the player’s current velocity, keyboard input, FSM state, etc.
Mario Galaxy does feature this sort of “magnetic boot” type behaviour, however the shapes Mario runs along are very “nice” — they tend to be static, convex, smooth, large/flat compared to Mario’s scale, etc — and they get by (as far as we can tell) with the rule “find the point on the world closest to Mario: down is in that direction”. This simple rule doesn’t work in the general case: closest points can jump all over the place, and there can be an arbitrary number of equidistant “closest points”, especially when you have dynamic concave shapes moving around. Most importantly, the shapes in MG are heavily authored and tested, which isn’t a viable solution for user-made or procedural content. Plus, the movement is very “Mario” rather than being based on the same underlying physics simulation as the rest of the game.
Anyway, our current problem is that the two behaviours we’re trying to produce — “soft” movement, and movement along arbitrary surfaces — are seemingly at odds with each other! Our prototype for soft movement only works well when the “down” direction is fixed to the world’s y-axis, and our running-up-walls prototype doesn’t like it when the player’s distance from the ground changes (as it is bound to do when the player is given “soft” bendable knees).
It’s quite a conundrum, but we’ve got a few theories; right now we’re working through them, and a few other problems that will be the topic of our next post.. which we’ll hopefully get to soon!