• Nicholas Eckstein

Started working on a new puzzle game



A couple weeks ago, I started working on a new puzzle game in my free time. I had planned on taking the pipe minigame that you might have seen before either by itself or as a minigame in larger titles, which involves rotating pipes in a grid, to connect an input to an output. I decided I wanted to add more movement mechanics though. So I added a setting to the tile object to determine how the player can interact with it. Some tiles will be static, in that they cannot move. Other's will rotate like before. Some will be able to slide around. And other's can be picked up and placed on any available spot. The next change I wanted to make to this was to add a pump mechanic. Somewhere in the pipe network, there needs to be a pump tile, with a specific input and output. If the wrong end is hooked up to the water source, it won't count as a win. The next change is a power mechanic. The pump needs to be powered somehow. For this I added nodes to some tiles, which can have wires connected to them.

The final change was to have different grids of tiles interact with each other. This way I could apply the movement mechanics to entire grids themselves, so they could be moved around a larger grid. (see video for example)

How it started

Honestly development has been very smooth. I mean it's not an overly complicated game, but even taking that into consideration, it has been actually very smooth sailing.


The first thing I did was create the movement mechanics for the tiles. To do this I wrote 5 coroutines:

Rise: Lerps tile to current position but, 1 unit away from grid.

Lower: Lerps to current position but back to 0.1 units from grid.

Slide: Slide to position. Stop if one of the corners hits overlaps a tile coordinate occupied by another tile.

Glide: Just like slide, but don't care about collisions.

Rotate: Rotate in place 90 degrees.

Next I used those coroutines to "script" different interactions.

When a tile set to rotate is clicked, it plays the rise coroutine, then rotate, then lower.

Sliding tiles, only slide, but when the player releases the tile, it will glide to the nearest coordinate.

Pickup tiles will play the rise coroutine, then glide to mouse position, until the mouse is released, then it will glide to the closest open grid slot, and lower.


Next I added pipes. Again not very difficult. The hardest part was just taking rotations into account. Each pipe on the tile has a list of "openings". Each opening can either have a set forced connection that will never change, or a direction using an enum called Side { NONE, BOTTOM, RIGHT, TOP, LEFT }. When the pipes check their connections, if forcedConnection is null, it will try to find a tile in the direction specified. The "sides" are local space. So "TOP" may mean bottom, if the tile is rotated 180 degrees. All this means, is to find what tile a pipe is facing based on it's side variable, instead of doing something like this:

neighborTile = coord;

if (side == Side.RIGHT)


neighborTile = coord.x + 1;


You would do this instead

if (side == Side.RIGHT)


neighborTile = coord + tile.transform.right


Of course after I added the ability to rotated entire grids, that changed to this:

if (side == Side.RIGHT)


neighborTile = coord + tile.GridSystem.transform.InverseTransformVector(tile.transform.right).normalized;


Water Pathfinding

I wanted the option to have multiple water sources/outlets, along with branching pipes. I didn't want the water coming from one source to be able to solve to water outlets, so used generic A* pathfinding class I wrote for another game to find the fastest route from the pump's input to the nearest water source, and the pump's output to the nearest water outlet. If both succeed, I keep the path and add some player feedback to show a path was found.


I actually wrote the class previously for a game I was working on with a friend to allow for enemy pathfinding. Luckily I had this game in my mind, and knew I would need to have water pathfinding, so I wrote it as a generic class. It can take any object, as long as you also pass a function for determining the object's connections, and a function to determine if to instances are equal. You then pass a starting node, and a goal node, and it will take it from there. It worked for the AI in that other game, and it worked perfectly with the pipe's in this game. I love it when things just work on the first go.

Power network

The power system was a easier than the pipe network, because it didn't need rotation math, or even care where things were in the grid. (I will in the future, when I limit the lengths of the wires)

I created a new prefab and script called PowerNode, and PowerWire. Power nodes could be added to tiles, and they could hold up to a specific number of wires (specified in the editor on a per node basis).

They then had 2 booleans. "Is this a power source?" and "Is this a power user".

Next I used the same A* algorithm to pathfind through the wire network from power users to power sources.

Lastly I added a setting to the pump so that a powerNode reference could be given, in which case the pump would only work, if the given powerNode was powered.

Also bonus: I was sick of wiring nodes manually when editing test levels, so I wrote a custom Window script, that allows me to click 2 nodes, check if the wire is locked to either or both sides, then click "Save Connection" or "Remove Connection" and it would spawn in a wire, and setup all the references automatically.

How it's going

I knew I wanted the game to be in 3D, but up until now, I've been working in 2D because I just didn't know how I wanted to implement it. My first thought was maybe, the player could be a plumber for hire. But I didn't think that would be very interesting. Not to mention the setting always being in a dark basement seemed kind of boring. The other option I could think of was having the pipe grids be on panels spread throughout a sort of abstract level, but that would be straying a bit to close to the Witness, which while a great game, I would rather be a bit more original.

I asked my friend who's a game designer, how I should go about converting this game to 3D, and he mentioned being able to move around the actual grids themselves and using the pipes to unlock doors. I thought that was a great idea

I'm still not quite sure how I will do this, but I think I'm landing on a sort of abstract Cube (the film) game. This might end up being a bit to close to Portal, but only theme. Still I will try to be careful to not get to close to portal's themes. (Also I won't have a faceless voice talking to you so that should help).

Converting to 3D

Converting this to 3D with a first person camera was incredibly easy. I already had most of the transformations happening in the grid's local space (aside from a few instances where I wrote the global position/rotation/scale by mistake). The only thing that really needed changing was changing the mouse to be a raycast to click. After that, the game was in 3D.


The most recent thing I have done, was add the ability to move around grids themselves like the tiles. To do this, all I had to do was add the tile components to the grid themselves, then add the grids to a larger grid. Then to get the pipes to be able to connect to neighboring grids, I would just have them check if the tile they are pointing towards is out of bounds for the current grid. If so, they would check if a parent grid exists. If one exists, it would then convert the small local coords it was checking, into world position, then have the big grid, convert that world position, into it's big coords. If it found a neighboring grid at that location, it would then convert that world position again, but this time into the neighbor grid's coords. If a pipe was found, the normal check would occur to see if their sides match up (taking into account the rotation of the pipes' tiles and grids.

And that's what I have so far. Now that most of the base things are done, I can start building levels. I still don't know too much about how I want the game to look and play, but I feel really good about how things are going so far.

Thank you for reading this post!

3 views0 comments