Add scoreboard

This commit is contained in:
Sofia 2026-07-23 23:28:11 +03:00
parent c7d5bcc7ad
commit b707115c79
9 changed files with 147 additions and 68 deletions

View File

@ -93,6 +93,11 @@ pause={
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194305,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194305,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
] ]
} }
scoreboard={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194306,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
[physics] [physics]

View File

@ -2,11 +2,9 @@
[ext_resource type="PackedScene" uid="uid://2sfy0vq0fqt3" path="res://scenes/ui/player_listing.tscn" id="1_ou354"] [ext_resource type="PackedScene" uid="uid://2sfy0vq0fqt3" path="res://scenes/ui/player_listing.tscn" id="1_ou354"]
[node name="game_finished" type="GameFinishedScreen" unique_id=700430082 node_paths=PackedStringArray("title_container", "back_button", "players_hbox")] [node name="game_finished" type="GameFinishedScreen" unique_id=700430082 node_paths=PackedStringArray("title_container", "back_button")]
title_container = NodePath("title_container") title_container = NodePath("title_container")
back_button = NodePath("button") back_button = NodePath("button")
players_hbox = NodePath("player_listings")
player_listing_scene = ExtResource("1_ou354")
anchors_preset = 15 anchors_preset = 15
anchor_right = 1.0 anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
@ -32,26 +30,27 @@ anchor_left = 0.5
anchor_top = 1.0 anchor_top = 1.0
anchor_right = 0.5 anchor_right = 0.5
anchor_bottom = 1.0 anchor_bottom = 1.0
offset_left = -22.0 offset_left = -40.0
offset_top = -103.0 offset_top = -87.0
offset_right = 23.0 offset_right = 42.0
offset_bottom = -69.0 offset_bottom = -34.0
grow_horizontal = 2 grow_horizontal = 2
grow_vertical = 0 grow_vertical = 0
theme_override_font_sizes/font_size = 32 theme_override_font_sizes/font_size = 32
text = "Back" text = "Back"
[node name="player_listings" type="HBoxContainer" parent="." unique_id=588134370] [node name="player_listings" type="PlayerListings" parent="." unique_id=602626392]
player_listing_scene = ExtResource("1_ou354")
layout_mode = 1 layout_mode = 1
anchors_preset = 8 anchors_preset = 8
anchor_left = 0.5 anchor_left = 0.5
anchor_top = 0.5 anchor_top = 0.5
anchor_right = 0.5 anchor_right = 0.5
anchor_bottom = 0.5 anchor_bottom = 0.5
offset_left = -186.0 offset_left = -554.5
offset_top = -193.0 offset_top = -210.0
offset_right = 186.0 offset_right = 554.5
offset_bottom = -153.0 offset_bottom = 210.0
grow_horizontal = 2 grow_horizontal = 2
grow_vertical = 2 grow_vertical = 2
alignment = 1 alignment = 1

View File

@ -3,13 +3,14 @@
[ext_resource type="PackedScene" uid="uid://bod6b3befmyt5" path="res://scenes/player/soldier_m.tscn" id="1_jd651"] [ext_resource type="PackedScene" uid="uid://bod6b3befmyt5" path="res://scenes/player/soldier_m.tscn" id="1_jd651"]
[ext_resource type="PackedScene" uid="uid://cl66unms2gim0" path="res://scenes/player/splorch.tscn" id="2_ywmwa"] [ext_resource type="PackedScene" uid="uid://cl66unms2gim0" path="res://scenes/player/splorch.tscn" id="2_ywmwa"]
[ext_resource type="PackedScene" uid="uid://n3u0jr4wiib1" path="res://scenes/ui/settings.tscn" id="3_beej8"] [ext_resource type="PackedScene" uid="uid://n3u0jr4wiib1" path="res://scenes/ui/settings.tscn" id="3_beej8"]
[ext_resource type="PackedScene" uid="uid://2sfy0vq0fqt3" path="res://scenes/ui/player_listing.tscn" id="4_okac2"]
[sub_resource type="Environment" id="Environment_3nx84"] [sub_resource type="Environment" id="Environment_3nx84"]
glow_enabled = true glow_enabled = true
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_oh8vq"] [sub_resource type="CapsuleShape3D" id="CapsuleShape3D_oh8vq"]
[node name="player" type="LocalPlayer" unique_id=863055906 node_paths=PackedStringArray("camera", "soldier_mesh", "collider", "splorch", "dead_cam_target", "respawn_label", "ball_origin", "weapon_node", "pause_panel", "exit_to_lobby", "settings_panel")] [node name="player" type="LocalPlayer" unique_id=863055906 node_paths=PackedStringArray("camera", "soldier_mesh", "collider", "splorch", "dead_cam_target", "respawn_label", "ball_origin", "weapon_node", "pause_panel", "exit_to_lobby", "settings_panel", "scoreboard")]
look_sensitivity = 1.5 look_sensitivity = 1.5
camera = NodePath("camera_3d") camera = NodePath("camera_3d")
move_speed = 5.0 move_speed = 5.0
@ -23,6 +24,7 @@ weapon_node = NodePath("camera_3d/weapon_node")
pause_panel = NodePath("pause_menu") pause_panel = NodePath("pause_menu")
exit_to_lobby = NodePath("pause_menu/v_box_container/exit_to_lobby") exit_to_lobby = NodePath("pause_menu/v_box_container/exit_to_lobby")
settings_panel = NodePath("settings") settings_panel = NodePath("settings")
scoreboard = NodePath("scoreboard")
health = 100 health = 100
collision_mask = 4 collision_mask = 4
@ -117,6 +119,24 @@ text = "Exit"
[node name="settings" parent="." unique_id=999912383 instance=ExtResource("3_beej8")] [node name="settings" parent="." unique_id=999912383 instance=ExtResource("3_beej8")]
visible = false visible = false
[node name="scoreboard" type="PanelContainer" parent="." unique_id=1276565374]
custom_minimum_size = Vector2(0, -1)
anchors_preset = 5
anchor_left = 0.5
anchor_right = 0.5
offset_left = -76.0
offset_top = 58.0
offset_right = 77.0
offset_bottom = 100.0
grow_horizontal = 2
size_flags_vertical = 3
[node name="h_box_container" type="PlayerListings" parent="scoreboard" unique_id=256898638]
player_listing_scene = ExtResource("4_okac2")
layout_mode = 2
alignment = 1
metadata/_edit_lock_ = true
[connection signal="pressed" from="pause_menu/v_box_container/settings" to="settings" method="open"] [connection signal="pressed" from="pause_menu/v_box_container/settings" to="settings" method="open"]
[connection signal="pressed" from="pause_menu/v_box_container/exit_to_lobby" to="." method="exit_to_lobby"] [connection signal="pressed" from="pause_menu/v_box_container/exit_to_lobby" to="." method="exit_to_lobby"]
[connection signal="pressed" from="pause_menu/v_box_container/exit" to="." method="exit"] [connection signal="pressed" from="pause_menu/v_box_container/exit" to="." method="exit"]

View File

@ -5,24 +5,24 @@ name_label = NodePath("name")
kills_label = NodePath("kills") kills_label = NodePath("kills")
deaths_label = NodePath("deaths") deaths_label = NodePath("deaths")
ping_label = NodePath("ping") ping_label = NodePath("ping")
size_flags_horizontal = 3
[node name="name" type="Label" parent="." unique_id=1361759955] [node name="name" type="Label" parent="." unique_id=1361759955]
custom_minimum_size = Vector2(200, 0)
custom_maximum_size = Vector2(200, -1)
clip_contents = true clip_contents = true
layout_mode = 2 layout_mode = 2
size_flags_horizontal = 2
text = "Player Name" text = "Player Name"
[node name="kills" type="Label" parent="." unique_id=690390687] [node name="kills" type="Label" parent="." unique_id=690390687]
custom_minimum_size = Vector2(30, 0) custom_minimum_size = Vector2(50, 0)
custom_maximum_size = Vector2(30, -1) custom_maximum_size = Vector2(50, -1)
layout_mode = 2 layout_mode = 2
text = "0" text = "0"
horizontal_alignment = 1 horizontal_alignment = 1
[node name="deaths" type="Label" parent="." unique_id=1615203485] [node name="deaths" type="Label" parent="." unique_id=1615203485]
custom_minimum_size = Vector2(30, 0) custom_minimum_size = Vector2(50, 0)
custom_maximum_size = Vector2(30, -1) custom_maximum_size = Vector2(50, -1)
layout_mode = 2 layout_mode = 2
text = "0" text = "0"
horizontal_alignment = 1 horizontal_alignment = 1

View File

@ -3,7 +3,8 @@ use std::{f32::consts::PI, ops::Neg};
use godot::{ use godot::{
classes::{ classes::{
Button, Camera3D, CharacterBody3D, CollisionShape3D, GpuParticles3D, ICharacterBody3D, Button, Camera3D, CharacterBody3D, CollisionShape3D, GpuParticles3D, ICharacterBody3D,
Input, InputEvent, InputEventMouseMotion, Label, Label3D, Panel, input::MouseMode, Input, InputEvent, InputEventMouseMotion, Label, Label3D, Panel, PanelContainer,
input::MouseMode,
}, },
obj::WithBaseField, obj::WithBaseField,
prelude::*, prelude::*,
@ -198,6 +199,8 @@ pub struct LocalPlayer {
#[export] #[export]
settings_panel: Option<Gd<SettingsPanel>>, settings_panel: Option<Gd<SettingsPanel>>,
#[export] #[export]
scoreboard: Option<Gd<PanelContainer>>,
#[export]
health: i32, health: i32,
pub player_id: Option<u16>, pub player_id: Option<u16>,
@ -491,6 +494,10 @@ impl ICharacterBody3D for LocalPlayer {
let new_pos = camera_prev_pos.lerp(target.get_global_position(), 0.1); let new_pos = camera_prev_pos.lerp(target.get_global_position(), 0.1);
camera.set_global_position(new_pos); camera.set_global_position(new_pos);
} }
if let Some(scoreboard) = &mut self.scoreboard {
scoreboard.set_visible(Input::singleton().is_action_pressed("scoreboard"));
}
} }
fn input(&mut self, event: Gd<InputEvent>) { fn input(&mut self, event: Gd<InputEvent>) {

View File

@ -1,15 +1,14 @@
use godot::{ use godot::{
classes::{ classes::{
Button, HBoxContainer, IPanel, Label, Panel, VBoxContainer, box_container::AlignmentMode, Button, HBoxContainer, IPanel, Label, Panel, VBoxContainer, box_container::AlignmentMode,
control::LayoutDirection,
}, },
global::{HorizontalAlignment, VerticalAlignment}, global::HorizontalAlignment,
prelude::*, prelude::*,
}; };
use crate::{ use crate::{
game_manager::{Game, GameManager}, game_manager::{Game, GameManager},
ui::player_listing::PlayerListing, ui::{player_listing::PlayerListing, player_listings::PlayerListings},
}; };
#[derive(GodotClass)] #[derive(GodotClass)]
@ -20,9 +19,7 @@ pub struct GameFinishedScreen {
#[export] #[export]
back_button: Option<Gd<Button>>, back_button: Option<Gd<Button>>,
#[export] #[export]
players_hbox: Option<Gd<HBoxContainer>>, player_listings: Option<Gd<PlayerListings>>,
#[export]
player_listing_scene: Option<Gd<PackedScene>>,
base: Base<Panel>, base: Base<Panel>,
} }
@ -31,7 +28,9 @@ pub struct GameFinishedScreen {
impl IPanel for GameFinishedScreen { impl IPanel for GameFinishedScreen {
fn ready(&mut self) { fn ready(&mut self) {
self.produce_title(); self.produce_title();
self.produce_player_listings(); if let Some(listings) = &mut self.player_listings {
listings.bind_mut().update_player_listings();
}
if let Some(back) = &self.back_button { if let Some(back) = &self.back_button {
back.signals().pressed().connect_other(self, |_| { back.signals().pressed().connect_other(self, |_| {
if let Some(mut game) = Game::singleton() { if let Some(mut game) = Game::singleton() {
@ -44,39 +43,6 @@ impl IPanel for GameFinishedScreen {
} }
impl GameFinishedScreen { impl GameFinishedScreen {
fn produce_player_listings(&mut self) {
if let Some(game) = Game::singleton() {
for (id, team) in game.bind().get_teams().iter_shared().enumerate() {
let mut vbox = VBoxContainer::new_alloc();
vbox.set_alignment(AlignmentMode::CENTER);
let mut team_label = Label::new_alloc();
team_label.set_modulate(team.bind().color);
team_label.set_text(&team.bind().name);
team_label.set_horizontal_alignment(HorizontalAlignment::CENTER);
vbox.add_child(&team_label);
if let Some(listing_scene) = &self.player_listing_scene {
let game = game.bind();
let players = game
.players
.iter()
.filter(|p| p.data.team == id as u8)
.collect::<Vec<_>>();
for player in players {
let mut listing = listing_scene.instantiate_as::<PlayerListing>();
listing.bind_mut().player_id = Some(player.id());
vbox.add_child(&listing);
}
}
if let Some(hbox) = &mut self.players_hbox {
hbox.add_child(&vbox);
}
}
}
}
fn produce_title(&mut self) { fn produce_title(&mut self) {
if let Some(game) = Game::singleton() { if let Some(game) = Game::singleton() {
let max_goals = game let max_goals = game

View File

@ -6,6 +6,7 @@ pub mod main_menu;
pub mod menu_player; pub mod menu_player;
pub mod net_stats; pub mod net_stats;
pub mod player_listing; pub mod player_listing;
pub mod player_listings;
pub mod settings; pub mod settings;
pub mod simple_score_view; pub mod simple_score_view;
pub mod slider; pub mod slider;

View File

@ -36,14 +36,29 @@ impl IHBoxContainer for PlayerListing {
impl PlayerListing { impl PlayerListing {
pub fn update(&mut self) { pub fn update(&mut self) {
if let Some(game) = Game::singleton() if let Some(game) = Game::singleton() {
&& let Some(player) = game.bind().find_player(self.player_id.unwrap_or(0)) if let Some(player_id) = self.player_id
{ && let Some(player) = game.bind().find_player(player_id)
if let Some(name_label) = &mut self.name_label { {
name_label.set_text(&player.data.name); if let Some(name_label) = &mut self.name_label {
} name_label.set_text(&player.data.name);
if let Some(ping_label) = &mut self.ping_label { }
ping_label.set_text(&format!("{}ms", player.data.ping)); if let Some(ping_label) = &mut self.ping_label {
ping_label.set_text(&player.data.ping.to_string());
}
} else {
if let Some(name_label) = &mut self.name_label {
name_label.set_text("Name");
}
if let Some(kills_label) = &mut self.kills_label {
kills_label.set_text("Kills");
}
if let Some(deaths_label) = &mut self.deaths_label {
deaths_label.set_text("Deaths");
}
if let Some(ping_label) = &mut self.ping_label {
ping_label.set_text("Ping");
}
} }
} }
} }

View File

@ -0,0 +1,66 @@
use godot::{
classes::{HBoxContainer, IHBoxContainer, Label, VBoxContainer, box_container::AlignmentMode},
global::HorizontalAlignment,
prelude::*,
};
use crate::{game_manager::Game, ui::player_listing::PlayerListing};
#[derive(GodotClass)]
#[class(base=HBoxContainer, init)]
pub struct PlayerListings {
#[export]
player_listing_scene: Option<Gd<PackedScene>>,
base: Base<HBoxContainer>,
}
#[godot_api]
impl IHBoxContainer for PlayerListings {
fn ready(&mut self) {
self.run_deferred(|s| s.update_player_listings());
}
}
impl PlayerListings {
pub fn update_player_listings(&mut self) {
for child in self.base().get_children().iter_shared() {
self.base_mut().remove_child(&child);
}
if let Some(game) = Game::singleton() {
for (id, team) in game.bind().get_teams().iter_shared().enumerate() {
let mut vbox = VBoxContainer::new_alloc();
vbox.set_alignment(AlignmentMode::BEGIN);
vbox.set_custom_minimum_size(Vector2::new(300., 0.));
let mut team_label = Label::new_alloc();
team_label.set_modulate(team.bind().color);
team_label.set_text(&team.bind().name);
team_label.set_horizontal_alignment(HorizontalAlignment::CENTER);
vbox.add_child(&team_label);
if let Some(listing_scene) = &self.player_listing_scene {
let game = game.bind();
let players = game
.players
.iter()
.filter(|p| p.data.team == id as u8)
.collect::<Vec<_>>();
let header = listing_scene.instantiate_as::<PlayerListing>();
vbox.add_child(&header);
for player in players {
let mut listing = listing_scene.instantiate_as::<PlayerListing>();
listing.bind_mut().player_id = Some(player.id());
vbox.add_child(&listing);
}
}
self.base_mut().add_child(&vbox);
}
}
}
}