The Setup
Task 01 β XR Grab Interaction with Haptic Feedback
Implement a custom GrabbableObject MonoBehaviour using XR Interaction Toolkit's XRGrabInteractable. On grab: trigger a short sharp haptic pulse (0.8 amplitude, 0.1s). On release: trigger a lighter fade pulse (0.3 amplitude, 0.08s). Highlight the object's material on hover. Handle the edge case where the controller loses tracking mid-grab without throwing a NullReferenceException.
Cursor produced a well-structured GrabbableObject class in about 6 minutes. It correctly subscribed to selectEntered and selectExited events and used SendHapticImpulse on the XRBaseController. The hover highlight used a material swap β functional, though I'd use a shader property in production. The tracking loss guard was where it fell short: AI added a null check on the interactor but not on the controller reference itself, meaning a tracking dropout mid-grab would still throw.
Riya's implementation took 28 minutes β she spent time reading the XRI Toolkit docs for the haptic API, which she hadn't used before. Her null guard was complete: she checked both the interactor cast and the controller reference separately. She also unsubscribed from events in OnDisable β something the AI completely missed, which would cause ghost event callbacks after the object is disabled or destroyed.
Task 1 verdict: AI wins on speed but introduces a real XR-specific bug. Missing the OnDisable event unsubscription is something I see frequently from developers who are new to Unity's event system β and it means the haptic callback will fire even after the GameObject is disabled or pooled. In a shipped XR app, this causes hard-to-reproduce bugs that only surface when the object lifecycle is stressed. Riya thought about lifecycle. The AI didn't.
Task 02 β Debug a Broken Coroutine Scene Load
Given a broken Unity scene management script with three intentional bugs: (1) a coroutine that starts before AsyncOperation is complete β a timing bug that surfaces only on slower devices, (2) an AR Foundation ARSession reference that's not null-checked when tracking is temporarily lost, causing a crash on resume, and (3) a DontDestroyOnLoad manager that gets duplicated on scene reload because it's missing the singleton guard. Time to identify and fix all three.
Bug 3 (the singleton duplicate) was caught almost instantly β Cursor recognised the pattern immediately and suggested the standard instance guard. Bug 2 (the AR tracking null ref) was partially caught: Cursor flagged the reference but suggested wrapping it in a generic try/catch rather than properly checking ARSession.state. Bug 1 was never found. The async timing issue only manifests on devices slower than the editor β AI had no way to reason about the hardware timing context, and the code was syntactically valid. After 4 prompts describing the symptom ("sometimes loads before async is done"), Cursor kept suggesting adding a yield return null in the wrong place.
Riya tested in the editor first, then specifically asked me: "Is this expected to run on mobile? Because some of these timings look editor-only." That question alone was worth the whole experiment β she'd been burned by async timing differences between editor and device before. She correctly replaced the bare yield return asyncOp with a while (!asyncOp.isDone) loop. Bug 2 she fixed properly using ARSession.state comparison rather than a try/catch. All three found. Time: 32 minutes.
The coroutine timing bug only manifests on device, not in the editor β because the Unity Editor runs on a machine fast enough to complete the async operation before the next frame. On an older Android phone, it crashes on every load. AI cannot reason about this class of bug because it has no concept of the hardware execution context. Riya asked the right question: "Is this for mobile?" That question unlocks the entire debugging path. AI never asks it. This is the gap that matters most in XR development, where editor behaviour and device behaviour routinely diverge in exactly these timing-sensitive scenarios.
Task 03 β Unity EditorTests for a Spatial Math Utility
Given a 90-line SpatialMath static class with 5 methods: a world-to-local transform converter, a smoothed quaternion lerp (using Slerp with a configurable speed), a bounds-overlap checker for XR colliders, an angle-between-vectors utility, and a function that snaps a Vector3 to the nearest point on a plane. Write Unity EditorTests covering all 5 functions with meaningful edge cases. Target: zero test failures on first run.
This was AI's best task. Cursor produced the full test suite in 7 minutes, structured with NUnit [TestFixture] and clear [Test] attributes. It correctly used Assert.That(..., Is.EqualTo(...).Within(0.001f)) for float comparisons β a Unity-specific gotcha that many junior devs miss. Edge cases were solid: identity quaternions, zero-length vectors, degenerate plane normals. One miss: the bounds-overlap test used new Bounds() without a size, creating a zero-size bounds that always returns false β making the test trivially pass rather than actually testing the function.
Riya took 26 minutes and wrote more descriptive test names β the kind that tell you exactly what failed when CI goes red at 2am. Her bounds test was correct: she constructed a proper Bounds with explicit center and size. She also tested the Slerp function at t=0 and t=1 boundary conditions β the AI only tested midpoint interpolation. One miss: she forgot to test the plane-snap function with a degenerate (zero-length) normal, which the AI had caught.
The AI's zero-size Bounds test is a subtle but important failure: it wrote a test that passes without actually testing anything meaningful. This class of mistake β tests that pass regardless of the implementation β is harder to catch than a failing test because everything appears green. It's a Unity-specific variant of a general AI testing pattern: AI optimises for tests that don't fail, not for tests that are genuinely meaningful. Always read AI-generated test assertions, not just the test names.
Aggregate Numbers
π The Scorecard
π The Honest Verdict
This is the largest margin of any battle in the series so far: 39 vs 30. The gap is wider than logo design or caption writing because Unity XR development has a layer of complexity that AI tools currently handle very poorly β the gap between editor behaviour and device behaviour.
In 13 years of XR development, I've seen this specific class of bug cause more production issues than almost anything else. Coroutines that work perfectly in the editor but crash on a mid-tier Android. AR tracking states that behave differently depending on whether the session was paused or freshly initialised. Haptic callbacks that fire on destroyed objects because nobody called RemoveListener in OnDisable. None of these are syntax errors β they're hardware-context errors, and AI has no hardware context.
Riya's instinct to ask "Is this for mobile?" before even looking at the coroutine bug was worth more than any amount of syntactic pattern-matching. That question comes from being burned by the same issue on a real device. AI doesn't get burned. It doesn't have a shipped product that crashed at a client demo. That experiential knowledge is not in any training dataset.
Speed remains AI's only clear win. 35 minutes vs 86 minutes across 3 tasks is significant, and for scaffolding, boilerplate, and initial structure, AI is genuinely faster. But in XR specifically, fast scaffolding with broken lifecycle management can make things slower overall β because you're debugging on device, which is the slowest possible feedback loop.
π How I Actually Use AI in My Unity Workflow
AI for structure, human judgment for lifecycle and device
I use Copilot every day in my Unity work. Here's exactly where I let it lead and where I take over:
With this workflow, AI saves me approximately 40β50% of feature development time β primarily on scaffolding, boilerplate, and test writing. The parts I still write manually are the parts that have burned me on real shipped projects: lifecycle management, AR state handling, and anything that behaves differently on device vs editor.
When to use each approach in Unity XR
- Scaffolding a new MonoBehaviour or ScriptableObject
- Setting up XRI event wiring and initial field declarations
- Generating EditorTests for pure logic / math utilities
- Converting C# patterns between Unity versions
- Writing shader property wrappers and material helpers
- OnDisable / OnDestroy / event unsubscription β always
- Any coroutine involving async scene operations on device
- AR Foundation tracking state and session lifecycle
- Haptic, audio, and visual feedback β needs tuning on device
- Any bug that only manifests on hardware, not in editor
Series tally after 3 battles
Human wins all three: Logo Design (39 vs 32), Instagram Captions (37.4 vs 35.8), Unity Coding (39 vs 30). The coding battle produced the widest margin β not because AI is bad at Unity, but because Unity XR development has a class of hardware-context bugs that sit completely outside what LLMs can reason about. The pattern across all three battles remains consistent: AI wins when the task is well-defined and lives entirely in a single context. Human wins when the task requires reasoning about a context the AI has never experienced β a real brand, a specific audience, a device that crashes differently than the editor.