ARTICLE

Building a Memory Game using Unity’s 2D Functionality

From Unity in Action, Third Edition by Joe Hocking

Take 35% off Unity in Action, Third Edition by entering fcchocking3 into the discount code box at checkout at manning.com.

You might be used to working with 3D graphics, but you can also work with 2D graphics in Unity. In this article, you’ll learn by building a 2D game. You’re going to develop the classic children’s game Memory: you’ll display a grid of card backs, reveal the card front when it’s clicked, and score matches. These mechanics cover the basics you need to know in order to develop 2D games in Unity.

Although Unity originated as a tool for 3D games, it’s used often for 2D games as well. Later versions of Unity (starting with version 4.3, released near the end of 2013) have added the ability to display 2D graphics, but even before then 2D games were already being developed in Unity (like mobile games that took advantage of Unity’s cross-platform nature). In prior versions of Unity, game developers required a third-party framework (such as 2D Toolkit from Unikron Software) to emulate 2D graphics within Unity’s 3D scenes. Eventually, the core editor and game engine were modified to incorporate 2D graphics, and this article teaches you about that newer functionality.

The 2D workflow in Unity is more or less the same as the workflow to develop a 3D game: import art assets, drag them into a scene, and write scripts to attach to the objects. The primary kind of art asset in 2D graphics is called a sprite.

DEFINITION: Sprites are 2D images displayed directly on the screen, as opposed to images displayed on the surface of 3D models (textures).

You can import 2D images into Unity as sprites in much the same way you can import images as textures. Technically, these sprites are objects in 3D space, but they’re flat surfaces oriented perpendicular to the Z-axis. Because they all face the same direction, you can point the camera straight at the sprites and players can only discern their movements along the X- and Y-axes (two dimensions).

Coordinate axes have three dimensions, which adds a Z-axis perpendicular to the X- and Y-axes. Two dimensions are those X- and Y-axes (this is what your teacher was talking about in math class!).

Setting everything up for 2D graphics

You’re going to create the classic game of Memory. For those unfamiliar with this game, a series of cards is dealt out facedown. Every card has a matching card located somewhere else, but the player can only see the reverse side of the card. The player can turn over two cards at a time, attempting to find matching cards; if the two cards chosen aren’t a match, they’ll flip back and then the player can guess again.

Figure 1 shows a mock-up of the game we’re going to build.

Figure 1 Mock-up of what the Memory game looks like

Note that the mock-up this time depicts exactly what the player sees (whereas the mock-up for a 3D scene depicts the space around the player and then where the camera goes for the player to see through). Now that you know what you’re building, it’s time to get to work!

Preparing the project

The first step is to gather up and display graphics for our game. In much the same way as building the 3D demo previously, you want to start the new game by putting together the minimum set of graphics for the game to operate, and after this is in place, you can start programming the functionality.

That means you’ll need to create everything depicted in figure 1: card backs for hidden cards, a series of card fronts for when they turn over, a score display in one corner, and a reset button in the opposite corner. We also need a background for the screen, and all together our art requirements sum up to figure 2.

Figure 2 Art assets required for the Memory game

TIP: As always, a finished version of the project, including all necessary art assets, can be downloaded from https://www.manning.com/books/unity-in-action-third-edition. You can copy the images from there to use in your own project.

Gather together the required images, and then create a new project in Unity. In the New Project window that comes up, you’ll notice project templates (shown in figure 3) that allows you switch between 2D and 3D mode. Because 3D graphics are the default value we haven’t been concerned with this setting. In this article, though, you’ll want to select the 2D template when creating a new project.

Figure 3 Create new projects in either 2D or 3D mode with these buttons.

2D Editor mode and 2D Scene view

The 2D/3D setting for new projects adjusts two different settings within Unity’s editor, both of which you can adjust manually later if you wish. Those two settings are the 2D Editor mode and the 2D Scene view. The 2D Scene view controls how the scene is displayed within Unity; toggle the 2D button along the top of the Scene view.

