Search
  • Nicholas Eckstein

Started working on a new puzzle game

Demo

Intro

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.


Interactions

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.


Pipes

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:

if (side == Side.RIGHT)
{
    neighborTile = coord + Vector2int.Right;
}

You would do this instead:

if (side == Side.RIGHT)
{
    neighborTile = coord + tile.transform.right;
}

Of course after I added the ability to rotate 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 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.


A*

I wrote the A* class as a generic class so that 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. I made it so generic, so I could apply it to both the pipe network, and the power network. It ended up working perfectly for both. 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.


Multigrids

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.


VR

From the beginning, I wanted this game to be VR. Before I put in the time to make the game VR, I wanted to first make sure the puzzles were even interesting. Once I had implemented the main mechanics, I started work on adding the SteamVR plugin. Implementing the plugin was fairly straight forward. The only thing that needed changing was interactions. I already was treating the camera as basically a laser pointer, that used it's forward vector and rotation to interact with the tiles, so I just had to apply it to both controllers, and it just inherently worked right away. Amazing. Also the scale of the world is just so cool looking in vr. The tiles are massive. I can't wait to actually have a world I can explore, in this game!


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!

2 views0 comments

Recent Posts

See All