How to Make a Game Like Monument Valley

Learn to create a simple click-to-move game where you navigate a series of seemingly impossible platforms like in Monument Valley. By Wilmer Lin.

4.7 (20) · 2 Reviews

Download materials
Save for later
Share
You are currently viewing page 2 of 5 of this article. Click here to view the first page.

Bridging the Gap

Open the Scene view. Note the large physical gap between the HorizontalPlatform and the Bridge. That’s what you’ll be working with in this section.

scene view showing the large physical gap between sections that needs to be bridged.

Enter Play mode in the Editor, then hover your mouse over the SpinnerControl. The Highlighter component causes the SpinnerMesh to glow red. Clicking and dragging snaps the Bridge to 90-degree intervals.

Platforms with the spinner highlighted in red

Watch when the Bridge‘s X rotation reaches 90 degrees. Notice how Box10 appears to connect with Box15 in the Game view. In the Scene view, however, the gap remains.

Gap between platforms visible in the Scene view on the left, but obscured in the Game view on the right

Note: To better preview this effect, switch the Scene view from Perspective to Isometric.

You want the two platforms to appear seamless. But right now, when you look through the Main Camera you can see a shading error where the two platforms join.

section where platform and spinner appear to not connect

A small piece of geometry can conceal this region to repair the glitch, similar to the way you fixed the Penrose triangle in an earlier section.

Drag a new LJoint prefab into the Hierarchy. Set it’s Position to (X:7, Y:8, Z:-5) with a Rotation of (X:90, Y:-90, Z:0). To stay organized, rename it to LJoint10 to match Box10.

This conceals the break between Box10 and Box15.

Adjust the SpinnerControl in Play mode. The connection now appears seamless.

Platforms with no visible gap

Now, it’s time to introduce the character.

Using Layers With the Camera Stack

Adding a playable character on top of the level adds an unfortunate complication — the character doesn’t display properly because the draw order is incorrect.

Check this out by dragging the Player from Prefabs/Player into the Hierarchy. Position it at (X:-1, Y:0.5, Z:3).

Now, you can see that LJoint10 incorrectly obscures the Player‘s MeshRenderer.

Player character partially obscured by the platform its standing on

The holdout geometry needs to appear in front of the level. However, it also needs to render behind the Player. Tricky!

To solve this problem, you’ll use multiple cameras to adjust the draw order of meshes onscreen. Exit Play mode to get started.

Using Layers

The project already has several custom layers, which you’ll find in Layers ▸ Edit Layers…Tags and Layers. Select Layers ▸ Edit Layers… to confirm.

Next, check that User Layers 8 to 10 are labeled Background, Level and Player.

User Layers including the correctly-labeled 8, 9 and 10

Unity can use a camera stack to render multiple camera passes. This allows you to control the order of everything drawn onscreen.

To use this feature, start by cloning the MainCamera twice using Edit ▸ Duplicate.

Rename the clones to LevelCamera and PlayerCamera. Remove their AudioListener components.

Multiple Cameras in the Cameras section of the Hierarchy

Set the LevelCamera and the PlayerCamera to use RenderType: Overlay. The MainCamera should continue to use RenderType: Base.

Select the MainCamera and modify its CullingMask in the Rendering options. First, choose Everything for Culling Mask. Then, uncheck Level and Player. This camera will not draw those layers.

Main Camera Culling Mask with Player and Level deselected

In LevelCamera’s CullingMask, select Nothing and then select the Level layer. This camera will only render the Level layer.

Finally, in the PlayerCamera, select Nothing in the CullingMask and select the Player layer. This camera will only draw the game’s foreground elements.

Assign the Player to use Layer 10: Player. Select Yes, Change Children when prompted.

Player Layer

The PlayerCamera view will now look like this:

view of the player from PlayerCamera

The LevelCamera view will now look like this:

level camera game view

Bridge, HorizontalPlatform, VerticalPlatform, StairsPlatform, and LJoint10 should use Layer 9: Level. Assign those and, again, choose Yes, Change Children for each.

Level Layer

Confirm that you’ve already assigned the Backdrop to Layer 8: Background.

With those actions complete, it’s time to move on to creating the camera stack itself.

Creating the Camera Stack

Camera stacking is a common technique to composite rendered elements at runtime. You’ll use it here to add challenge to your game.

Select the LevelCamera or PlayerCamera. A thumbnail preview of their respective layers appears in the Scene view. However, only the Backdrop remains visible in the Game view. This is because you have not yet composited the cameras to form a stack yet.

Next, you’ll create a camera stack so all the cameras render together. Select MainCamera and, at the bottom of the Inspector, locate the Stack.

Click the + button to add the LevelCamera and PlayerCamera, in that order. Cameras at the bottom of the stack draw last.

Camera stack

Everything now appears in the Game view in the correct rendering order.

Enter Play mode to confirm the SpinnerControl still works. The Bridge forms a partial Penrose triangle with the other platforms.

Draw Order Fixed

Now, you need to connect the various platforms so the Player can cross the level.

Adding a Graph, Nodes and Edges

The level consists of several blocks and ramps to reach the final Goal at the top of StairsPlatform.

Unity’s built-in navigation system does not adapt easily to this game’s tile-based design. Instead, the project includes a custom pathfinding solution. This allows your character to move in discrete steps along the polygon faces.

Before you start building, take a moment to familiarize yourself with some terminology from graph theory:

  • A waypoint, or node, forms one unit of the path. It describes a three-dimensional location.
  • A node connects to its neighboring nodes with structures called edges.
  • The network of nodes forms a graph that describes the possible pathways through the maze.

Later in this tutorial, you’ll build a click-to-move controller to navigate this graph.

Exploring Nodes and Edges

If you’re already familiar with these concepts, open Node.cs and Edge.cs and familiarize yourself with those classes. Otherwise, here’s some background.

Nodes are simply three-dimensional points tracked by their transform.position. This implementation includes some options for visualization, like Gizmo size and color.

Node component

The helper Edge class allows a node to connect to its neighboring nodes. You can toggle each edge on and off, which will be useful later.

You won’t use some of the fields and methods, like PreviousNode, GameEvent and EnableEdge, until you dive deeper into the project. Set those aside for now, but don’t forget about them!

In the Hierarchy, each box that comprises HorizontalPlatform has a child transform with a Node component.

Hierarchy showing the Node6 component under Box6

Under the Box6 transform, for example, select the Node6 child GameObject. Note that the numerical suffixes match the Node with the corresponding Box tile.