feat: admin UI, player scoreboard, back button logic

This commit is contained in:
2025-12-04 10:47:40 -05:00
Unverified
parent a16a44ba7a
commit 24ca218ee2
8 changed files with 236 additions and 17 deletions

View File

@@ -11,7 +11,7 @@ config_version=5
[application]
config/name="connect4-moderator-observer"
run/main_scene="uid://cr8fi0e4r88s8"
run/main_scene="uid://dcx5nvs0pa7me"
config/features=PackedStringArray("4.5", "C#", "Forward Plus")
config/icon="uid://ckmfi0cjgxgyk"

View File

@@ -1,6 +1,7 @@
[gd_scene load_steps=13 format=3 uid="uid://m542qwlp7hl7"]
[gd_scene load_steps=14 format=3 uid="uid://m542qwlp7hl7"]
[ext_resource type="Script" uid="uid://dg5jt0o0r0v3r" path="res://scripts/BoardScreen.cs" id="1_b3w8x"]
[ext_resource type="PackedScene" uid="uid://rl33x81cxlh0" path="res://scenes/bracket_view.tscn" id="2_u1oi2"]
[ext_resource type="Texture2D" uid="uid://dlx02qat7j6lf" path="res://assets/sprites/AssetTileset.png" id="3_1tlhv"]
[ext_resource type="FontFile" uid="uid://c3jmev24lo6ci" path="res://assets/fonts/PixelOperator8.ttf" id="3_rjcmr"]
[ext_resource type="Texture2D" uid="uid://ckmfi0cjgxgyk" path="res://assets/sprites/RedChip.png" id="4_1hrcj"]
@@ -30,8 +31,10 @@ sources/0 = SubResource("TileSetAtlasSource_i2o8i")
atlas = ExtResource("3_1tlhv")
region = Rect2(112, 32, 16, 16)
[node name="BoardScreen" type="Node2D"]
[node name="BoardScreen" type="Node2D" node_paths=PackedStringArray("BackButton")]
script = ExtResource("1_b3w8x")
BracketScene = ExtResource("2_u1oi2")
BackButton = NodePath("BracketButton")
[node name="Floor Collider" type="StaticBody2D" parent="."]
position = Vector2(0, 200)

View File

