Compare commits

..

3 Commits

Author SHA1 Message Date
8db0495242 add CREDITS.md 2026-07-22 20:40:59 +03:00
fc44f23092 Rename player_listing to lobby_player_listing 2026-07-22 20:30:32 +03:00
736dbe4c3b Add simple score view 2026-07-22 20:29:14 +03:00
9 changed files with 85 additions and 11 deletions

4
CREDITS.md Normal file
View File

@ -0,0 +1,4 @@
- [Sound effects](Assets/Audio/Sfx/ZapSplat) from [zapsplat.com](https://www.zapsplat.com/)
- [LaserFast and LaserWithRecovery](godot/assets/)
- [Hit](godot/assets/Hit.mp3)
- [Soldier model and rig](godot/RawAssets/Soldier/) by [Casti_131](https://opengameart.org/content/low-poly-soldier-with-weapons)

View File

@ -1,6 +1,6 @@
[gd_scene format=3 uid="uid://bwd6bj21x310s"] [gd_scene format=3 uid="uid://bwd6bj21x310s"]
[ext_resource type="PackedScene" uid="uid://ccd0wj2usx5os" path="res://scenes/ui/player_listing.tscn" id="1_o1atq"] [ext_resource type="PackedScene" uid="uid://ccd0wj2usx5os" path="res://scenes/ui/lobby_player_listing.tscn" id="1_o1atq"]
[sub_resource type="LabelSettings" id="LabelSettings_1cgct"] [sub_resource type="LabelSettings" id="LabelSettings_1cgct"]
font_size = 32 font_size = 32

View File

@ -57,3 +57,14 @@ offset_bottom = 11.5
grow_horizontal = 2 grow_horizontal = 2
grow_vertical = 2 grow_vertical = 2
horizontal_alignment = 1 horizontal_alignment = 1
[node name="score_view" type="SimpleScoreView" parent="." unique_id=1128041371]
anchors_preset = 5
anchor_left = 0.5
anchor_right = 0.5
offset_left = -20.0
offset_top = 18.0
offset_right = 20.0
offset_bottom = 58.0
grow_horizontal = 2
alignment = 1

View File

@ -1,11 +1,11 @@
[gd_scene format=3 uid="uid://ccd0wj2usx5os"] [gd_scene format=3 uid="uid://ccd0wj2usx5os"]
[node name="player_listing" type="PlayerListing" unique_id=772938280 node_paths=PackedStringArray("name_label", "ping_label", "ready_label", "team_dropdown")] [node name="lobby_player_listing" type="LobbyPlayerListing" unique_id=887620055 node_paths=PackedStringArray("name_label", "ping_label", "ready_label", "team_dropdown")]
name_label = NodePath("name") name_label = NodePath("name")
ping_label = NodePath("ping") ping_label = NodePath("ping")
ready_label = NodePath("ready") ready_label = NodePath("ready")
team_dropdown = NodePath("option_button") team_dropdown = NodePath("option_button")
offset_right = 319.0 offset_right = 673.0
offset_bottom = 23.0 offset_bottom = 23.0
columns = 4 columns = 4

View File

@ -252,6 +252,8 @@ impl Game {
pub fn on_map_changed(id: u8); pub fn on_map_changed(id: u8);
#[signal] #[signal]
pub fn options_changed(); pub fn options_changed();
#[signal]
pub fn on_goal();
pub fn singleton() -> Option<Gd<Game>> { pub fn singleton() -> Option<Gd<Game>> {
GameManager::singleton() GameManager::singleton()
@ -522,7 +524,8 @@ impl Game {
self.goals self.goals
.insert(*team, self.goals.get(&team).copied().unwrap_or(0) + 1); .insert(*team, self.goals.get(&team).copied().unwrap_or(0) + 1);
} }
self.run_deferred(move |_| { self.run_deferred(move |s| {
s.signals().on_goal().emit();
if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer { if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer {
if let PeerKind::Server(peer, _) = peer { if let PeerKind::Server(peer, _) = peer {
peer.broadcast_reliable(Package::Goal(teams)); peer.broadcast_reliable(Package::Goal(teams));

View File

@ -11,7 +11,7 @@ use godot::{
use crate::{ use crate::{
game_manager::{Game, GameManager, GameOption, GameOptionValue, GameOptions}, game_manager::{Game, GameManager, GameOption, GameOptionValue, GameOptions},
net::network_manager::{NetworkManager, Package, PeerKind}, net::network_manager::{NetworkManager, Package, PeerKind},
ui::player_listing::PlayerListing, ui::lobby_player_listing::LobbyPlayerListing,
}; };
#[derive(GodotClass)] #[derive(GodotClass)]
@ -239,7 +239,7 @@ impl LobbyPanel {
if let Some(prefab) = &self.player_listing_prefab { if let Some(prefab) = &self.player_listing_prefab {
for player in &game.bind().players { for player in &game.bind().players {
if let Some(node) = prefab.instantiate() { if let Some(node) = prefab.instantiate() {
let mut listing = node.cast::<PlayerListing>(); let mut listing = node.cast::<LobbyPlayerListing>();
listing.bind_mut().player_id = Some(player.id()); listing.bind_mut().player_id = Some(player.id());
listing.bind_mut().update_teams(game.bind().get_teams()); listing.bind_mut().update_teams(game.bind().get_teams());
listing.bind_mut().update(); listing.bind_mut().update();
@ -250,7 +250,7 @@ impl LobbyPanel {
} }
} else { } else {
for child in list.get_children().iter_shared() { for child in list.get_children().iter_shared() {
let mut listing = child.cast::<PlayerListing>(); let mut listing = child.cast::<LobbyPlayerListing>();
if let Some(game) = Game::singleton() { if let Some(game) = Game::singleton() {
listing.bind_mut().update_teams(game.bind().get_teams()); listing.bind_mut().update_teams(game.bind().get_teams());
} }

View File

@ -11,7 +11,7 @@ use crate::{
#[derive(GodotClass)] #[derive(GodotClass)]
#[class(base=GridContainer, init)] #[class(base=GridContainer, init)]
pub struct PlayerListing { pub struct LobbyPlayerListing {
#[export] #[export]
pub name_label: Option<Gd<Label>>, pub name_label: Option<Gd<Label>>,
#[export] #[export]
@ -27,7 +27,7 @@ pub struct PlayerListing {
} }
#[godot_api] #[godot_api]
impl IGridContainer for PlayerListing { impl IGridContainer for LobbyPlayerListing {
fn ready(&mut self) { fn ready(&mut self) {
self.run_deferred(|s| { self.run_deferred(|s| {
if let Some(game) = &mut Game::singleton() { if let Some(game) = &mut Game::singleton() {
@ -65,7 +65,7 @@ impl IGridContainer for PlayerListing {
} }
} }
impl PlayerListing { impl LobbyPlayerListing {
pub fn update_game_options(&mut self, opts: &GameOptions, self_id: Option<u16>) { pub fn update_game_options(&mut self, opts: &GameOptions, self_id: Option<u16>) {
let is_host = NetworkManager::singleton().bind().is_host(); let is_host = NetworkManager::singleton().bind().is_host();

View File

@ -1,4 +1,5 @@
pub mod cli; pub mod cli;
pub mod lobby; pub mod lobby;
pub mod lobby_player_listing;
pub mod net_stats; pub mod net_stats;
pub mod player_listing; pub mod simple_score_view;

View File

@ -0,0 +1,55 @@
use std::collections::HashMap;
use godot::{
classes::{HBoxContainer, IHBoxContainer, Label},
prelude::*,
};
use crate::game_manager::Game;
#[derive(GodotClass)]
#[class(base=HBoxContainer, init)]
pub struct SimpleScoreView {
team_goals: HashMap<u8, Gd<Label>>,
base: Base<HBoxContainer>,
}
#[godot_api]
impl IHBoxContainer for SimpleScoreView {
fn ready(&mut self) {
self.run_deferred(|s| {
if let Some(game) = Game::singleton() {
for (id, team) in game.bind().get_teams().iter_shared().enumerate() {
let mut goals_label = Label::new_alloc();
goals_label.set_modulate(team.bind().color);
goals_label.set_text("0");
if !s.team_goals.is_empty() {
let mut dash = Label::new_alloc();
dash.set_text(" - ");
s.base_mut().add_child(&dash);
}
s.base_mut().add_child(&goals_label);
s.team_goals.insert(id as u8, goals_label);
}
game.signals()
.on_goal()
.connect_other(s, |s| s.update_goals());
}
});
}
}
impl SimpleScoreView {
pub fn update_goals(&mut self) {
if let Some(game) = Game::singleton() {
for (id, _) in game.bind().get_teams().iter_shared().enumerate() {
if let Some(goals) = game.bind().goals.get(&(id as u8))
&& let Some(label) = self.team_goals.get_mut(&(id as u8))
{
label.set_text(&goals.to_string());
}
}
}
}
}