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.
- Create a Plane at position (0, 0, 0) to act as the ground.
- Create a Cube at position (0, 0.5, 0) — this is your player.
- Give the Cube a distinct colour (create a new Material and assign it) so you can identify it easily.
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.
- 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
void FixedUpdate() {
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
Vector3 movement = new Vector3(h, 0, v);
rb.velocity = movement * speed;
}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.
- Use the player cube from Task 1 (or create a new one if you skipped it).
- Create 4–5 Sphere objects scattered across the ground plane.
- Give the spheres a bright colour (e.g., yellow) and scale them down to (0.5, 0.5, 0.5).
- Add the tag Collectible in the Tag Manager (Edit → Project Settings → Tags and Layers), then assign it to all spheres.
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.
- 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
private int collectCount = 0;
void OnTriggerEnter(Collider other) {
if (other.CompareTag("Collectible")) {
collectCount++;
Debug.Log("Collected: " + collectCount);
Destroy(other.gameObject);
}
}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.
- Create a Capsule in the scene. Give it a red Material. This is your enemy template.
- Drag the Capsule from the Hierarchy into the Project window (Assets folder) to create a Prefab.
- Delete the Capsule from the scene — you'll spawn it via script.
- Create an empty GameObject named "Spawner" and position it at the centre of your ground plane.
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.
- 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)
[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);
}
}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.
- You need a UI text element on screen. You'll create this through the Unity menu system — look under GameObject → UI.
- Position the text in the top-left corner of the screen.
- Set the default text to "Score: 0" and make the font large enough to read easily (at least size 32).
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.
- "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
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;
}
}
}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.
- Create a UI Text element (TextMeshPro) in the top-right corner of the screen. This displays the remaining time.
- 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.
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.
- 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
[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();
}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. |