Skip to main content

โœจ Lesson 11.4: Polishing a 2D Scene (Mini-Project)

This is where the whole 2D track comes together. You have a working platformer from Module 10, an animated hero from Lessons 11.1โ€“11.2, and lighting from 11.3. Now you'll layer on the polish that separates a prototype from a game people feel: parallax backgrounds, a lit tilemap, an animated sprite character, particles, and post-processing. One atmospheric level, built from parts you already own.

๐ŸŽฏ Learning Objectives

By the end of this mini-project, you will be able to:

  • Build a parallax background from layers that scroll at different speeds
  • Combine a lit tilemap, an animated hero, and lights into one cohesive scene
  • Add particle touches (dust, sparks, floating motes) for life and depth
  • Apply URP post-processing (Bloom, Vignette, Color Adjustments) with a Global Volume
  • Work through a repeatable polish checklist you can reuse on any 2D scene

Estimated Time: 50 minutes  ยท  Prerequisite: Lessons 11.1โ€“11.3 and the Module 10 platformer

In This Lesson

The Goal: From Flat to Atmospheric

Your Module 10 platformer works โ€” the hero runs, jumps, and collides with a tilemap. But it probably looks flat: a single background, even lighting, no sense of depth or mood. Polish is the art of adding a handful of cheap, high-impact touches that make a scene feel like a place.

We'll assemble it in layers, back to front: a parallax sky, a lit tilemap world, the animated hero, particle atmosphere, and a post-processing grade over the whole thing. Here's how those layers stack:

Parallax layer stack with 2D lighting A side view of a 2D scene built from stacked layers. Far back is a night sky with a moon, moving slowest. In front, distant hills move a little faster. Then a mid-ground tree line. Then the foreground tilemap ground where a character stands, lit by a warm spot light casting a glow. Arrows show each layer scrolling at a different speed, slowest at the back and fastest at the front. A dashed camera frustum sits at the right. 1 ยท Sky (slowest) 2 ยท Far hills 3 ยท Tree line 4 ยท Ground + hero (fastest) Camera
Figure 1: The layered parallax scene. Back layers scroll slower than front layers as the camera moves, creating the illusion of depth. A warm spot light and floating particle motes add atmosphere over the lit tilemap ground.

Parallax Backgrounds

Parallax is the effect where distant things appear to move slower than close things โ€” look out a moving car window and the far hills crawl while the roadside blurs past. In 2D you fake it by putting each background layer on its own object and scrolling it a fraction of the camera's movement.

Set up several layers (sky, hills, trees) on separate sorting layers, then drive each with a small script. Using the new Input System-driven camera from earlier modules, the parallax reads the camera's position each frame:

using UnityEngine;

// Attach to each background layer. Lower parallaxFactor = further away = slower.
public class ParallaxLayer : MonoBehaviour
{
    [SerializeField, Range(0f, 1f)] float parallaxFactor = 0.5f;

    Transform cam;
    Vector3 previousCamPos;

    void Start()
    {
        cam = Camera.main.transform;
        previousCamPos = cam.position;
    }

    void LateUpdate()
    {
        // how far the camera moved since last frame
        Vector3 delta = cam.position - previousCamPos;

        // move this layer a fraction of that โ€” nearer layers use a bigger factor
        transform.position += new Vector3(delta.x * parallaxFactor, delta.y * parallaxFactor, 0f);

        previousCamPos = cam.position;
    }
}

Give the sky a parallaxFactor near 0.1, the hills ~0.4, the tree line ~0.7, and leave the gameplay layer at 1 (it moves with the world). Run in LateUpdate so the layers move after the camera has finished following the player โ€” otherwise you get jitter.

โœ… Pro Tip

For endless scrolling, make each layer's sprite tileable and duplicate it twice side by side; when the camera passes one copy's edge, snap it ahead of the other. Two tiles are enough to cover any horizontal travel.

A Lit Tilemap Scene

Your Module 10 platformer already uses a Tilemap for the ground. To make it respond to your Lesson 11.3 lights, its tiles need to render lit: assign a material using the Sprite-Lit-Default shader to the Tilemap Renderer (or ensure the tile sprites use a lit material). Now your Global and Spot lights fall on the terrain, not just the character.

  • Drop the animated hero (from Lessons 11.1โ€“11.2) into the scene on the gameplay sorting layer.
  • Add a Global Light 2D at low intensity for a night mood, plus a warm Spot/Point light following the hero as a lantern.
  • Give a few foreground tiles or pillars a Shadow Caster 2D so the lantern throws shadows across the ground.

Sorting layers matter here: background parallax layers behind the tilemap, the tilemap and hero in the middle, and any foreground silhouette layer in front. Lights can target specific sorting layers if you want the background unlit and only the play area lit.

๐Ÿ’ก Callback: the hero's Animator is the same state machine from Module 1 and Lesson 11.1 โ€” Speed drives Idle โ‡„ Run, a Jump trigger fires the jump. Polishing the scene doesn't touch that logic; you're dressing the stage the character already performs on.

Particles for Life

A still scene feels dead; a little constant motion sells "living world." Unity's Particle System (GameObject โ–ธ Effects โ–ธ Particle System) is perfect for cheap atmosphere:

  • Floating motes / dust โ€” a wide emitter, tiny slow particles drifting upward, low emission rate. Instant "dusty cave" or "magical forest."
  • Landing dust โ€” a short burst emitted from the hero's feet when they land (trigger it from your landing code).
  • Sparks / embers โ€” small additive particles near torches, glowing because their material uses an additive blend.

