diff --git a/godot/scenes/game_finished.tscn b/godot/scenes/game_finished.tscn new file mode 100644 index 0000000..4d1a973 --- /dev/null +++ b/godot/scenes/game_finished.tscn @@ -0,0 +1,21 @@ +[gd_scene format=3 uid="uid://df84sctteh4kw"] + +[node name="game_finished" type="GameFinishedScreen" unique_id=700430082 node_paths=PackedStringArray("title_container")] +title_container = NodePath("title_container") +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="title_container" type="HBoxContainer" parent="." unique_id=980404596] +layout_mode = 1 +anchors_preset = 5 +anchor_left = 0.5 +anchor_right = 0.5 +offset_left = -168.0 +offset_top = 55.0 +offset_right = 168.0 +offset_bottom = 110.0 +grow_horizontal = 2 +alignment = 1 diff --git a/godot/scenes/misc/game_manager.tscn b/godot/scenes/misc/game_manager.tscn index 45863cd..bd17bfc 100644 --- a/godot/scenes/misc/game_manager.tscn +++ b/godot/scenes/misc/game_manager.tscn @@ -1,8 +1,10 @@ [gd_scene format=3 uid="uid://bii6018k3ip3t"] [ext_resource type="MapResource" uid="uid://c7n1tacc7a73t" path="res://maps/default_map.tres" id="1_glms7"] +[ext_resource type="PackedScene" uid="uid://df84sctteh4kw" path="res://scenes/game_finished.tscn" id="1_qf2qp"] [ext_resource type="MapResource" uid="uid://bsjoandgu476y" path="res://maps/diner.tres" id="2_glms7"] [node name="game_manager" type="GameManager" unique_id=1442044769] respawn_timer = 10.0 +game_finished_screen = ExtResource("1_qf2qp") maps = Array[MapResource]([ExtResource("1_glms7"), ExtResource("2_glms7")]) diff --git a/rust/src/game_manager.rs b/rust/src/game_manager.rs index af0f7e9..fc67a57 100644 --- a/rust/src/game_manager.rs +++ b/rust/src/game_manager.rs @@ -27,6 +27,8 @@ pub const GAME_MANAGER_GLOBAL: &str = "GameManagerGlobal"; pub struct GameManager { #[export] pub respawn_timer: f64, + #[export] + pub game_finished_screen: Option>, pub game: Option>, base: Base, @@ -73,6 +75,9 @@ impl GameManager { game.signals() .on_map_changed() .connect_other(s, |s, id| s.signals().on_map_changed().emit(id)); + game.signals() + .on_game_finished() + .connect_other(s, |s| s.on_game_finished()); } }); @@ -80,6 +85,12 @@ impl GameManager { self.game = Some(game); } + + pub fn on_game_finished(&mut self) { + if let Some(scene) = &self.game_finished_screen { + self.base().get_tree().change_scene_to_packed(scene); + } + } } pub struct GameOptions { @@ -254,6 +265,8 @@ impl Game { pub fn options_changed(); #[signal] pub fn on_goal(); + #[signal] + pub fn on_game_finished(); pub fn singleton() -> Option> { GameManager::singleton() @@ -532,6 +545,22 @@ impl Game { } } }); + let max_goals = self.goals.values().max().copied().unwrap_or(0); + if max_goals >= 1 { + self.finish_game(); + } + } + + pub fn finish_game(&mut self) { + for player in &mut self.players { + if let Some(mut character) = player.character.take() { + character.queue_free(); + } + } + if let Some(mut ball) = self.world_ball.take() { + ball.queue_free(); + } + self.run_deferred(|s| s.signals().on_game_finished().emit()); } pub fn handle_ball_pickup(&mut self, player_id: u16) { diff --git a/rust/src/player.rs b/rust/src/player.rs index 5fa5d51..54374ee 100644 --- a/rust/src/player.rs +++ b/rust/src/player.rs @@ -528,6 +528,10 @@ impl ICharacterBody3D for LocalPlayer { } } } + + fn exit_tree(&mut self) { + self.set_lock(false); + } } #[godot_api] diff --git a/rust/src/ui/game_finished_screen.rs b/rust/src/ui/game_finished_screen.rs new file mode 100644 index 0000000..9d4e5c4 --- /dev/null +++ b/rust/src/ui/game_finished_screen.rs @@ -0,0 +1,69 @@ +use godot::{ + classes::{HBoxContainer, IPanel, Label, Panel}, + prelude::*, +}; + +use crate::game_manager::Game; + +#[derive(GodotClass)] +#[class(base=Panel, init)] +pub struct GameFinishedScreen { + #[export] + title_container: Option>, + + base: Base, +} + +#[godot_api] +impl IPanel for GameFinishedScreen { + fn ready(&mut self) { + self.produce_title(); + } +} + +impl GameFinishedScreen { + fn produce_title(&mut self) { + if let Some(game) = Game::singleton() { + let max_goals = game + .bind() + .goals + .iter() + .map(|(_, v)| v) + .max() + .copied() + .unwrap_or(0); + let winning_team_ids = game + .bind() + .goals + .iter() + .filter(|(_, goals)| **goals == max_goals) + .map(|(team, _)| *team) + .collect::>(); + let winning_teams = game + .bind() + .get_teams() + .iter_shared() + .enumerate() + .filter(|(id, _)| winning_team_ids.contains(&((*id) as u8))) + .map(|(_, team)| team) + .collect::>(); + + if let Some(container) = &mut self.title_container { + for (idx, team) in winning_teams.iter().enumerate() { + let mut label = Label::new_alloc(); + label.set_text(&team.bind().name); + label.set_modulate(team.bind().color); + if idx > 0 { + let mut and_label = Label::new_alloc(); + and_label.set_text(" and "); + container.add_child(&and_label); + } + container.add_child(&label); + } + let mut end = Label::new_alloc(); + end.set_text(" victory!"); + container.add_child(&end); + } + } + } +} diff --git a/rust/src/ui/mod.rs b/rust/src/ui/mod.rs index 659fc53..7eaa545 100644 --- a/rust/src/ui/mod.rs +++ b/rust/src/ui/mod.rs @@ -1,4 +1,5 @@ pub mod cli; +pub mod game_finished_screen; pub mod lobby; pub mod lobby_player_listing; pub mod net_stats;