Mini Udon Game Interface (Mugi)
Mugi is a framework for creating games as prefabs in VRChat worlds. It gives you a robust implementation of:
- Lobby UI and management for both Free-for-all and Teams
- Game Lifecycle (Start/Stop/Reset)
- Scoring with Scoreboard UI
- Game Clock/Timelimit
- Disable/Enable behavior
i.e. all the usual things you’d expect out of a game prefab.
Mugi also happens to check most of the guidelines for the Jam Rules. However, you’re not required to use it. And if you want to make a game without submitting to the Jam, feel free to use Mugi as well. It’s fully free and open source (WTFPL).
Demo Video
Section titled “Demo Video”TODO
How to Use
Section titled “How to Use”Installation
Section titled “Installation”- Install the Vrchat Creator Companion (VCC) or ALCOM first.
- Visit https://hiinaspace.github.io/vrgjam2025-vpm-repo/ and press the “Add to VCC” button.
- Click the “Manage” button for your project, and install the “Mugi (Mini Udon Game Interface)” package.
Basic Usage
Section titled “Basic Usage”- Right click somewhere in either your scene hierarchy or the Unity asset browser, and choose Create -> Mugi-based Game. This’ll create a new prefab for you to build your game inside, along with a LobbyUI and Scoreboard (UI Canvasses).
- Add assets for your game as children of the prefab.
- Configure min/max players and teams in the MugiController.
- Set up callback UdonBehaviours to respond to game events
- Use
MugiController.IncrementScore()
and other methods in your game logic.
Architecture
Section titled “Architecture”MugiGame
Section titled “MugiGame”An UdonSharpBehavior on root gameobject of your prefab. It runs the show essentially. Other parts of your game will have a reference to it in order to get the active players in the game, get the current game state, and manipulate player scores.
The default MugiGame prefab includes the MugiLobbyUI and MugiScoreboard as children. You’ll put any other gameobjects you need for your game alongside them.
MugiGame will pause completely if its GameObject is turned off, and will resume if it the GameObject is turned back on, so you can add toggles for games built on Mugi. the toggle state isn’t synced internally, so it’s possible for non-players to turn off a MugiGame as well without affecting others. (If you don’t want this behavior though, you’ll have to implement a synced toggle yourself).
Lobby UI
Section titled “Lobby UI”MugiLobbyUI is a world-space 2d Canvas UI that gives you the usual lobby behavior, i.e.
- Players can click the Join button to join the lobby, and everyone in the instance can see the current players.
- The first player to join is the “Game Master” and can start the game (and stop it early).
- If teams are enabled, players can join/switch/leave teams freely.
MugiLobbyUI is optional; MugiGame supports callbacks to add/remove players itself if you want to build your own lobby.
Scoreboard
Section titled “Scoreboard”MugiScoreboard is another world-space 2d Canvas UI that shows the current scores of all players in a game in progress, or the last known scores and ranks of players from a game that’s ended.
MugiScoreboard is similarly optional, if you want to build your own way to show player scores and winners.
Game Master
Section titled “Game Master”MugiGame uses VRChat’s networking system with a Game Master pattern:
Game Master Role:
- The first player to join becomes the Game Master (owner of the MugiGame object)
- Only the Game Master can start/stop games and process score changes
- Game Master handles all networked state changes and validation
Ownership Transfer: When the Game Master leaves, MugiGame automatically promotes a new Game Master:
- Priority 1: Active game players (lowest player ID)
- Priority 2: Any remaining players in instance (lowest player ID)
There’s no current facility to voluntarily change the game master other than having all players leave the lobby and the new game master join first.
Networking
Section titled “Networking”The game state, start time (and thus time remaining) and player/team state is synchronized, as well as the callbacks. All players (including players in the instance but not in the lobby) should see the same basic information about your game.
Game Lifecycle
Section titled “Game Lifecycle”Mugi operates as a state machine, with the current state accessible as MugiGame.gameState
:
graph LR Lobby -- Start --> Countdown Countdown -- after 3 seconds --> Running Running -- timer or manual end --> Ended Ended -- after 3 seconds --> Lobby Running -. too many players disconnect .-> Lobby
The default state. Players join and leave the game using the MugiLobbyUI (or with a custom UI). The first player to join is the Game Master (indicated by a star next to their name in the LobbyUI). If the minimum number of players have joined, then the Game Master can start the game, transitioning to the Countdown state.
Countdown
Section titled “Countdown”Players can no longer join/leave the game. The Lobby UI displays a short countdown. This is a good time to use the OnMugiCountdown
countdown to do things like teleport players to new positions or enable more expensive Udon behaviors (e.g. with Update()).
After the countdown, the game transitions automatically to the Running state.
Running
Section titled “Running”The main game clock will tick down during this state. The MugiScoreboard will update with the live scores from other players.
The game will transition to the Ended state either when the clock reaches zero, or MugiGame.EndGameEarly()
is called.
If players disconnect from the VRChat instance during the game and number of players falls below the minimum, the game will transition back to the Lobby state.
A short cooldown state after the game ends. Will transition to the Lobby state after 3 seconds.
Scoring
Section titled “Scoring”MugiGame keeps track of a numeric score per player. The score is an arbitrary integer (can be negative).
If enabled teams don’t have scores themselves. The default MugiScoreboard implements team scores/ranks by simply summing the each player’s score within it.
API Reference
Section titled “API Reference”Game States
Section titled “Game States”// Check current game stateif (mugiGame.gameState == MugiGame.STATE_LOBBY) { /* players joining */ }if (mugiGame.gameState == MugiGame.STATE_COUNTDOWN) { /* 3-sec countdown */ }if (mugiGame.gameState == MugiGame.STATE_RUNNING) { /* active gameplay */ }if (mugiGame.gameState == MugiGame.STATE_ENDED) { /* brief end state */ }
// Get time remaining in current state (countdown or game time)float timeLeft = mugiGame.timeRemaining;
Player Info
Section titled “Player Info”// Check if a player is currently in the gamebool inGame = mugiGame.IsPlayerInGame(player);
// Get all players currently in the gameVRCPlayerApi[] players = mugiGame.GetPlayersInGame();
// Get a player's team index (-1 if not in game, 0 for FFA)int teamIndex = mugiGame.GetPlayerTeam(player);
// Get team name for displaystring teamName = mugiGame.GetTeamName(teamIndex);
Game Control
Section titled “Game Control”// Check if game has enough players to startbool canStart = mugiGame.IsGameReady();
// Start the game (only game master can call)mugiGame.StartGame();
// End the game early (only game master can call)mugiGame.EndGameEarly();
// Get time remaining in current statefloat timeLeft = mugiGame.GetRemainingTime();
Player Scores
Section titled “Player Scores”These are the main methods you’ll use to interact with mugi.
// Add to a player's score (networked, only works during STATE_RUNNING)mugiGame.IncrementScore(player.playerId, 10);
// Set a player's score directly (networked, only works during STATE_RUNNING)mugiGame.SetScore(player.playerId, 100);
// Get a player's current scoreint score = mugiGame.GetPlayerScore(player);int score = mugiGame.GetPlayerScore(playerId);
// Get total score for a team (sum of all players on team)int teamScore = mugiGame.GetTeamScore(teamIndex);
Lobby Management
Section titled “Lobby Management”// Request to join the game (becomes networked call to game master)mugiGame.RequestJoinGame(player.playerId);
// Request to leave the game (becomes networked call to game master)mugiGame.RequestLeaveGame(player.playerId);
// Request to join a specific team (becomes networked call to game master)mugiGame.RequestJoinTeam(player.playerId, teamIndex);
Callback System
Section titled “Callback System”Mugi can call public methods on arbitrary UdonBehaviors at different points of the game lifecycle. To register callbacks, add your UdonBehavior to the appropriate array field on the MugiGame component, e.g. by dragging the gameobject into the inspector. These callbacks run on all clients (i.e. they are synchronized across the network).
Event Methods
Section titled “Event Methods”Method Name | When Called | Use For |
---|---|---|
OnMugiCountdown | Game enters countdown state | Setup like teleporting players or enabling expensive behaviors |
OnMugiStart | Gameplay begins (after countdown) | Game timer starts here, initialize game mechanics |
OnMugiEnd | Game finishes (timer expired or manual end) | Cleanup and result processing |
OnMugiPlayerJoin | Player joins the lobby | Handle new player setup, access player info via MugiGame API |
OnMugiPlayerLeave | Player leaves (disconnection or manual) | Handle any player-specific cleanup |
OnMugiTimeWarning | Once when 30 seconds remain | ”Hurry up” effects or warnings |
Example Implementation
Section titled “Example Implementation”public class MyGameBehavior : UdonSharpBehaviour{ public MugiGame mugiGame;
public void OnMugiStart() { // Enable game mechanics when game starts gameObject.SetActive(true);
// Get all players and do something VRCPlayerApi[] players = mugiGame.GetPlayersInGame(); // ... your game logic }
public void OnMugiEnd() { // Disable expensive behaviors gameObject.SetActive(false); }}
Lifecycle Gameobjects
Section titled “Lifecycle Gameobjects”Mugi can also automatically enable and disable GameObjects when the game is in the Running
state. Add your gameobjects to the Enable During Game
array on the MugiGame
behavior. The gameobjects will be enabled for all players, including those outside the game.
I scrolled all the way through your dumb readme, where da anime grills at?
Section titled “I scrolled all the way through your dumb readme, where da anime grills at?”Fine, here’s my favorite ‘mugi pic: