Welcome to CodeBench
Five short coding problems to test what you really know about Unity game programming. The questions get progressively harder and target the specific concepts that separate beginners from intermediate game developers. Take your time — wrong answers come with explanations.
Frame-Rate Independent Movement
Problem
You're writing a script to move an enemy forward at exactly 5 units per second, regardless of whether the game runs at 30 FPS or 144 FPS. Which expression correctly fills the blank?
void Update() { // Fill in the blank to move 5 units/sec forward transform.position += ________________; }
Time.deltaTime is the number of seconds since the last frame — multiplying by it converts "per frame" into "per second."
Why this matters
Without Time.deltaTime, your enemy moves the same distance every frame. If the game runs at 60 FPS, that's 5 × 60 = 300 units per second. At 30 FPS, it's 150 units per second. The same script behaves completely differently depending on hardware.
Multiplying by Time.deltaTime means "5 units × (seconds per frame)" — which works out to exactly 5 units per second regardless of frame rate. This is the most common beginner bug in Unity.
The exception: when you're using Rigidbody.MovePosition() in FixedUpdate(), the physics engine already handles fixed timing — you don't need Time.deltaTime in that case.
MonoBehaviour Lifecycle Order
Problem
The script below is attached to an active GameObject and the script is enabled. What is the order of the first letters printed to the Console? Type your answer as four letters with no spaces or punctuation (e.g., ASUE).
void Awake() { Debug.Log("A"); } void Start() { Debug.Log("S"); } void Update() { Debug.Log("U"); } void OnEnable() { Debug.Log("E"); }
Why this matters
The correct order is AESU: Awake → OnEnable → Start → Update.
Knowing this order tells you where to put your setup code:
- Awake — cache your own components (
GetComponenton yourself). Safe even when the GameObject is inactive. - OnEnable — subscribe to events. Pairs with
OnDisablefor cleanup. - Start — access OTHER objects. All other Awakes have already run, so their references are ready.
- Update — runs every frame thereafter.
Putting GameManager.Instance.AddScore(...) in Awake can fail because the GameManager's Awake may not have run yet — but the same call in Start is safe.
Complete the Coroutine
Problem
Complete the coroutine so the GameObject is destroyed exactly 3 seconds after the coroutine starts. Type only the missing line of code (the one that goes where the dashes are).
IEnumerator DestroyAfterDelay() { ________________________________ Destroy(gameObject); }
3, 3f, and 3.0f are acceptable.yield return statement. Unity provides a special object that, when yielded, pauses the coroutine for a number of seconds. Its name describes exactly what it does.
Why this matters
The answer is yield return new WaitForSeconds(3);
Coroutines are Unity's way of writing time-based logic without blocking the main thread or creating new threads. When the coroutine hits yield return new WaitForSeconds(3), it:
- Pauses the coroutine right at that line
- Lets
Update()and every other script keep running normally - Resumes 3 in-game seconds later, on the next available frame
Important distinction: WaitForSeconds respects Time.timeScale — pausing the game with Time.timeScale = 0 also pauses the coroutine. Use WaitForSecondsRealtime when you need real wall-clock time (e.g., timers in a pause menu).
To actually run the coroutine, you need StartCoroutine(DestroyAfterDelay()) somewhere in your code — typically in Start() or in response to an event.
The Phantom Death Bug
Problem
The enemy script below should run its death sequence once when health reaches zero. But your QA team reports that the death sound plays multiple times per kill and the score sometimes increments by 30 or 40 instead of 10. The script compiles without errors. Why?
public class Enemy : MonoBehaviour { public float health = 100; [SerializeField] private AudioClip deathSound; void Update() { if (health <= 0) { AudioSource.PlayClipAtPoint(deathSound, transform.position); GameManager.Instance.AddScore(10); Destroy(gameObject); } } }
Destroy(). The keyword you're looking for is "deferred" — when exactly does the object actually disappear?
Why this matters
Destroy(gameObject) doesn't remove the GameObject immediately. Unity schedules it for the end of the current frame (after all Update() calls finish on every script). Until then, the GameObject is still alive — and so is its Update().
If health is at 0 when the if-block runs, it's still 0 the next time Update() runs on the same frame's late updates, and on the start of the next frame before the actual removal. The whole block fires multiple times.
The fix — a guard flag:
private bool isDying = false; void Update() { if (health <= 0 && !isDying) { isDying = true; AudioSource.PlayClipAtPoint(deathSound, transform.position); GameManager.Instance.AddScore(10); Destroy(gameObject); } }
This same pattern (a bool guard) solves a huge class of "executed too many times" bugs — projectiles hitting multiple targets in one frame, triggers firing repeatedly, coroutines stacking on themselves. Recognising it is a hallmark of an intermediate game programmer.
Enemy Vision Cone
Problem
You're writing the AI for a stealth game. A guard can see the player if both:
- The player is within
viewRangeunits of the guard, AND - The player is within
fieldOfViewdegrees of the guard'sforwarddirection (where a 90° FOV means 45° to each side).
Which implementation is correct?
public bool CanSeePlayer(Transform guard, Vector3 playerPos, float viewRange, float fieldOfView) { Vector3 toPlayer = playerPos - guard.position; // Which return statement is correct? }
Vector3.Angle() returns the unsigned angle (0–180°). Think about: if my FOV is 90°, the player can be at most 45° to either side of forward. So the angle from forward must be at most...?
Why this matters
The correct answer is A. Let's see why the others fail:
- B uses
||(OR). The player would be "seen" if EITHER condition holds — so a player 1000 units away but directly in front would be "seen." The angle test also forgets to halve the FOV. - C uses
Dot > 0which only checks if the player is in front of the guard at all — even at 89.9° to the side. It ignores the FOV constraint entirely. - D compares an arbitrary X coordinate (
guard.forward.x == toPlayer.x) — meaningless geometrically. Floating-point equality also rarely holds.
Why A works:
magnitudegives the length oftoPlayer— which is the distance from guard to player.Vector3.Angle(a, b)returns the unsigned angle (0–180°) between two vectors, regardless of direction.- Dividing the FOV by 2 is essential. A "90° vision cone" means 45° to the left AND 45° to the right of forward. The angle from forward to player must be ≤ half the FOV.
&&(AND) requires both conditions to be true — exactly the spec.
Real-world upgrade: A complete AI also raycasts from guard to player and rejects the sighting if a wall is in the way. The vision cone is the cheap broad-phase check; the raycast is the expensive narrow-phase check. Doing them in that order saves performance.
Bench Complete
You've worked through the full set. Whatever your score, every problem here is the kind of thing you'll hit in real Unity projects — getting them wrong now means you get them right when they matter.