First of all, I figured out why the camera tended to jitter while moving up or down a pivoting platform. It turned out to be caused by the platform pivoting up into the player’s bounding box. The player’s motion code attempted to move the player and apply standing correction for platforms in the same step, and in this particular case, that would prevent the player from moving at full velocity. The solution was to change the algorithm to work like this:
- Check to see if the platform the player is standing on has moved since the last frame. If so, adjust the player’s Y coordinate to compensate.
- Attempt to apply the player’s X velocity, and adjust the player’s Y coordinate based on his new standing Y coordinate (for the new X coordinate).
- Attempt to apply the player’s Y velocity (falling/jumping).
The duplication of adjusting the player’s Y coordinate twice kind of sucks, but it fixes most of the glitches when moving on a rapidly pivoting surface, and it has the added benefit of making moving platforms work a bit better.
After solving that issue, I started working on implementing an actual puzzle using the level elements I’d built so far.
The first thing I needed to be able to construct an actual puzzle was the ability to attach level elements to each other in complex ways. To do that, I started working on extending the simple expression parser I had built earlier so that I could use it to link platforms, pressure plates, switches and doors together.
The approach I ended up using is similar to the one I was using before, but it’s more sophisticated. The expressions in my level data look like this:
<pivotPlatform id="platform1" a="8.5,11.5" b="12.5,12" minTilt="-3.25" maxTilt="3.25" tiltSpeed="0.065" tilt="plate1.State ? 1.0 : -1.0" /> <door id="door2" a="1.75,9" b="2.75,14" openDirection="0,1" state="switch1.State and switch2.State" />
Parsing the expressions and converting them into something the game can use at runtime is a multiple-step process. The first step is to convert the expression string into a stream of tokens. Right now, I’m doing this with a regular expression:
( (?'number' (-?) [0-9]+ (\.[0-9]+)? ) | (?'identifier' [_A-Za-z][A-Za-z0-9_]*) | (?'operator' <= | >= | != | [\-+/*&|^!><=.%?:]) | (?'paren' [()]) )
I apply this regex to the expression string and get a string of Match objects as a result, with named groups that determine the type of each token.
After that, I scan through the token stream and convert the tokens into function objects. Number tokens get converted into functions that return their values, like this:
public static ValueProxy MakeFloat (float value) {
return () => value;
Identifiers get transformed in a similar, though slightly more complex manner, in order to map them to the set of named objects in the level:
public static object MakeIdentifier (string identifier, NameResolver resolver) {
ValueProxy result = () => resolver(identifier);
The NameResolver in use here is defined elsewhere to map a string identifier to an element in the NamedObjects dictionary:
public Func<T> ParseExpression<T> (string expression) {
var resolveName = (NameResolver)((name) => this.NamedObjects[name]);
These two bits of code combined allow straightforward connections between named objects in a level, without having to pay attention to order of declaration or having to load a level in multiple passes.
Paren tokens are treated as a signal to the parser that a new subexpression has started. When I hit an open paren, I recurse into a new expression parser that runs until it hits a close paren, at which point it returns a function that can be evaluated to get the result of that subexpression. (I could have implemented this without recursion, but I’m too lazy.
)
Operator tokens get mapped to function objects based on the particular operator they represent. Most operators map to unary or binary operator functions that are predefined, like this:
case "^": return (BinaryOperator)( (lhs, rhs) => lhs.As<bool>() ^ rhs.As<bool>() ); case "!": return (PrefixOperator)( (rhs) => !rhs.As<bool>() ); case ">": return (BinaryOperator)( (lhs, rhs) => lhs.As<float>() > rhs.As<float>() );
(The one exception is the ternary operator, which has to be converted to two special ‘placeholder’ objects that a later stage of the expression parser translates into a single callable function.)
Once all the tokens have been converted, the final stage of the expression parser starts. This stage is fairly simplistic – it scans through the stream of converted tokens repeatedly, starting from the beginning each time, looking for operations that it can collapse into a callable function. For example, if it finds:
ValueProxy:2 BinaryOperator:+ ValueProxy:4
It knows that it can collapse that string of operations into a single new function, like this:
} else if (current is BinaryOperator && prev is ValueProxy && next is ValueProxy) {
stack.RemoveRange(i - 1, 3);
stack.Insert(i - 1, ApplyBinary(prev, current, next));
ApplyBinary takes an operator function and a pair of value proxy functions, and returns a new function that applies the operator to the two value proxies when invoked:
internal static ValueProxy ApplyBinary (object lhs, object binary, object rhs) {
var b = (BinaryOperator)binary;
var l = (ValueProxy)lhs;
var r = (ValueProxy)rhs;
return () => b(l, r);
This transformation is applied repeatedly to the stack until it contains a single ValueProxy representing the value of the entire expression. You might want to note that this approach doesn’t handle things like operator precedence, type safety, or type conversion – but I don’t currently need any of those things.
One particularly important detail is that I implemented a simple . operator that allows me to access fields and properties of named objects. This allows me to build more complex puzzles by having objects with multiple properties attached to them (for example, pressure plates have both a boolean State and a floating-point Depth). The way the dot operator works is fairly simple:
When the expression parser encounters a dot operator, it scans backwards one token and tries to grab an identifier. After that, it scans forward one token and tries to grab another identifier. If this fails, the expression is assumed to be invalid. At this point, the parser has a pair of identifiers, and the one on the left has already been resolved to point to a variable. The parser constructs a special function that will, when invoked, attempt to look up the value of a named property (the name is on the right) on the contents of the variable (on the left). Right now I do this with some reflection-based code, with a simple dictionary cache to mitigate the performance overhead of doing reflection at runtime by only performing a given reflection lookup once per variable/property pair.
With all this work done, I started experimenting with building a puzzle out of the primitives I already had: Pivoting platforms, switches, pressure plates and doors. As it turns out, being able to wall-jump off the side of a pivoting platform is actually pretty cool.
I’m still going to need to tune the physics some before these types of puzzles feel satisfying (it’s a bit hard to properly perform a wall-jump off the platforms due to how small they are, among other things), but I’m still pretty happy with how the puzzle turned out, considering how quickly I was able to assemble it.

