Creating Depth in a 2D World

Matt Buckley
Nice Things | iOS + Android Development
3 min readAug 21, 2018

Like this post? You might like BentoBlox too — check out the game here on the App Store.

Top-down 2D games share a recognizable approach to perspective. But playing with depth and shadow can give your top-down game a distinct visual style.

Adding a little depth to your 2D worth is easier than you think. In fact, it can be accomplished with a little bit of scripting using ordinary sprites. Here’s how:

First, import your sprite into Unity and drag it onto your scene.

Then create a new script, let’s call it SpriteShadow. This script will manage two SpriteRenderers (one for your sprite and another for its shadow). In SpriteShadow, create a few properties:

// the (x, y) offset of the shadow from the "subject" sprite
private Vector2 shadowOffset = new Vector2(-.1f, -.1f);
// the SpriteRenderer for the "shadow" sprite
private SpriteRenderer shadowSpriteRenderer;
// the SpriteRenderer for the sprite casting the shadow
private SpriteRenderer subjectSpriteRenderer;

Add additional properties to store the transform of your subject sprite and shadow sprite:

// shadow sprite transform
private Transform shadowTransform;
// subject sprite transform
private Transform subjectSpriteTransform;

In Start(), set subjectSpriteTransform to your gameObject's transform, and add shadowSpriteTransform as a child:

void Start()
{
subjectSpriteTransform = transform;
shadowTransform = new GameObject().transform;
shadowTransform.parent = subjectSpriteTransform;
}

Also in Start(), set the subjectSpriteRenderer and shadowSpriteRenderer (create your shadowSpriteRenderer programmatically):

void Start()
{
subjectSpriteTransform = transform;
shadowTransform = new GameObject().transform;
shadowTransform.parent = subjectSpriteTransform;
subjectSpriteRenderer = GetComponent<SpriteRenderer>();
shadowSpriteRenderer = shadowTransform.gameObject.AddComponent<SpriteRenderer>();
}

You’ll also want your shadow to display behind your subject. This is easy to accomplish in your script. This can be accomplished by decrementing its sorting order by 1. Just add:

shadowSpriteRenderer.sortingOrder =    subjectSpriteRenderer.sortingOrder - 1;

to your Start() method.

Now, if your sprite moves or animates during gameplay, you’ll want your sprite’s shadow to follow along. To make sure this happens, update your shadow’s sprite’s transform in LateUpdate(). Also in LateUpdate(), set your shadowSpriteRenderer's sprite to match your subjectSpriteRenderer's sprite. This ensures that your shadow will retain the shape of its subject:

void LateUpdate()
{
shadowTransform.position = new Vector2(subjectSpriteTransform.position.x + shadowOffset.x, subjectSpriteTransform.position.y + shadowOffset.y);
shadowSpriteRenderer.sprite = subjectSpriteRenderer.sprite;
}

The final thing you’ll want to do is add a material to your shadow sprite in order to make it black (or dark grey, whatever your shadow color of choice might be).

To accomplish this, add a property for such a Material, and make it visible to in the Unity editor:

[SerializeField]
private Material shadowMaterial;

Create a new Material in Unity, add a Shader to it to give it a solid black color, and drag your Material onto your sprite (shaders are beyond the scope of this post, click here for more information).

Press Play, and you’ll see an elegant, pixel-art-esque shadow below your sprite .

Like this post? You might like BentoBlox too — check out the game here on the App Store.

--

--