The Puzzle Manager

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 visualize
    Quickly 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.

Mechropolis_PuzzleManagerSimple

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.

Mechropolis_PuzzleManagerComplex

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.

New game in development!

After recovering from the haze that was CoBots development, we’re back with a new game, Mechropolis! It’s a first person action puzzle game set in what’s the remnants of a lost civilization. The only remaining sign of life are small rusty robots going about their business, long after whoever built has gone.

You need to overcome challenges by throwing them (the robots, that is) together to create new ones that will help you traverse the environment and overcome challenges. I made our first development log to show off how it works:

I’ve mainly focused on the level design so far and it’s coming along really nicely. The process we’re doing consists of me doing the basic level geometry in Unity using the ProBuilder plugin, this allows for quick creation of somewhat complex geometry, much like in the old days of the Radiant and Hammer editors, which is what I’m used too. It allows you to create a whole range customizable simple shapes, which can then be manipulated into basically anything.

Mechropolis_Cavern_1

After the greyboxing and layouting was finished, I started refining and preparing the level for detailing. An example of this are the rock walls seen in the screenshot above, they’re all pretty much flat throughout the entire cavern but have a whole bunch of vertices that can just be manipulated to give it that rock:y look (as on the right side in the screenshot).

Something I learnt a long time ago when doing similar work Radiant years ago was that you should have all terrain pieces of uniform resolution, this makes it a whole lot easier to stitch the different terrains together. Not stitching together them precisely is just a recipe for failure, you’ll have light leaks and the collision might be off causing characters to get stuck, not to mention how bad it’ll look.

The screenshots below shows 2 different pieces of terrain coming together, with all vertices along the edge lined up to avoid the problems listed above.

UnityTerrain

It can be tempting to do higher resolution terrains but in my experience it’s a whole load more pain than gain. When doing large scale manipulations it’s a hassle to deal with the amount of vertices that higher resolution produce and beyond a certain point the extra detail is negligible to the look.

I settled on 1 vertex per 3 meters as it’s a good middle ground, could have probably gotten away with lower resolution on the large walls but as there are intricate details on some parts (the ramp visible to the upper left for example) that need to be stitched together it’s just better to go with the same resolution overall.

Of course, there are times when you really need to transition between terrain resolution, but I try to keep these places far enough from the play-area so player(s) won’t notice any eventual flaws. As in the screenshot below:

UnityTerrain2

I’ve also coded a system for handling puzzles in their entirety (triggers, managers, and parts) but that’s the topic for a whole other post.