Add simple finish game screen

This commit is contained in:
Sofia 2026-07-22 21:19:44 +03:00
parent 03f4dcba41
commit e1ad6b12d7
6 changed files with 126 additions and 0 deletions

View File

@ -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

View File

@ -1,8 +1,10 @@
[gd_scene format=3 uid="uid://bii6018k3ip3t"] [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="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"] [ext_resource type="MapResource" uid="uid://bsjoandgu476y" path="res://maps/diner.tres" id="2_glms7"]
[node name="game_manager" type="GameManager" unique_id=1442044769] [node name="game_manager" type="GameManager" unique_id=1442044769]
respawn_timer = 10.0 respawn_timer = 10.0
game_finished_screen = ExtResource("1_qf2qp")
maps = Array[MapResource]([ExtResource("1_glms7"), ExtResource("2_glms7")]) maps = Array[MapResource]([ExtResource("1_glms7"), ExtResource("2_glms7")])

View File

@ -27,6 +27,8 @@ pub const GAME_MANAGER_GLOBAL: &str = "GameManagerGlobal";
pub struct GameManager { pub struct GameManager {
#[export] #[export]
pub respawn_timer: f64, pub respawn_timer: f64,
#[export]
pub game_finished_screen: Option<Gd<PackedScene>>,
pub game: Option<Gd<Game>>, pub game: Option<Gd<Game>>,
base: Base<Node>, base: Base<Node>,
@ -73,6 +75,9 @@ impl GameManager {
game.signals() game.signals()
.on_map_changed() .on_map_changed()
.connect_other(s, |s, id| s.signals().on_map_changed().emit(id)); .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); 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 { pub struct GameOptions {
@ -254,6 +265,8 @@ impl Game {
pub fn options_changed(); pub fn options_changed();
#[signal] #[signal]
pub fn on_goal(); pub fn on_goal();
#[signal]
pub fn on_game_finished();
pub fn singleton() -> Option<Gd<Game>> { pub fn singleton() -> Option<Gd<Game>> {
GameManager::singleton() 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) { pub fn handle_ball_pickup(&mut self, player_id: u16) {

View File

@ -528,6 +528,10 @@ impl ICharacterBody3D for LocalPlayer {
} }
} }
} }
fn exit_tree(&mut self) {
self.set_lock(false);
}
} }
#[godot_api] #[godot_api]

View File

@ -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<Gd<HBoxContainer>>,
base: Base<Panel>,
}
#[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::<Vec<_>>();
let winning_teams = game
.bind()
.get_teams()
.iter_shared()
.enumerate()
.filter(|(id, _)| winning_team_ids.contains(&((*id) as u8)))
.map(|(_, team)| team)
.collect::<Vec<_>>();
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);
}
}
}
}

View File

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