Keep counts low โ€” a few dozen particles read as atmosphere; thousands tank performance (a topic for Module 12). Set the Particle System's Renderer โ–ธ Material to a lit or additive sprite material so it matches your lighting.

โš ๏ธ Particles have a sorting order too

If your dust vanishes behind the tilemap, set the Particle System Renderer's Sorting Layer and Order in Layer so it draws in front of the ground but behind the UI. 2D particles obey the same sorting rules as sprites.

Post-Processing

Post-processing grades the entire rendered image after everything is drawn โ€” the final layer of polish. In URP it's driven by a Volume. Add GameObject โ–ธ Volume โ–ธ Global Volume, create a new Volume Profile, and add overrides:

  • Bloom โ€” makes bright areas glow softly. This is what makes your lanterns, sparks, and glowing gems feel luminous. The single highest-impact effect for a lit 2D scene.
  • Vignette โ€” darkens the screen edges, focusing the eye on the center and adding drama.
  • Color Adjustments โ€” shift the whole scene's temperature and contrast. Cool it blue for night, warm it amber for sunset.

Make sure your Camera has Post Processing ticked in its Inspector, or the Volume does nothing. For 2D, Bloom needs some pixels above the bloom threshold โ€” which is exactly what an Additive light or bright particle provides.

๐Ÿ“– Definition

Volume: a URP object holding a stack of post-processing overrides. A Global Volume affects the whole scene; local Volumes with colliders affect only when the camera enters them (e.g. a spooky grade inside a cave). Priority decides which wins when they overlap.

The Polish Checklist

Here's a repeatable order of operations for polishing any 2D scene. Work back-to-front and top-down, checking as you go:

flowchart TD A["Start: working but flat scene"] --> B["Parallax layers
(sky โ†’ hills โ†’ trees)"] B --> C["Lit tilemap
(Sprite-Lit material)"] C --> D["Lights
(Global base + accent Spot/Point)"] D --> E["Animated hero in place
(same Animator as Module 1)"] E --> F["Shadows
(Shadow Caster 2D on props)"] F --> G["Particles
(dust, sparks, motes)"] G --> H["Post-processing Volume
(Bloom โ†’ Vignette โ†’ Color)"] H --> I["Play, tune intensities,
ship it โœจ"]

Figure 2: The 2D polish checklist. Each step is optional and cheap on its own; together they transform a prototype into an atmosphere.

โœ… Pro Tip

Polish last, and tune with the game running. Enter Play mode and adjust light intensity, bloom, and vignette live until it feels right โ€” then note the values and set them back in Edit mode (Play-mode changes revert on Stop).

Mini-Project: Polish the Platformer

๐Ÿ—๏ธ Build: An atmospheric night level

Objective: Take your Module 10 platformer and run it through the full polish checklist to produce one moody, lit, living level.

  1. Parallax: add at least three background layers (sky, hills, trees) with a ParallaxLayer script and factors ~0.1 / 0.4 / 0.7. Confirm depth as the camera follows the hero.
  2. Lit tilemap: switch the Tilemap Renderer to a Sprite-Lit material.
  3. Lights: add a dim Global Light 2D and a warm Spot/Point lantern that follows the hero.
  4. Hero: drop in your animated sprite character; verify the Animator's Speed/Jump still drive it.
  5. Shadows: add Shadow Caster 2D to two or three props; enable Shadows on the lantern.
  6. Particles: add slow floating motes across the scene and a landing-dust burst on the hero.
  7. Post: add a Global Volume with Bloom, Vignette, and a cool Color Adjustments grade. Tick Post Processing on the Camera.
๐Ÿ’ก Hint: it looks busy / muddy, not atmospheric

Less is more. Pull the Global Light down, keep only one strong accent light, lower particle counts to a few dozen, and ease off Bloom until only the true light sources glow. Atmosphere comes from contrast, not from adding more of everything.

โœ… Success check

The camera follows the hero with visible parallax depth; the tilemap and hero are lit by a warm lantern that casts moving shadows; dust drifts through the light; and the whole image has a cohesive graded, gently glowing look. It reads as a place, not a test scene.

๐ŸŽฏ Quick Quiz

Question 1: For a convincing parallax effect, how should a distant sky layer move relative to the foreground?

Question 2: Which post-processing override most makes lanterns and sparks feel luminous?

Question 3: Why run the parallax movement in LateUpdate?

Summary

๐ŸŽ‰ Key Takeaways

  • Parallax scrolls background layers at fractions of the camera's movement โ€” slower = further away โ€” for cheap depth. Run it in LateUpdate.
  • A lit tilemap needs a Sprite-Lit material so your Lesson 11.3 lights fall on the terrain, not just the hero.
  • Particles (dust, sparks, motes) add life; keep counts low and mind their sorting layer.
  • Post-processing via a Global Volume โ€” Bloom, Vignette, Color Adjustments โ€” grades the final image; enable Post Processing on the Camera.
  • Follow the polish checklist back-to-front, tune live in Play mode, and remember: atmosphere is contrast, not clutter.
  • Everything sits on the same animated hero and Animator you built in Module 1 and Lesson 11.1 โ€” polish dresses the stage, it doesn't rebuild the actor.

๐Ÿš€ What's Next?

Your 2D world now looks the part. But parallax scripts, particles, and post-processing all cost performance โ€” and eventually something will stutter. In Lesson 12.1: Profiling: Finding Bottlenecks you'll open the Profiler and learn to measure exactly where your frames are going, so your beautiful scene also runs smoothly.

โœจ You built an atmosphere

Parallax, lighting, particles, and a post grade turned a working prototype into a place with mood. That's the entire 2D track โ€” animation, lighting, and polish โ€” standing together in one scene.