@@ -1,8 +1,9 @@
[gd_scene load_steps=4 format=3 uid="uid://rl33x81cxlh0"]
[gd_scene load_steps=5 format=3 uid="uid://rl33x81cxlh0"]
[ext_resource type="Script" uid="uid://dm25u0a2lqk2x" path="res://scripts/BracketScene.cs" id="1_dvj3m"]
[ext_resource type="Texture2D" uid="uid://ckmfi0cjgxgyk" path="res://assets/sprites/RedChip.png" id="2_7c11m"]
[ext_resource type="PackedScene" uid="uid://cr8fi0e4r88s8" path="res://scenes/game.tscn" id="3_1511b"]
[ext_resource type="Script" uid="uid://1y72woiynf31" path="res://scripts/AdminControls.cs" id="4_mbqc8"]
[node name="BracketView" type="Control" node_paths=PackedStringArray("Players", "Matches")]
layout_mode = 3
@@ -17,9 +18,36 @@ Matches = NodePath("HBoxContainer/MatchList")
JoinButton = ExtResource("2_7c11m")
BoardScene = ExtResource("3_1511b")
[node name="ColorRect" type="ColorRect" parent="."]
custom_minimum_size = Vector2(0, 36)
layout_mode = 1
anchors_preset = 10
anchor_right = 1.0
grow_horizontal = 2
color = Color(0.13319641, 0.13319641, 0.13319638, 1)
[node name="AdminControls" type="HBoxContainer" parent="ColorRect" node_paths=PackedStringArray("BecomeAdmin", "StartTournament")]
custom_minimum_size = Vector2(0, 36)
layout_mode = 1
anchors_preset = 10
anchor_right = 1.0
offset_bottom = 36.0
grow_horizontal = 2
script = ExtResource("4_mbqc8")
BecomeAdmin = NodePath("BecomeAdmin")
StartTournament = NodePath("StartTournament")
[node name="BecomeAdmin" type="Button" parent="ColorRect/AdminControls"]
layout_mode = 2
text = "Become Admin"
[node name="StartTournament" type="Button" parent="ColorRect/AdminControls"]
layout_mode = 2
text = "Start Tournament"
[node name="HBoxContainer" type="HBoxContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchors_preset = -1
anchor_right = 1.0
anchor_bottom = 1.0
offset_top = 36.0

123
scripts/AdminControls.cs Normal file
View File

@@ -0,0 +1,123 @@
using Godot;
using System;
using System.Collections.Generic;
public partial class AdminControls : HBoxContainer
{
[Export] public Button BecomeAdmin;
[Export] public Button StartTournament;
public override void _Ready()
{
Connection.Instance.OnBecomeAdmin += OnBecomeAdmin;
Connection.Instance.OnTournamentEnd += OnEndTournament;
StartTournament.Pressed += StartTournamentCommand;
if (!Connection.Instance.IsAdmin || Connection.Instance.ActiveTournament)
{
StartTournament.Hide();
}
BecomeAdmin.Pressed += ShowAuthPopup;
}
public override void _ExitTree()
{
Connection.Instance.OnBecomeAdmin -= OnBecomeAdmin;
Connection.Instance.OnTournamentEnd -= OnEndTournament;
}
private void StartTournamentCommand()
{
Connection.Instance.StartTournament();
}
private void OnEndTournament(List<(string, int)> playerScoreboard)
{
StartTournament.Show();
ShowTournamentScoreboard(playerScoreboard);
}
private void ShowAuthPopup()
{
var authWindow = new Window();
authWindow.AlwaysOnTop = true;
authWindow.MaximizeDisabled = true;
authWindow.Unresizable = true;
authWindow.InitialPosition = Window.WindowInitialPosition.CenterMainWindowScreen;
authWindow.Size = new Vector2I(256, 128);
authWindow.CloseRequested += () =>
{
GetTree().Root.RemoveChild(authWindow);
};
var vbox = new VBoxContainer();
vbox.LayoutMode = 1;
vbox.AnchorBottom = 1.0f;
vbox.AnchorRight = 1.0f;
vbox.GrowHorizontal = GrowDirection.Both;
vbox.GrowVertical = GrowDirection.Both;
vbox.Alignment = AlignmentMode.Center;
var passwordBox = new TextEdit();
passwordBox.PlaceholderText = "Password";
passwordBox.SetCustomMinimumSize(new Vector2(32, 32));
var button = new Button();
button.Text = "Login";
button.Pressed += () =>
{
Connection.Instance.AdminAuth(passwordBox.Text);
GetTree().Root.RemoveChild(authWindow);
};
vbox.AddChild(passwordBox);
vbox.AddChild(button);
authWindow.AddChild(vbox);
GetTree().Root.AddChild(authWindow);
}
private void ShowTournamentScoreboard(List<(string, int)> playerScoreboard)
{
var scoreboardWindow = new Window();
scoreboardWindow.AlwaysOnTop = true;
scoreboardWindow.MaximizeDisabled = true;
scoreboardWindow.Unresizable = true;
scoreboardWindow.InitialPosition = Window.WindowInitialPosition.CenterMainWindowScreen;
scoreboardWindow.Size = new Vector2I(256, 512);
scoreboardWindow.CloseRequested += () =>
{
GetTree().Root.RemoveChild(scoreboardWindow);
};
var tree = new Tree();
tree.HideRoot = true;
tree.Columns = 2;
tree.ColumnTitlesVisible = true;
tree.SetColumnTitle(0, "Player");
tree.SetColumnTitle(1, "Score");
var root = tree.CreateItem();
foreach ((string, int) entry in playerScoreboard)
{
var item = tree.CreateItem(root);
item.SetText(0, entry.Item1);
item.SetText(1, entry.Item2.ToString());
}
scoreboardWindow.AddChild(tree);
GetTree().Root.AddChild(scoreboardWindow);
}
private void OnBecomeAdmin()
{
BecomeAdmin.Hide();
if (!Connection.Instance.ActiveTournament)
{
StartTournament.Show();
}
}
}

View File

@@ -0,0 +1 @@
uid://1y72woiynf31

View File

@@ -1,9 +1,11 @@
using Godot;
using System;
using System.Collections.Generic;
public partial class BoardScreen : Node2D {
[Export] public PackedScene BracketScene;
[Export] public BaseButton BackButton;
private const string RED_CHIP_PATH = "res://scenes/red_chip.tscn";
private const string YELLOW_CHIP_PATH = "res://scenes/yellow_chip.tscn";
@@ -45,6 +47,12 @@ public partial class BoardScreen : Node2D {
Connection.Instance.OnObserveDraw += ObserveDraw;
Connection.Instance.OnObserveTerminated += ObserveTerminated;
Connection.Instance.OnObserveMove += ObserveMove;
Connection.Instance.OnTournamentEnd += ShowTournamentScoreboard;
BackButton.Pressed += () =>
{
TransitionToBracket();
};
}
public override void _ExitTree()
@@ -53,6 +61,7 @@ public partial class BoardScreen : Node2D {
Connection.Instance.OnObserveDraw -= ObserveDraw;
Connection.Instance.OnObserveTerminated -= ObserveTerminated;
Connection.Instance.OnObserveMove -= ObserveMove;
Connection.Instance.OnTournamentEnd -= ShowTournamentScoreboard;
}
private void ObserveMove(string username, int column)
@@ -69,22 +78,76 @@ public partial class BoardScreen : Node2D {
private void ObserveWin(string winner)
{
// TODO
var popup = new Popup();
popup.AlwaysOnTop = true;
popup.PopupCentered();
popup.Size = new Vector2I(128, 128);
var text = new Label();
text.Text = winner + " wins!";
popup.AddChild(text);
GetTree().Root.AddChild(popup);
TransitionToBracket();
}
private void ObserveDraw()
{
// TODO
var popup = new Popup();
popup.AlwaysOnTop = true;
popup.PopupCentered();
popup.Size = new Vector2I(128, 128);
var text = new Label();
text.Text = "Draw!";
popup.AddChild(text);
GetTree().Root.AddChild(popup);
TransitionToBracket();
}
private void ObserveTerminated()
{
// TODO
var popup = new Popup();
popup.AlwaysOnTop = true;
popup.PopupCentered();
popup.Size = new Vector2I(128, 128);
var text = new Label();
text.Text = "Match Terminated";
popup.AddChild(text);
GetTree().Root.AddChild(popup);
TransitionToBracket();
}
private void ShowTournamentScoreboard(List<(string, int)> playerScoreboard)
{
var scoreboardWindow = new Window();
scoreboardWindow.AlwaysOnTop = true;
scoreboardWindow.MaximizeDisabled = true;
scoreboardWindow.Unresizable = true;
scoreboardWindow.InitialPosition = Window.WindowInitialPosition.CenterMainWindowScreen;
scoreboardWindow.Size = new Vector2I(256, 512);
scoreboardWindow.CloseRequested += () =>
{
GetTree().Root.RemoveChild(scoreboardWindow);
};
var tree = new Tree();
tree.HideRoot = true;
tree.Columns = 2;
tree.ColumnTitlesVisible = true;
tree.SetColumnTitle(0, "Player");
tree.SetColumnTitle(1, "Score");
var root = tree.CreateItem();
foreach ((string, int) entry in playerScoreboard)
{
var item = tree.CreateItem(root);
item.SetText(0, entry.Item1);
item.SetText(1, entry.Item2.ToString());
}
scoreboardWindow.AddChild(tree);
GetTree().Root.AddChild(scoreboardWindow);
}
private void TransitionToBracket()
{
GetTree().ChangeSceneToPacked(BracketScene);

View File

@@ -29,7 +29,6 @@ public partial class BracketScene : Control
Connection.Instance.OnUpdatedPlayers += UpdatePlayers;
Connection.Instance.OnUpdatedMatches += UpdateMatches;
Connection.Instance.OnBecomeAdmin += BecomeAdmin;
Connection.Instance.OnWatchGameAck += TransitionToBoard;
}
@@ -37,7 +36,6 @@ public partial class BracketScene : Control
{
Connection.Instance.OnUpdatedPlayers -= UpdatePlayers;
Connection.Instance.OnUpdatedMatches -= UpdateMatches;
Connection.Instance.OnBecomeAdmin -= BecomeAdmin;
Connection.Instance.OnWatchGameAck -= TransitionToBoard;
}
@@ -90,15 +88,8 @@ public partial class BracketScene : Control
}
}
private void BecomeAdmin()
{
// TODO
}
private void TransitionToBoard()
{
// TODO
GD.Print("Watch game worked!");
GetTree().ChangeSceneToPacked(BoardScene);
}
}

View File

@@ -30,6 +30,7 @@ public partial class Connection : Node
public event Action<string, int> OnObserveMove;
public event Action<List<MatchData>> OnUpdatedMatches;
public event Action<List<PlayerData>> OnUpdatedPlayers;
public event Action OnStartTournamentAck;
public event Action<List<(string, int)>> OnTournamentEnd;
public event Action OnBecomeAdmin;
@@ -39,6 +40,8 @@ public partial class Connection : Node
public bool IsAdmin { get; private set; }
public bool IsPlayer { get; private set; }
public bool ActiveTournament { get; private set; }
public MatchData CurrentObservingMatch { get; private set; }
@@ -334,6 +337,7 @@ public partial class Connection : Node
{
case "END":
{
ActiveTournament = false;
List<(string, int)> playerScoreboard = new List<(string, int)>();
string[] entries = segments[1].Split("|");
foreach (string entry in entries)
@@ -345,6 +349,12 @@ public partial class Connection : Node
OnTournamentEnd?.Invoke(playerScoreboard);
break;
}
case "START":
{
OnStartTournamentAck?.Invoke();
ActiveTournament = true;
break;
}
}
}