Float precision issues is something you always know is out there, but something you rarely need to pay any thought to. As you can guess, it’s an issue we ran into. When making a build, one of our puzzles involving a rotating platform would seemingly work, but not fire the event it was suppose to at the end of it’s movement. Not firing this event essentially locked the entire puzzle as the player was not able to rotate the platform into any of the states required to proceed.

After a lot of debugging and generally tearing our hair out, me and Kenth finally found the cause of the issue. To keep track of what rotation (and if it had reached its destination) the delta rotation was calculated and then added to a variable each frame, simply:

It turns out, in this particular case, the value calculated by Unitys SmoothDampAngle got below the Epsilon value at high framerates. What this means in practice is that the value got so small enough for it to more or less equal zero, making it completely useless.

The way we resolved this issue is to simply check if whether value of actualRotationDelta is less than the Epsilon and if we’re close to the rotation we’re rotating to. This is not a optimal solution but considering the time constraints we had it was the simplest to implement.

So, the original plan was to post weekly video logs, but holy smokes we’ve been busy. The entire team has been working a whole load more than full time for the last weeks to get all the features in game… and we did it, We’re feature complete!

There’s still a lot of content missing and things work in progress but all the important features are in, most importantly all of the 5 initial robots have been implemented and all their 6 combinations (fusions) are almost fully functional.

Here’s some screenshots to show of our progress, as you can tell, a lot has been going on in the art department. We’re sticking to showing the same two robots for now, as the textures are still WIP on the others.

That’s all for update, as mentioned above we’ve been working as crazy to get stuff done, and we’ll keep at it. The future of the video logs are kinda uncertain at the moment, if we find time we’ll do some new ones but finding any spare time is unlikely at this point. Luckily though, we’ve got a trailer planned for release in two weeks!

Learning from the technical aspects of implementing puzzles and level events in CoBots, I was determined to come up with a solution for implementing the puzzles that generally would be easier to work with. The system had to fulfill the following requirements:

Easy to visualizeQuickly being able to grasp how things are tied together saves a lot of time in the long run and makes it a lot easier for someone else other than the initial author to grasp the system

Easily interchangeable prefabs
When working in a team on a project of this scope and on this timescale, rapid iteration is key. You should take this into consideration and design your tools to allow for it. Being able to easily switch out an entire object does just that.

Self contained and environment-unaware prefabs
What does that even mean? It ties into the point above, for the different puzzle components/prefabs to be easily interchangeable the different instances can’t be very specialized as it would force you to do a whole bunch of setup whenever you want to switch something out. It also mean that the prefabs themselves should not concern themselves with anything outside their own hierarchy.

Keep serialized references to a minimum
This further ties into the “interchangeable prefabs” point, to make that process as simple as possible, it’s easier if the references to a object is kept to a minimum. Also, Unity inspector object references is more or less an accident waiting to happen, something will happen which will magically break the reference connection for no apparent reason.

After giving it some thought and while taking all of the requirements above into consideration, the puzzle system that I came up consists of these three parts:

PuzzleTrigger
When activated, will send a predetermined event to the PuzzleManager. How it’s activated and what event is sent is determined by what sort of object it is.

PuzzleManager
Holds references to all of the PuzzleTriggers and PuzzleTargets. Will convey any events from PuzzleTrigger to all the registered PuzzleTargets.

PuzzleTarget
Listens to and acts upon events set up in the editor.

The different events that can be sent across the ‘network’ is simply an enum, containing generic, common events (ON, MOVING, IDLE, etc).. One compromise had to be made when it comes to the PuzzleTarget, you choose per instance what event act as activation and/or deactivation. This is because you often would like several different things affecting the same object but do different things.

Here’s a simple example of using the system. The lever and the door does not know of each others existence, not even at run-time. The PuzzleManager holds all the references and makes sure the event triggered by pulling the lever reaches the door.

Here’s the most complex use-case we’ve got for the system so far. It centers around a rotating platform which can be moved by several different levers. Each lever corresponds to a different rotational state and depending on what state it’s in, different doors are open.

It’s actually somewhat more complex than that, the player needs to move a minecart across the platform so the PuzzleManagers also manages which pieces of rail are currently connected. It also disables all the levers while the platform is moving, re-enabling them once it stops moving.

With all the green and yellow lines, at a glance it looks rather confusing, but while working with it all makes sense and is still somewhat clear. Admittedly, this case is more complex than the system was designed for, so some improvements can certainly be made. For example, some objects could be grouped together under a common manager if they activate/deactivate under the same circumstances.

I’m quite happy with this system as it achieved all the goals we set and stayed well clear of problems we’ve had with setting up puzzles previously.