// PanelScoreboard.cs // A custom UI panel (CreatePanel) shown as a screen OVERLAY in a corner behind the platform's own UI. It is NOT shown // to everyone automatically: a player gets it when they click a button object you slot in, or the object this script is on (and can close it with the x, // then click again to reopen). It shows a shared round score every player sees the same, a coin count that is each // player's own, and a // "Collect a coin" button. A click comes back to this server script as that player (e.panel event): their own coins go // up for them only, the shared total goes up for everyone, and both update live on every screen. // // This is the difference from a HUD: a HUD is the player's personal window; a panel is the world's own UI surface. Set // it to SetMode(PanelMode.WorldSpace) instead and the very same panel stands in the world for VR (see PanelWorldMenu). using System.Collections; using System.Collections.Generic; using IHXR.Simulation; public class PanelScoreboard : ScriptBase { [Header("Look")] public string Title = "Scoreboard"; public Color TitleColor = new Color(1f, 0.85f, 0.3f); [Tooltip("Where it sits on screen.")] public PanelAnchor Corner = PanelAnchor.TopRight; public TextureItem CoinIcon; public Color AccentColor = new Color(0.3f, 0.75f, 1f); [Header("Opening it")] [Tooltip("The object players click to open the scoreboard. Empty = the object this script is on.")] public SceneObject OpenButton; [Tooltip("The hint shown when a player points at that object.")] public string OpenHint = "Open the scoreboard"; [Header("Round")] [Tooltip("The shared total everyone is working toward.")] public int RoundGoal = 50; private ScriptPanel panel; private PanelItem coinLabel; // per-player private PanelItem sharedLabel; // everyone private PanelProgressBar sharedBar; private int sharedTotal; private readonly Dictionary coins = new Dictionary(); public override void Start() { panel = CreatePanel("scoreboard", 300); panel.SetMode(PanelMode.Overlay) .SetAnchor(Corner, 24, 24) .SetTitle(Title).SetTitleStyle(TitleColor, 20) .SetFont(PanelFont.Rounded, 14) .SetAccentColor(AccentColor) .SetLayout(1, 8, 14); sharedLabel = panel.AddLabel("Round total: 0 / " + RoundGoal); sharedBar = panel.AddProgressBar(0f); panel.AddDivider(); // A counter: an icon with a label beside it. It starts as the base value; each player sees their own once they collect. coinLabel = panel.AddCounter("Your coins: 0", CoinIcon); panel.AddButton("Collect a coin", OnCollect).SetTooltip("Adds one coin for you and the round"); // Shown to a player only when they click the Open Button (or this object if none is slotted). The x closes it; clicking again reopens. if (OpenButton != null && !OpenButton.IsNull) MakeInteractable(OpenButton, click => panel.Show(click.Username), true, null, true, 10f, OpenHint); else MakeInteractable(click => panel.Show(click.Username), true, null, true, 10f, OpenHint); } private void OnCollect(PanelEvent e) { // The click arrives here as the player who clicked (e.Username): act "for that user". string user = e.Username; int mine = (coins.TryGetValue(user, out var c) ? c : 0) + 1; coins[user] = mine; coinLabel.SetText("Your coins: " + mine, user); // for that player only sharedTotal += 1; sharedLabel.SetText("Round total: " + sharedTotal + " / " + RoundGoal); // for everyone sharedBar.SetValue(RoundGoal > 0 ? Mathf.Clamp01((float)sharedTotal / RoundGoal) : 1f); if (sharedTotal == RoundGoal) SendScriptChat(user + " collected the coin that finished the round!"); } }