Design of Software Module Architecture for VR Games
VR game written without planned architecture becomes untouched minefield by third month. All classes know about all classes, XR Origin directly calls GameManager, which pulls AudioManager, which for some reason stores Player reference — and when trying add second platform support entire construction needs rewrite from scratch.
VR adds specific problems to general architecture: multiple input sources (left controller, right, hand tracking, gaze), platform-dependent APIs (OpenXR vs OVR vs SteamVR), strict framerate requirements, need isolate platform code from game logic.
Key architectural decisions for VR
Input abstraction — first and most important decision. If game logic directly works with OVRInput.Get(OVRInput.Button.PrimaryIndexTrigger), porting to another platform requires fixing every input location. Right approach: Input Abstraction Layer — interface IXRInputProvider with methods GetGripAxis(), GetTriggerAxis(), GetPrimary2DAxis(), separate implementations for each platform/SDK. Game logic knows only interface.
In Unity natively supported through OpenXR + Input System: InputActionAsset with bindings for different devices, InputAction with callbacks. One InputActionAsset with two binding paths works on any OpenXR-compatible platform without extra code.
Interaction System — second key layer. XR Interaction Toolkit provides IXRInteractable and IXRInteractor interfaces, but for complex projects insufficient. Need custom event system: InteractionEventBus with typed events (GrabStarted, GrabEnded, HoverEntered, ActivatePerformed) and subscription without direct dependencies.
State Machine for player state — mandatory in VR due specific states: Grounded, Teleporting, InMenu, GrabbingObject, UsingTool. Without explicit state machine these scattered across bool flags and conflict.
Modular structure of VR project
Working modular architecture for Unity VR project:
Core — platform-independent interfaces: IXRInputProvider, ILocomotionController, IHapticController, IHandTrackingProvider. No Unity or XR-specific dependencies, only C# interfaces.
Platform — Core implementations: OculusInputProvider, OpenXRInputProvider, SteamVRInputProvider. Platform code concentrated here. Bootstrap component at scene start determines active platform and registers implementations through Dependency Injection (Zenject or custom IoC).
XR — interaction logic: XRInteractionManager, HandPresenceController, GrabSystem, LocomotionSystem. Works through Core interfaces, unaware of specific platforms.
Gameplay — game logic: mechanics, progression, AI, saves. Works through XR layer events, unaware of XR directly.
UI — game interfaces through World Space Canvas + UGUI or custom spatial UI. Doesn't address Gameplay directly — only through events or ViewModel pattern.
Such division allows testing Gameplay logic through Unity Test Framework without XR session — through mock Core implementations.
Performance as architectural constraint
In VR every architectural decision evaluated through performance lens. 90 fps — 11 ms frame budget. Patterns harmless in regular games kill framerate in VR:
FindObjectOfType<T>() in Update — full scene scan every frame. In VR scene with 500+ objects easily 2–3 ms.
C# allocations in hot path — GC pauses noticeable in VR because dropped frame is not just "stutters", it's motion sickness trigger. In Update/FixedUpdate — zero allocations, everything through object pools and struct-based events.
Synchronous operations in main thread — resource loading, network requests. In VR everything async: AddressableAssets.LoadAssetAsync, async/await with proper synchronization context.
Job System and DOTS for VR projects with many physics objects or NPCs — not just optimization, architectural requirement. IJobParallelFor for vectorizable calculations unloads main thread 30–50% typical scenarios.
| Volume | Timeline |
|---|---|
| MVP architecture (one platform, 3–5 modules) | 1–2 weeks |
| Multiplatform architecture (3+ SDK) | 3–4 weeks |
| Full architecture with multiplayer and save system | 4–6 weeks |
Design includes documentation, dependency diagrams and proof-of-concept implementation of critical modules. Cost calculated after requirements analysis.





