Ultimate Glove Ball sample
Updated: May 10, 2026
This sample is a multiplayer VR sports game built with Unity Netcode for GameObjects and Photon Realtime. It demonstrates custom physics synchronization, Meta Avatars integration, asymmetric player/spectator roles, and social platform features including group presence and invites. The sample targets developers building networked VR experiences who want to see how Meta XR SDKs combine with third-party networking solutions in a production-ready architecture.
- Integrating Unity Netcode for GameObjects with Photon Realtime as a transport layer, including host migration and connection approval
- Implementing custom state synchronization for fast-moving physics objects using jitter buffers and client-side prediction
- Creating asymmetric multiplayer experiences with distinct player and spectator roles, input maps, and capacity limits
- Integrating Meta Avatars with networked gameplay, including multi-object avatar construction and LOD-based streaming
- Using Meta Platform SDK features including group presence, friend invites, join intents, user blocking, and in-app purchases
- Device: Meta Quest 2 or newer
- Development environment: Unity 6000.0.59f2 or newer
For detailed SDK versions, build prerequisites, and platform setup, see the sample README.
Clone the repository from GitHub and open the project in Unity 6000.0.59f2 or newer. The main entry point is the Startup.unity scene in Assets/UltimateGloveBall/Scenes/. For detailed build instructions including Photon configuration and platform entitlement setup, see the sample README.
The sample separates reusable multiplayer infrastructure from game-specific logic using a two-layer architecture. The Packages/com.meta.multiplayer.netcode-photon/ package provides networking, avatars, VoIP, and social features that you can adapt for other projects, while Assets/UltimateGloveBall/ implements the sports game logic on top of it.
| Scene / Script | What it demonstrates | Key concepts |
|---|
Startup.unity | Application entry point and platform initialization | Oculus Platform SDK entitlement check, Photon lobby connection |
MainMenu.unity | Matchmaking and social UI | Quick match, host match, watch match, friends list, store |
Arena.unity | Gameplay environment | Game phases, team assignment, ball spawning, scoring |
UGBApplication.cs | Application lifecycle singleton | Platform SDK init, group presence, join intent handling, IAP |
NetworkLayer.cs | Core networking state machine | Photon + Netcode hybrid, host migration, connection approval |
BallStateSync.cs | Custom physics synchronization | Jitter buffer, lerp/slerp correction, snap threshold |
GameManager.cs | Game state machine | PreGame, CountDown, InGame (3 min), PostGame phases |
PlayerControllerNetwork.cs | Player mechanics and shields | Shield charge/drain system, invulnerability |
Glove.cs | Glove states and ball throwing | Anchored/Flying states, charge-up mechanics, ball anchoring, target selection |
ArenaApprovalController.cs | Asymmetric capacity management | 6 player limit, 4 spectator limit, connection approval |
SpectatorNetwork.cs | Spectator-specific behavior | Crowd NPC body, item cycling, fireworks |
AvatarEntity.cs | Meta Avatar integration | Body tracking, lip sync, face tracking, eye tracking |
ArenaPlayerSpawningManager.cs | Multi-object networked avatar | 5 network objects per player (avatar + armatures + gloves) |
When you run the sample, the app initializes the Oculus Platform SDK and connects to the Photon lobby, then transitions to the main menu. You see your Meta Avatar in a VR menu environment with options for Quick Match, Host Match, Watch Match, Friends, and Store. Selecting Quick Match joins or creates a Photon room and loads the Arena scene.
During PreGame, you walk around and choose a team side. When the host starts the game, a 4-second countdown begins, followed by 3 minutes of gameplay. Balls spawn at center court with random types:
- Normal — standard ball with no special behavior
- Electric — passes through shields and obstacles
- Ghost — grants temporary invulnerability to the holder
- Homing — tracks the nearest opponent’s chest
- Triple — splits into 3 balls shortly after being thrown
You throw balls by grabbing with grip, charging up, and releasing. Shields activate with grip buttons but drain quickly when active and recharge faster when idle.
Spectators spawn as crowd NPCs in the stands and can cycle held items with the left trigger and launch fireworks with the right trigger. After 3 minutes, the game transitions to PostGame, separating winners and losers, with options to restart or return to the main menu.
Custom ball physics synchronization
The sample implements custom state synchronization for balls instead of using Unity’s built-in NetworkTransform. Notice how BallStateSync.cs uses a jitter buffer and client-side prediction to handle fast-moving physics objects. The server sends BallPacket structs via ClientRpc at a configurable rate, and clients smoothly interpolate position, velocity, and rotation to reduce network jitter. A snap threshold handles large discrepancies when prediction drifts too far from server state.
See the full implementation in BallStateSync.cs.
Photon Realtime as Unity Netcode transport
The sample uses Photon Realtime as the transport layer for Unity Netcode for GameObjects, combining Photon’s mature relay infrastructure with Netcode’s high-level API. Notice how NetworkLayer.cs implements a state machine (Disconnected, StartingLobby, StartingHost, StartingClient, MigratingHost) and handles host migration via Photon’s OnMasterClientSwitched callback, preserving game state when the original host disconnects.
See the state machine implementation in NetworkLayer.cs.
Asymmetric player and spectator experiences
The sample creates distinct roles for players and spectators with separate capacity limits, input maps, and spawned objects. Notice how ArenaApprovalController.cs enforces a maximum of 6 players and 4 spectators during connection approval by checking the connection payload. Spectators spawn as crowd NPCs with a SpectatorNetwork.cs component that enables item cycling and fireworks, while players spawn with full avatar rigs, gloves, and shields.
See connection approval logic in ArenaApprovalController.cs.
Multi-object networked avatars
The sample constructs each player from 5 separate networked objects to enable independent ownership of throwable gloves and support LOD-based streaming for bandwidth optimization. Notice how ArenaPlayerSpawningManager.cs spawns an avatar root, two armature hierarchies, and two glove objects, then parents them correctly. The AvatarEntity.cs component handles body tracking, lip sync, face tracking, and eye tracking, while AvatarNetworking.cs streams avatar data via RPCs with update frequencies that adjust based on distance.
See multi-object spawning in ArenaPlayerSpawningManager.cs.
The sample integrates multiple Meta Platform SDK features including group presence, join intents, friend lists, user blocking, and in-app purchases. Notice how UGBApplication.cs initializes the platform SDK, sets group presence via GroupPresenceState.cs, and handles join intents when users accept invites. The BlockUserManager.cs component fetches blocked users and prevents them from joining the same match.
See platform initialization in UGBApplication.cs.
- Add new ball types: Create a new script inheriting from BallBehaviour and implement custom behavior in
Update() or override ResetBall() as needed. See ElectricBall.cs, GhostBall.cs, HomingBall.cs, and TripleBall.cs for reference implementations. Add the new ball prefab to the BallSpawningData ScriptableObject’s ball list with an appropriate spawn weight. - Implement tournament mode: Extend GameManager.cs to track multiple rounds and persistent scores across game phases. Use PlayerPresenceHandler.cs to set custom destination metadata for tournament lobbies, and leverage the existing NetworkedScore component to aggregate results across rounds.
- Add power-ups for spectators: Extend SpectatorNetwork.cs to include interactive abilities that affect gameplay, such as spawning obstacles or healing players. The existing spectator item system (SpectatorItem base class) provides a pattern for adding new interactive objects, and ServerRpc calls synchronize effects across clients.
Social platform integration