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.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
How to Make a Game Like Monument Valley
35 mins
- Getting Started
- Setting up the Game View
- Discovering Penrose Triangles
- Adjusting Camera and Lighting
- Fixing Seams
- Shifting Screen Z
- Adding Level Geometry
- Building Platforms
- Bridging the Gap
- Using Layers With the Camera Stack
- Using Layers
- Creating the Camera Stack
- Adding a Graph, Nodes and Edges
- Exploring Nodes and Edges
- Adding the Graph
- Connecting Edges Manually
- Setting the Goal Node
- Starting Pathfinding
- Clicking Input
- Controlling the Player
- Animating the Player
- Holding out Geometry
- Visualizing the Clicks
- Building Impossible Paths
- Linking the Bridge Rotation
- Adding Node Events
- Completing the Game Manager
- Where to Go From Here?
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
The PlayerCamera view will now look like this:
The LevelCamera view will now look like this:
Bridge, HorizontalPlatform, VerticalPlatform, StairsPlatform, and LJoint10 should use Layer 9: Level. Assign those and, again, choose Yes, Change Children for each.
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.
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.
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.
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.
Under the Box6 transform, for example, select the Node6 child GameObject. Note that the numerical suffixes match the Node with the corresponding Box tile.