Devlog: Lobby System for Zoofite – Invite Friends, Start a Party!

In this devlog, I’ll show how we built a simple yet robust lobby (party) system using Unity Lobby. The goal was to allow players in Zoofite to create a party, join one via a code, and leave it – perfect for playing with friends or fixed teams.

Features

Create a party (lobby)

Join a party using a code

Display current teammate in the UI

Leave the party

Error handling via a central Result<T> system we use project-wide for structured error reporting

Foundation: Unity Lobby Service

We’re using Unity Lobby as the backbone. On startup, the player authenticates and receives a unique ID via AuthenticationService.Instance.PlayerId.

Example: Creating a Party

public async Task<Lobby> CreateOwnLobbyAsync()
{
    var options = new CreateLobbyOptions
    {
        IsPrivate = true,
        Player = new LobbyPlayer { Data = CreatePlayerData() },
        Data = new Dictionary<string, DataObject>
        {
            { "LobbySettings", new DataObject(DataObject.VisibilityOptions.Public, "DefaultMode") }
        }
    };

    var lobby = await LobbyService.Instance.CreateLobbyAsync("Zoofite Lobby", 2, options);
    CurrentLobby = lobby;
    await SubscribeToLobbyEventsAsync();
    return lobby;
}

The lobby object is stored, and event subscriptions are set up to react to changes in the lobby.

Joining a Party via Code

public async Task<bool> JoinLobbyByCodeAsync(string code)
{
    var joinOptions = new JoinLobbyByCodeOptions
    {
        Player = new LobbyPlayer { Data = CreatePlayerData() }
    };

    var lobby = await LobbyService.Instance.JoinLobbyByCodeAsync(code, joinOptions);
    CurrentLobby = lobby;
    await SubscribeToLobbyEventsAsync();
    return true;
}

After joining, the UI displays the party code and the teammate’s name.

UI Handling: GUIParty Script

The GUIParty script handles the UI logic: buttons, input field, and teammate visibility.

private void OnCodeChanged(string code)
{
    bool hasInput = !string.IsNullOrEmpty(code);
    m_BTN_StartParty.gameObject.SetActive(!hasInput);
    m_BTN_JoinParty.gameObject.SetActive(hasInput);
}

A useful trick: m_INP_Partycode.SetTextWithoutNotify("") prevents unintended value change triggers when resetting the input field.

Leaving a Lobby (with Error Handling)

This is where our Result<T> system shines:

public async Task<Result> LeaveLobbyAsync()
{
    if (CurrentLobby == null)
        return Result.Failure("No lobby joined", ErrorReason.NoDataAvailable);

    string lobbyId = CurrentLobby.Id;
    CurrentLobby = null;

    try
    {
        await LobbyService.Instance.RemovePlayerAsync(lobbyId, AuthenticationService.Instance.PlayerId);
    }
    catch (LobbyServiceException e)
    {
        return Result.Failure($"Lobby error: {e.Message}", ErrorReason.NetworkError);
    }

    OnLobbyLeft?.Invoke();
    return Result.Success();
}

Showing Teammate in the UI

When another player joins, we instantly reflect that in the UI:

private void OnPlayerJoinToLobby(LobbyPlayer _player)
{
    if(_player.Data.TryGetValue("name", out var name))
    {
        m_teammateName.text = name.Value;
        m_teammateName.SetActive(true);
    }
}

Lobby Events Overview

Lobby changes (join, leave, kick) are handled through Unity’s LobbyEventCallbacks:

callbacks.LobbyChanged += async changes =>
{
    switch (changes)
    {
        case { PlayerJoined.Changed: true }:
            foreach (var joined in changes.PlayerJoined.Value)
                Debug.Log($"Player joined: {joined.Player.Id}");
            break;

        case { PlayerLeft.Changed: true }:
            foreach (var left in changes.PlayerLeft.Value)
                Debug.Log($"Player left: {left}");
            break;
    }
};

Summary

The party system works reliably and feels intuitive:

  • Join and create logic is clearly separated
  • All error cases are handled via Result<T>
  • The UI is responsive and player-friendly

What’s Next

Next, we plan to expand the system with:

  • Lobby timeouts
  • Error detection for connection loss
  • Allowing the host to kick players from the lobby
  • Support for more players: possibly scaling up to 3–4 player parties

Stay tuned for more devlogs – we’re just getting started!

Schreibe einen Kommentar