2D Scene view toggle

You set 2D Editor mode by opening the Edit menu and selecting Editor from the Project Settings drop-down menu. Within those settings, you can see the Default Behavior Mode setting with selections for either 3D or 2D.

Default Behavior Mode setting within Edit > Project Settings > Editor

Setting the editor to 2D mode causes imported images to be set to Sprite. Images normally import as textures, but this is easy to switch in the Inspector. Select the asset to see its settings, and remember to hit Apply after making any changes.

2D Editor mode also causes new scenes to lack the default 3D lighting setup; this lighting doesn’t harm 2D scenes, but it’s unnecessary. If you ever need to remove it manually, delete the directional light that comes with new scenes and turn off the skybox in the lighting window (click the tiny circle icon for a file picker and choose None from the list).

With the new project created and set for 2D, we can start putting our images into the scene.

Displaying 2D images (aka sprites)

Drag all the image files into the Project view to import them; make sure the images are imported as sprites and not textures. (This is automatic if the editor is set to 2D. Select an asset to see its import settings in the Inspector.) Now drag the table_top sprite (our background image) up from the Project view into the empty scene. As with mesh objects, in the Inspector there’s a Transform component for the sprite; type 0, 0, 5 to position the background image.

TIP: Another import setting to take note of is Pixels Per Unit. Because Unity was previously a 3D engine that had 2D graphics grafted in, one unit in Unity isn’t necessarily one pixel in the image. You could set the Pixels Per Unit setting to 1:1, but I recommend leaving it at the default of 100:1 (because the physics engine doesn’t work properly at 1:1, and the default is better for compatibility with others’ code).

Creating packed sprite atlases

Although we’re going to use separate images in this project, you can have multiple sprites laid out in a single image. The image is usually called a sprite sheet when numerous frames of an animation are combined into one image, but the more general term for multiple images combined into one is an atlas.

Animated sprites are common in 2D games. Multiple frames can be imported as multiple images, but games usually have all the frames of animation laid out in a sprite sheet; all the separate frames appear as a grid on one large image.

In addition to keeping frames of animation together, sprite atlases are also often used for still images. This is because atlases can optimize the performance of sprites in two ways: (1) by reducing the amount of wasted space in images by packing them tightly, and (2) by reducing the draw calls of the video card (every new image which is loaded causes a bit more work for the video card).

Sprite atlases can be created using external tools like TexturePacker (see appendix B) and that approach certainly works, but Unity includes sprite packing functionality, which packs together multiple sprites automatically. To use this feature, enable Sprite Packer in Editor settings (found under Edit > Project Settings; switch the Mode to Always Enabled). Now you can create Sprite Atlas assets that contain individual sprites. For more information, look at Unity’s documentation: https://docs.unity3d.com/Manual/SpriteAtlasWorkflow.html

The 0s for the X and Y positions are straightforward (this sprite fills the entire screen, and you want it at the center), but that 5 for the Z position might seem odd. For 2D graphics, shouldn’t only X and Y matter? Well, X and Y are the only coordinates that matter for positioning the object on the 2D screen; Z coordinates still matter for stacking objects. Lower Z values are closer to the camera, and sprites with lower Z values are displayed on top of other sprites (refer to figure 4). Accordingly, the background sprite should have the highest Z value. You’ll set your background to a positive Z position, and then give everything else a 0 or negative Z position.

Figure 4 How sprites stack along the Z-axis

Other sprites are positioned with values with up to two decimal places because of the Pixels Per Unit setting mentioned earlier. A ratio of 100:1 means that 100 pixels in the image are 1 unit in Unity; put another way, 1 pixel is .01 units, but before you put any more sprites into the scene, let’s set up the camera for this game.

Switching the camera to 2D mode

Now let’s adjust settings on the main camera in the scene. You might think that because the Scene view is set to 2D, what you see in Unity is what you’ll see in the game. Somewhat unintuitively, though, this isn’t the case.

WARNING: Whether or not the Scene view is set to 2D has nothing to do with the camera view in the running game.

It turns out that, regardless of whether the Scene view is set to 2D mode, the camera in the game is set independently. This can be handy in many situations that allow you to toggle the Scene view back to 3D in order to work on certain effects within the scene. This disconnect means that what you see in Unity isn’t necessarily what you see in the game, and it can be easy for beginners to forget this.

The most important camera setting to adjust is Projection. The camera projection is probably already correct because you created the new project in 2D mode, but this is still important to know about and worth double-checking. Select the camera in Hierarchy to show its settings in the Inspector, and then look for the Projection setting (see figure 5). For 3D graphics the setting should be Perspective, but for 2D graphics the camera projection should be Orthographic.

Figure 5 Camera settings to adjust for 2D graphics

DEFINITION: Orthographic is the term for a flat camera view that has no apparent perspective. This is the opposite of a Perspective camera, where closer objects appear larger and lines recede into the distance.

Although the Projection mode is the most important camera setting for 2D graphics, there are a few other settings for us to adjust as well. Next, we’ll look at Size; this setting is under Projection. The camera’s orthographic size determines the size of the camera view from the center of the screen up to the top of the screen; set Size to half the pixel dimensions of the screen you want. If you later set the resolution of the deployed game to the same pixel dimensions, you’ll get pixel-perfect graphics.

DEFINITION: Pixel-perfect means one pixel on the screen corresponds to one pixel in the image (otherwise, the video card makes the images subtly blurry as it scales up to fit the screen).

Let’s say you want a pixel-perfect 1024 x 768 screen. That means the camera height should be 384 pixels. Divide that by 100 (because of the pixels-to-units scale) and you get 3.84 for the camera size. Again, that math is SCREEN_SIZE / 2 / 100f (f as in float, rather than an int value). Given that the background image is 1024 x 768 (select the asset to check its dimensions), then clearly this value of 3.84 is what we want for our camera.

The remaining adjustments to make in the Inspector are the camera’s background color and Z position. As mentioned previously for sprites, higher Z positions are further away into the scene. As such, the camera should have a pretty low Z position; set the position of the camera to 0, 0, -100. Next make sure the camera’s Clear Flag is set to Solid Color instead of Skybox; this setting determines the camera background. The camera’s background color should probably be black; the default color is blue, and this looks odd displayed along the sides if the screen is wider than the background image (which is likely). Click the color swatch next to Background and set the color picker to black.

Now save the scene as Scene and hit Play; you’ll see the Game view filled with our tabletop sprite. As you saw, getting to this point wasn’t completely straightforward (again, this is because Unity was a 3D game engine that has recently had 2D graphics grafted in), and the tabletop is still completely bare. Next you should put card sprites into the scene, just as you did with the tabletop sprite.

That’s all for this article. If you want to learn more about the book, check it out on Manning’s liveBook platform here.

--

--

--

Follow Manning Publications on Medium for free content and exclusive discounts.

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Introduction to Kubernetes

How to build a free-forever website portfolio in 10 minutes

Use AWS-CLI to create the EBS volume and attach to instance

FirebaseUI: Adding Firebase Authentication into your Android App

Knife Write up

Setting Up Git with Atom on Windows (Udacity’s course companion)

Lessons learned from 1000 dotfile commits.

Serious mistakes that could have been avoided: lessons we can learn through software testing

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Manning Publications

Manning Publications

Follow Manning Publications on Medium for free content and exclusive discounts.

More from Medium

Day 30 of Game Dev: Creating a Heat Seeking Missile in Unity Part 2!

Create a queued item production interface in Unity/C#

Async programming vs Parallel programming (Basic)

TDD — Simple Demonstration in Kotlin