Week 10 — Pre-Tutorial Activity

Micro-Tasks

Five small, independent challenges that test whether you can build from scratch — not follow instructions. Open Unity, create a new empty scene, and work through each task. Use the graduated hints only if you're stuck.

How This Works Each task tells you what to build and how to verify it works. It does not tell you how to build it — that's the test. If you get stuck, open the hints one at a time. Hint 1 is a gentle nudge. Hint 2 is more specific. Hint 3 gives you near-complete guidance. Try to use as few hints as possible.
Before You Start Create a new Unity 3D project (or a new empty Scene in an existing project). Use the built-in Render Pipeline. Each task is independent — you can do them in any order, and each can exist in the same scene.
1
Player Movement
~10 minutes
Objective

Create a player cube that moves on the ground plane using WASD or arrow keys. Movement must be physics-based (not transform-based) so the object interacts correctly with other colliders.

Scene Setup
  1. Create a Plane at position (0, 0, 0) to act as the ground.
  2. Create a Cube at position (0, 0.5, 0) — this is your player.
  3. Give the Cube a distinct colour (create a new Material and assign it) so you can identify it easily.
Requirements

Write a C# script called PlayerMovement that reads input every frame and moves the cube via physics. The player should move at a configurable speed that you can adjust in the Inspector.

Success Criteria
  • Pressing W/Up moves the cube forward (positive Z direction)
  • Pressing S/Down moves the cube backward (negative Z direction)
  • Pressing A/Left and D/Right moves left and right on the X axis
  • Movement is smooth and frame-rate independent (doesn't jitter or teleport)
  • You can change the speed value in the Inspector without editing code
Hints (use only if stuck)
Hint 1 — Nudge Think about what component enables physics-based movement. You'll need to add it to the cube, get a reference to it in your script, and apply velocity or force inside the correct update method (not Update).
Hint 2 — Direction Add a Rigidbody to the cube. In your script, use Input.GetAxis("Horizontal") and Input.GetAxis("Vertical") to get input values between -1 and 1. Build a Vector3 from these and apply it in FixedUpdate.
Hint 3 — Near-Solution Your FixedUpdate should look roughly like this:
void FixedUpdate() { float h = Input.GetAxis("Horizontal"); float v = Input.GetAxis("Vertical"); Vector3 movement = new Vector3(h, 0, v); rb.velocity = movement * speed; }
Cache your Rigidbody reference in Start() or Awake() using GetComponent<Rigidbody>(). The speed field should be public or marked with [SerializeField].
2
Collectible Pickup
~10 minutes
Objective

Create collectible objects that the player can pick up by moving into them. When the player touches a collectible, it should disappear. You must use triggers (not physical collisions) so the player passes through them smoothly.

Scene Setup
  1. Use the player cube from Task 1 (or create a new one if you skipped it).
  2. Create 4–5 Sphere objects scattered across the ground plane.
  3. Give the spheres a bright colour (e.g., yellow) and scale them down to (0.5, 0.5, 0.5).
  4. Add the tag Collectible in the Tag Manager (Edit → Project Settings → Tags and Layers), then assign it to all spheres.
Requirements

Write a C# script called PlayerCollector that detects when the player enters a collectible's trigger zone and destroys the collectible. Keep a count of how many have been collected and print it to the Console.

Success Criteria
  • Moving the player into a sphere makes the sphere disappear
  • The player does not bounce off or get stopped by the spheres
  • The Console shows an updated count each time a collectible is picked up (e.g., "Collected: 3")
  • Only objects tagged "Collectible" are affected — other objects are ignored
Hints (use only if stuck)
Hint 1 — Nudge For the player to pass through the spheres instead of bouncing off, the sphere's Collider needs to be configured as a trigger. There's a checkbox on the Collider component for this. The detection callback has "Trigger" in its method name.
Hint 2 — Direction On each sphere: tick Is Trigger on the Sphere Collider. On your player script, implement OnTriggerEnter(Collider other). Inside it, check the tag with other.CompareTag("Collectible"). Remember to destroy the entire GameObject, not just the collider.
Hint 3 — Near-Solution
private int collectCount = 0; void OnTriggerEnter(Collider other) { if (other.CompareTag("Collectible")) { collectCount++; Debug.Log("Collected: " + collectCount); Destroy(other.gameObject); } }
This script goes on the player. The critical detail: Destroy(other.gameObject) not Destroy(other) — the latter only removes the Collider component.
3
Enemy Spawner
~15 minutes
Objective

Create a spawner that automatically creates enemy objects at random positions on the ground every 2 seconds. This requires you to make a Prefab and use a Coroutine.

Scene Setup
  1. Create a Capsule in the scene. Give it a red Material. This is your enemy template.
  2. Drag the Capsule from the Hierarchy into the Project window (Assets folder) to create a Prefab.
  3. Delete the Capsule from the scene — you'll spawn it via script.
  4. Create an empty GameObject named "Spawner" and position it at the centre of your ground plane.
Requirements

Write a C# script called EnemySpawner and attach it to the Spawner object. It should repeatedly spawn clones of the enemy Prefab at random positions within a 10×10 unit area centred on the spawner, with a 2-second interval between spawns. The Prefab reference must be assignable in the Inspector.

Success Criteria
  • Red capsules appear in the scene automatically when you press Play
  • A new enemy spawns roughly every 2 seconds
  • Each enemy appears at a different, random position on the ground plane
  • You can see the clones appearing in the Hierarchy as children or root objects
  • The enemy Prefab field is assigned via drag-and-drop in the Inspector (not hard-coded)
Hints (use only if stuck)
Hint 1 — Nudge You need a way to repeatedly do something with a delay. Unity has a built-in mechanism for this that uses IEnumerator and yield return. You also need a way to generate random numbers for the X and Z position.
Hint 2 — Direction Start a coroutine in Start() using StartCoroutine(). Inside the coroutine, use a while(true) loop that calls Instantiate and then yield return new WaitForSeconds(2f). For random positions, use Random.Range(-5f, 5f) for X and Z, keeping Y fixed at ground level (e.g., 1f for the capsule's half-height).
Hint 3 — Near-Solution
[SerializeField] private GameObject enemyPrefab; void Start() { StartCoroutine(SpawnLoop()); } IEnumerator SpawnLoop() { while (true) { float x = Random.Range(-5f, 5f); float z = Random.Range(-5f, 5f); Vector3 pos = new Vector3(x, 1f, z); Instantiate(enemyPrefab, pos, Quaternion.identity); yield return new WaitForSeconds(2f); } }
Don't forget to drag the enemy Prefab from the Project window onto the enemyPrefab slot in the Inspector.
4
UI Score Display
~10 minutes
Objective

Display a score on screen using Unity's UI system. The score should increase by 1 every time the player presses the Space key. This task tests whether you can set up a Canvas, create a UI Text element, and update it from a script.

Scene Setup
  1. You need a UI text element on screen. You'll create this through the Unity menu system — look under GameObject → UI.
  2. Position the text in the top-left corner of the screen.
  3. Set the default text to "Score: 0" and make the font large enough to read easily (at least size 32).
Requirements

Write a C# script called ScoreManager. It should hold a reference to the UI text element, track the current score as an integer, and update the displayed text every time the player presses Space. Attach the script to any suitable GameObject.

Success Criteria
  • "Score: 0" is visible on screen when the game starts
  • Pressing Space increases the displayed number by 1 each press
  • Holding Space does not rapidly increase the score — it only counts distinct presses
  • The text stays anchored to the top-left regardless of screen resolution
Hints (use only if stuck)
Hint 1 — Nudge You need to decide whether to use the legacy Text component (requires using UnityEngine.UI;) or TextMeshProUGUI (requires using TMPro;). Either works. To anchor to the top-left, look at the anchor presets in the RectTransform component.
Hint 2 — Direction Create a UI → Text - TextMeshPro (Unity will auto-create a Canvas and EventSystem). Click the anchor presets square in RectTransform and choose top-left. In your script, store a reference to the TMP_Text component and use Input.GetKeyDown(KeyCode.Space) to detect single presses. Update the text with string concatenation or interpolation.
Hint 3 — Near-Solution
using TMPro; using UnityEngine; public class ScoreManager : MonoBehaviour { [SerializeField] private TMP_Text scoreText; private int score = 0; void Update() { if (Input.GetKeyDown(KeyCode.Space)) { score++; scoreText.text = "Score: " + score; } } }
Drag the TextMeshPro object from the Hierarchy into the scoreText field in the Inspector. Use GetKeyDown (not GetKey) to prevent rapid-fire counting.
5
Countdown Timer + Game Over
~15 minutes
Objective

Display a countdown timer on screen that starts at 30 seconds and counts down to zero. When the timer hits zero, show a "Time's Up!" message in the centre of the screen and stop the game clock. This task combines UI, time tracking, and game state management.

Scene Setup
  1. Create a UI Text element (TextMeshPro) in the top-right corner of the screen. This displays the remaining time.
  2. Create a second UI Text element centred on the screen. Set its text to "Time's Up!" and make it large (font size 60+). Disable this GameObject — it starts hidden.
Requirements

Write a C# script called GameTimer. It should count down from 30 seconds (configurable in Inspector), update the timer display every frame showing whole seconds remaining, and when the timer reaches zero: enable the "Time's Up!" text and set Time.timeScale = 0f to freeze the game.

Success Criteria
  • Timer starts at "30" and counts down one number per second
  • Timer shows whole seconds only (no decimals)
  • When the timer reaches 0, "Time's Up!" appears in the centre of the screen
  • After time runs out, all game movement freezes (physics, spawning, everything stops)
  • The starting time can be changed in the Inspector without editing code
Hints (use only if stuck)
Hint 1 — Nudge You can track remaining time as a float and subtract Time.deltaTime each frame. To display whole seconds, think about a method that rounds up or truncates to an integer. To freeze the game, Unity has a property that controls the speed of the game clock globally.
Hint 2 — Direction In Update(), subtract Time.deltaTime from your timer float. Use Mathf.CeilToInt() to convert it to a whole number for display. When the value reaches zero, use SetActive(true) on the "Time's Up!" text object and set Time.timeScale = 0f. You'll need two [SerializeField] references: one for each text element.
Hint 3 — Near-Solution
[SerializeField] private TMP_Text timerText; [SerializeField] private GameObject gameOverUI; [SerializeField] private float startTime = 30f; private float timeRemaining; private bool isGameOver = false; void Start() { timeRemaining = startTime; gameOverUI.SetActive(false); } void Update() { if (isGameOver) return; timeRemaining -= Time.deltaTime; if (timeRemaining <= 0f) { timeRemaining = 0f; isGameOver = true; gameOverUI.SetActive(true); Time.timeScale = 0f; } timerText.text = Mathf.CeilToInt(timeRemaining).ToString(); }
Remember to set Time.timeScale = 1f before entering Play mode if you've previously frozen it — Unity remembers the last value. The "Time's Up!" GameObject should start disabled in the Inspector.
Self-Assessment
Reflect on your performance before starting the Week 10 tutorial

After completing (or attempting) all five tasks, honestly assess yourself:

Completed Without Hints What It Means
5 tasks Excellent. You can build independently. The Week 10 tutorial should feel comfortable.
3–4 tasks Solid foundation. Review the areas where you needed hints — those are your weak spots.
1–2 tasks You can follow tutorials but struggle to build from scratch. Revisit Weeks 1–4 material and practice recreating those projects without the instructions.
0 tasks The fundamentals haven't stuck yet. Schedule time to revisit the early tutorials and focus on understanding why each step works, not just copying it.