Compare commits
7 Commits
8db0495242
...
f5cc26a048
| Author | SHA1 | Date | |
|---|---|---|---|
| f5cc26a048 | |||
| bda81f8c1e | |||
| 32d80dc0a3 | |||
| 147082bd8d | |||
| 623b9b8d95 | |||
| 9729f7bc7e | |||
| 3b0332ad6e |
@ -9,6 +9,7 @@
|
||||
[ext_resource type="Material" uid="uid://f4ne0rn5g5wh" path="res://maps/materials/green_ceiling_light.tres" id="7_8hfm3"]
|
||||
[ext_resource type="Material" uid="uid://1ine08aphdv7" path="res://maps/materials/orange_accent.tres" id="7_ap2uw"]
|
||||
[ext_resource type="LightmapGIData" uid="uid://hqspy3qsl5jd" path="res://maps/diner/diner.lmbake" id="9_g8xwm"]
|
||||
[ext_resource type="PackedScene" uid="uid://c1r8nk58cci3a" path="res://scenes/misc/goal.tscn" id="10_wffmg"]
|
||||
|
||||
[sub_resource type="ArrayMesh" id="ArrayMesh_o17ro"]
|
||||
lightmap_size_hint = Vector2i(354, 354)
|
||||
@ -540,8 +541,8 @@ indices = PackedInt32Array(0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10,
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_1cgct"]
|
||||
size = Vector3(1000, 10, 1000)
|
||||
|
||||
[node name="diner" type="Map" unique_id=1971127396 node_paths=PackedStringArray("spawner", "ball_spawner")]
|
||||
spawner = NodePath("spawner")
|
||||
[node name="diner" type="Map" unique_id=1971127396 node_paths=PackedStringArray("spawners", "ball_spawner")]
|
||||
spawners = [NodePath("spawner"), NodePath("spawner2")]
|
||||
ball_spawner = NodePath("ball_spawner")
|
||||
local_player = ExtResource("1_wffmg")
|
||||
remote_player = ExtResource("2_msi5w")
|
||||
@ -1057,6 +1058,9 @@ shadow_enabled = true
|
||||
[node name="spawner" type="Node3D" parent="." unique_id=2117785064]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -12.922944, 0.50108063, -0.19082117)
|
||||
|
||||
[node name="spawner2" type="Node3D" parent="." unique_id=1061070767]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 14.774757, 0.50108063, -14.130155)
|
||||
|
||||
[node name="killbox" type="Killbox" parent="." unique_id=1750431583]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -18.08466, 0)
|
||||
collision_layer = 7
|
||||
@ -1068,3 +1072,10 @@ shape = SubResource("BoxShape3D_1cgct")
|
||||
|
||||
[node name="ball_spawner" type="Node3D" parent="." unique_id=1771283598]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -4.6695356, 3.831614, 0.6756325)
|
||||
|
||||
[node name="goal2" parent="." unique_id=177528504 instance=ExtResource("10_wffmg")]
|
||||
team = 1
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 13.790253, -2.3841858e-07, -13.729624)
|
||||
|
||||
[node name="goal" parent="." unique_id=1795145790 instance=ExtResource("10_wffmg")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -13.09099, 0, -1.3568912)
|
||||
|
||||
57
godot/scenes/game_finished.tscn
Normal file
57
godot/scenes/game_finished.tscn
Normal file
@ -0,0 +1,57 @@
|
||||
[gd_scene format=3 uid="uid://df84sctteh4kw"]
|
||||
|
||||
[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")]
|
||||
title_container = NodePath("title_container")
|
||||
back_button = NodePath("button")
|
||||
players_hbox = NodePath("player_listings")
|
||||
player_listing_scene = ExtResource("1_ou354")
|
||||
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
|
||||
|
||||
[node name="button" type="Button" parent="." unique_id=1264024304]
|
||||
layout_mode = 1
|
||||
anchors_preset = 7
|
||||
anchor_left = 0.5
|
||||
anchor_top = 1.0
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -22.0
|
||||
offset_top = -103.0
|
||||
offset_right = 23.0
|
||||
offset_bottom = -69.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 0
|
||||
theme_override_font_sizes/font_size = 32
|
||||
text = "Back"
|
||||
|
||||
[node name="player_listings" type="HBoxContainer" parent="." unique_id=588134370]
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -186.0
|
||||
offset_top = -193.0
|
||||
offset_right = 186.0
|
||||
offset_bottom = -153.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
alignment = 1
|
||||
@ -1,8 +1,12 @@
|
||||
[gd_scene format=3 uid="uid://bii6018k3ip3t"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://bwd6bj21x310s" path="res://scenes/lobby.tscn" id="1_3ama4"]
|
||||
[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
|
||||
lobby_screen = ExtResource("1_3ama4")
|
||||
game_finished_screen = ExtResource("1_qf2qp")
|
||||
maps = Array[MapResource]([ExtResource("1_glms7"), ExtResource("2_glms7")])
|
||||
|
||||
35
godot/scenes/ui/player_listing.tscn
Normal file
35
godot/scenes/ui/player_listing.tscn
Normal file
@ -0,0 +1,35 @@
|
||||
[gd_scene format=3 uid="uid://2sfy0vq0fqt3"]
|
||||
|
||||
[node name="player_listing" type="PlayerListing" unique_id=965142972 node_paths=PackedStringArray("name_label", "kills_label", "deaths_label", "ping_label")]
|
||||
name_label = NodePath("name")
|
||||
kills_label = NodePath("kills")
|
||||
deaths_label = NodePath("deaths")
|
||||
ping_label = NodePath("ping")
|
||||
|
||||
[node name="name" type="Label" parent="." unique_id=1361759955]
|
||||
custom_minimum_size = Vector2(200, 0)
|
||||
custom_maximum_size = Vector2(200, -1)
|
||||
clip_contents = true
|
||||
layout_mode = 2
|
||||
text = "Player Name"
|
||||
|
||||
[node name="kills" type="Label" parent="." unique_id=690390687]
|
||||
custom_minimum_size = Vector2(30, 0)
|
||||
custom_maximum_size = Vector2(30, -1)
|
||||
layout_mode = 2
|
||||
text = "0"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="deaths" type="Label" parent="." unique_id=1615203485]
|
||||
custom_minimum_size = Vector2(30, 0)
|
||||
custom_maximum_size = Vector2(30, -1)
|
||||
layout_mode = 2
|
||||
text = "0"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="ping" type="Label" parent="." unique_id=1700548535]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
custom_maximum_size = Vector2(100, -1)
|
||||
layout_mode = 2
|
||||
text = "0ms"
|
||||
horizontal_alignment = 1
|
||||
@ -27,6 +27,10 @@ pub const GAME_MANAGER_GLOBAL: &str = "GameManagerGlobal";
|
||||
pub struct GameManager {
|
||||
#[export]
|
||||
pub respawn_timer: f64,
|
||||
#[export]
|
||||
pub lobby_screen: Option<Gd<PackedScene>>,
|
||||
#[export]
|
||||
pub game_finished_screen: Option<Gd<PackedScene>>,
|
||||
|
||||
pub game: Option<Gd<Game>>,
|
||||
base: Base<Node>,
|
||||
@ -73,6 +77,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.go_to_finish_screen());
|
||||
}
|
||||
});
|
||||
|
||||
@ -80,6 +87,18 @@ impl GameManager {
|
||||
|
||||
self.game = Some(game);
|
||||
}
|
||||
|
||||
pub fn go_to_finish_screen(&self) {
|
||||
if let Some(scene) = &self.game_finished_screen {
|
||||
self.base().get_tree().change_scene_to_packed(scene);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn go_to_lobby(&self) {
|
||||
if let Some(lobby) = &self.lobby_screen {
|
||||
self.base().get_tree().change_scene_to_packed(lobby);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GameOptions {
|
||||
@ -92,6 +111,7 @@ impl Default for GameOptions {
|
||||
opts.insert(GameOption::AllowAnyMap, GameOptionValue::Boolean(false));
|
||||
opts.insert(GameOption::AllowAnyTeam, GameOptionValue::Boolean(false));
|
||||
opts.insert(GameOption::FriendlyFire, GameOptionValue::Boolean(true));
|
||||
opts.insert(GameOption::GoalsNeededToWin, GameOptionValue::Number(10.));
|
||||
Self { values: opts }
|
||||
}
|
||||
}
|
||||
@ -118,6 +138,8 @@ pub enum GameOption {
|
||||
AllowAnyTeam,
|
||||
/// Allow anyone to shoot anyone, not just other team's members
|
||||
FriendlyFire,
|
||||
/// The number of goals needed to win a match
|
||||
GoalsNeededToWin,
|
||||
}
|
||||
|
||||
impl ToString for GameOption {
|
||||
@ -126,6 +148,7 @@ impl ToString for GameOption {
|
||||
GameOption::AllowAnyMap => "Allow anyone to select the map",
|
||||
GameOption::AllowAnyTeam => "Allow anyone to select any teams",
|
||||
GameOption::FriendlyFire => "Friendly fire",
|
||||
GameOption::GoalsNeededToWin => "Goals needed to win",
|
||||
}
|
||||
.to_owned()
|
||||
}
|
||||
@ -134,6 +157,7 @@ impl ToString for GameOption {
|
||||
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
|
||||
pub enum GameOptionValue {
|
||||
Boolean(bool),
|
||||
Number(f64),
|
||||
}
|
||||
|
||||
#[derive(GodotClass)]
|
||||
@ -254,6 +278,8 @@ impl Game {
|
||||
pub fn options_changed();
|
||||
#[signal]
|
||||
pub fn on_goal();
|
||||
#[signal]
|
||||
pub fn on_game_finished();
|
||||
|
||||
pub fn singleton() -> Option<Gd<Game>> {
|
||||
GameManager::singleton()
|
||||
@ -261,6 +287,51 @@ impl Game {
|
||||
.map(|g| g.cast::<Game>())
|
||||
}
|
||||
|
||||
pub fn reset_game(&mut self) {
|
||||
if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer
|
||||
&& let PeerKind::Server(peer, _) = peer
|
||||
&& let Some(player) = self.find_player_mut(self.self_id.unwrap_or(0))
|
||||
{
|
||||
player.data.ready = true;
|
||||
peer.broadcast_reliable(Package::SetReady(player.id(), true));
|
||||
}
|
||||
self.goals.clear();
|
||||
}
|
||||
|
||||
pub fn finish_game(&mut self) {
|
||||
for player in &mut self.players {
|
||||
if let Some(mut character) = player.character.take() {
|
||||
character.queue_free();
|
||||
}
|
||||
player.data.ready = false;
|
||||
}
|
||||
|
||||
self.run_deferred(|s| {
|
||||
if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer
|
||||
&& let PeerKind::Server(peer, _) = peer
|
||||
{
|
||||
for player in &s.players {
|
||||
peer.broadcast_reliable(Package::SetReady(player.id(), false));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(mut ball) = self.world_ball.take() {
|
||||
ball.queue_free();
|
||||
}
|
||||
self.current_map.take();
|
||||
self.game_started = false;
|
||||
|
||||
self.run_deferred(|s| {
|
||||
if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer
|
||||
&& let PeerKind::Server(peer, _) = peer
|
||||
{
|
||||
peer.broadcast_reliable(Package::FinishGame);
|
||||
}
|
||||
s.signals().on_game_finished().emit()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn change_option(&mut self, opt: GameOption, value: GameOptionValue) {
|
||||
self.opts.values.insert(opt, value);
|
||||
self.run_deferred(move |s| {
|
||||
@ -377,8 +448,8 @@ impl Game {
|
||||
name: name.unwrap_or(format!("Player {}", id)),
|
||||
ping: 0,
|
||||
team: 0,
|
||||
ready: false,
|
||||
},
|
||||
ready: false,
|
||||
character: None,
|
||||
});
|
||||
self.run_deferred(move |s| s.signals().on_new_player().emit(id));
|
||||
@ -451,7 +522,7 @@ impl Game {
|
||||
|
||||
pub fn update_player_ready(&mut self, player_id: u16, ready: bool) {
|
||||
if let Some(player) = self.players.iter_mut().find(|p| p.id() == player_id) {
|
||||
player.ready = ready;
|
||||
player.data.ready = ready;
|
||||
}
|
||||
self.run_deferred(|s| s.signals().on_players_updated().emit());
|
||||
}
|
||||
@ -531,6 +602,21 @@ impl Game {
|
||||
peer.broadcast_reliable(Package::Goal(teams));
|
||||
}
|
||||
}
|
||||
if NetworkManager::singleton().bind().is_host() {
|
||||
let max_goals = s.goals.values().max().copied().unwrap_or(0);
|
||||
let needed_goals = match s
|
||||
.opts
|
||||
.values
|
||||
.get(&GameOption::GoalsNeededToWin)
|
||||
.unwrap_or(&&GameOptionValue::Number(10.))
|
||||
{
|
||||
GameOptionValue::Boolean(_) => 10,
|
||||
GameOptionValue::Number(value) => *value as u16,
|
||||
};
|
||||
if max_goals >= needed_goals {
|
||||
s.finish_game();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -754,7 +840,6 @@ impl Game {
|
||||
pub struct Player {
|
||||
pub connection_addr: SocketAddr,
|
||||
pub data: NetPlayer,
|
||||
pub ready: bool,
|
||||
pub character: Option<DynGd<CharacterBody3D, dyn IPlayer + 'static>>,
|
||||
}
|
||||
|
||||
@ -857,6 +942,7 @@ impl Player {
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct NetPlayer {
|
||||
pub id: u16,
|
||||
pub ready: bool,
|
||||
pub name: String,
|
||||
pub ping: u128,
|
||||
pub team: u8,
|
||||
@ -867,7 +953,6 @@ impl From<NetPlayer> for Player {
|
||||
Player {
|
||||
connection_addr: SocketAddr::from(([0, 0, 0, 0], 0)),
|
||||
data: value,
|
||||
ready: false,
|
||||
character: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,9 +19,6 @@ use crate::{
|
||||
#[derive(GodotClass)]
|
||||
#[class(base=Node)]
|
||||
pub struct NetworkManager {
|
||||
#[export]
|
||||
lobby_scene: Option<Gd<PackedScene>>,
|
||||
|
||||
pub peer: Option<PeerKind>,
|
||||
|
||||
last_hello: Instant,
|
||||
@ -37,8 +34,6 @@ pub const NETWORK_SINGLETON_NAME: &str = "NetworkManagerGlob";
|
||||
impl INode for NetworkManager {
|
||||
fn init(base: Base<Node>) -> Self {
|
||||
NetworkManager {
|
||||
lobby_scene: None,
|
||||
|
||||
peer: None,
|
||||
|
||||
last_hello: Instant::now(),
|
||||
@ -219,10 +214,8 @@ impl NetworkManager {
|
||||
}
|
||||
|
||||
pub fn swap_to_lobby(&self, is_host: bool) {
|
||||
if let Some(scene) = &self.lobby_scene {
|
||||
self.base().get_tree().change_scene_to_packed(scene);
|
||||
GameManager::singleton().bind_mut().init_game(is_host);
|
||||
}
|
||||
GameManager::singleton().bind_mut().init_game(is_host);
|
||||
GameManager::singleton().bind().go_to_lobby();
|
||||
}
|
||||
|
||||
pub fn update_nick(&mut self, nick: String) {
|
||||
@ -276,6 +269,9 @@ pub enum Package {
|
||||
DespawnBall,
|
||||
SwapWeapon(u16, WeaponType),
|
||||
Goal(Vec<u8>),
|
||||
|
||||
// End-of-Game packages
|
||||
FinishGame,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
|
||||
@ -176,6 +176,11 @@ impl NetworkManager {
|
||||
game.bind_mut().handle_goal(teams);
|
||||
}
|
||||
}
|
||||
Package::FinishGame => {
|
||||
if let Some(game) = &mut Game::singleton() {
|
||||
game.bind_mut().finish_game();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
},
|
||||
|
||||
@ -528,6 +528,10 @@ impl ICharacterBody3D for LocalPlayer {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn exit_tree(&mut self) {
|
||||
self.set_lock(false);
|
||||
}
|
||||
}
|
||||
|
||||
#[godot_api]
|
||||
|
||||
124
rust/src/ui/game_finished_screen.rs
Normal file
124
rust/src/ui/game_finished_screen.rs
Normal file
@ -0,0 +1,124 @@
|
||||
use godot::{
|
||||
classes::{
|
||||
Button, HBoxContainer, IPanel, Label, Panel, VBoxContainer, box_container::AlignmentMode,
|
||||
control::LayoutDirection,
|
||||
},
|
||||
global::{HorizontalAlignment, VerticalAlignment},
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
game_manager::{Game, GameManager},
|
||||
ui::player_listing::PlayerListing,
|
||||
};
|
||||
|
||||
#[derive(GodotClass)]
|
||||
#[class(base=Panel, init)]
|
||||
pub struct GameFinishedScreen {
|
||||
#[export]
|
||||
title_container: Option<Gd<HBoxContainer>>,
|
||||
#[export]
|
||||
back_button: Option<Gd<Button>>,
|
||||
#[export]
|
||||
players_hbox: Option<Gd<HBoxContainer>>,
|
||||
#[export]
|
||||
player_listing_scene: Option<Gd<PackedScene>>,
|
||||
|
||||
base: Base<Panel>,
|
||||
}
|
||||
|
||||
#[godot_api]
|
||||
impl IPanel for GameFinishedScreen {
|
||||
fn ready(&mut self) {
|
||||
self.produce_title();
|
||||
self.produce_player_listings();
|
||||
if let Some(back) = &self.back_button {
|
||||
back.signals().pressed().connect_other(self, |_| {
|
||||
if let Some(mut game) = Game::singleton() {
|
||||
game.bind_mut().reset_game();
|
||||
}
|
||||
GameManager::singleton().bind().go_to_lobby();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,8 +2,8 @@ use std::collections::HashMap;
|
||||
|
||||
use godot::{
|
||||
classes::{
|
||||
Button, CheckBox, Control, GridContainer, IPanel, Label, OptionButton, Panel, TextEdit,
|
||||
VBoxContainer,
|
||||
Button, CheckBox, Control, GridContainer, IPanel, Label, OptionButton, Panel, SpinBox,
|
||||
TextEdit, VBoxContainer,
|
||||
},
|
||||
prelude::*,
|
||||
};
|
||||
@ -162,6 +162,22 @@ impl IPanel for LobbyPanel {
|
||||
|
||||
checkbox.upcast::<Control>()
|
||||
}
|
||||
GameOptionValue::Number(value) => {
|
||||
let mut spinbox = SpinBox::new_alloc();
|
||||
spinbox.set_value(*value);
|
||||
spinbox.set_editable(NetworkManager::singleton().bind().is_host());
|
||||
|
||||
let spinbox_clone = spinbox.clone();
|
||||
let option = option.clone();
|
||||
spinbox.signals().changed().connect_other(self, move |s| {
|
||||
s.option_changed(
|
||||
option,
|
||||
GameOptionValue::Number(spinbox_clone.get_value()),
|
||||
);
|
||||
});
|
||||
|
||||
spinbox.upcast()
|
||||
}
|
||||
};
|
||||
nodes.push(value_node);
|
||||
}
|
||||
@ -209,6 +225,11 @@ impl LobbyPanel {
|
||||
checkbox.set_pressed(*value);
|
||||
}
|
||||
}
|
||||
GameOptionValue::Number(value) => {
|
||||
if let Ok(mut spinbox) = control.try_cast::<SpinBox>() {
|
||||
spinbox.set_value(*value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -221,7 +242,7 @@ impl LobbyPanel {
|
||||
if let PeerKind::Server(_, _) = peer
|
||||
&& let Some(button) = &mut self.ready_button
|
||||
{
|
||||
let all_ready = game.bind().players.iter().all(|p| p.ready);
|
||||
let all_ready = game.bind().players.iter().all(|p| p.data.ready);
|
||||
button.set_disabled(!all_ready);
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,7 +93,7 @@ impl LobbyPlayerListing {
|
||||
}
|
||||
|
||||
if let Some(ready_label) = &mut self.ready_label {
|
||||
if player.ready {
|
||||
if player.data.ready {
|
||||
ready_label.set_text("Ready");
|
||||
} else {
|
||||
ready_label.set_text("Not Ready");
|
||||
@ -130,7 +130,6 @@ impl LobbyPlayerListing {
|
||||
&& let Some(player_label) = &mut self.name_label
|
||||
&& let Some(team) = game.bind().get_team(player.data.team)
|
||||
{
|
||||
godot_print!("Setting color");
|
||||
player_label.add_theme_color_override("font_color", team.bind().color);
|
||||
}
|
||||
}
|
||||
@ -146,7 +145,6 @@ impl LobbyPlayerListing {
|
||||
&& let Some(player_label) = &mut self.name_label
|
||||
&& let Some(team) = game.bind().get_team(player.data.team)
|
||||
{
|
||||
godot_print!("Setting color");
|
||||
player_label.add_theme_color_override("font_color", team.bind().color);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
pub mod cli;
|
||||
pub mod game_finished_screen;
|
||||
pub mod lobby;
|
||||
pub mod lobby_player_listing;
|
||||
pub mod net_stats;
|
||||
pub mod player_listing;
|
||||
pub mod simple_score_view;
|
||||
|
||||
50
rust/src/ui/player_listing.rs
Normal file
50
rust/src/ui/player_listing.rs
Normal file
@ -0,0 +1,50 @@
|
||||
use godot::{
|
||||
classes::{HBoxContainer, IHBoxContainer, Label},
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
use crate::game_manager::Game;
|
||||
|
||||
#[derive(GodotClass)]
|
||||
#[class(base=HBoxContainer, init)]
|
||||
pub struct PlayerListing {
|
||||
#[export]
|
||||
name_label: Option<Gd<Label>>,
|
||||
#[export]
|
||||
kills_label: Option<Gd<Label>>,
|
||||
#[export]
|
||||
deaths_label: Option<Gd<Label>>,
|
||||
#[export]
|
||||
ping_label: Option<Gd<Label>>,
|
||||
|
||||
pub player_id: Option<u16>,
|
||||
|
||||
base: Base<HBoxContainer>,
|
||||
}
|
||||
|
||||
#[godot_api]
|
||||
impl IHBoxContainer for PlayerListing {
|
||||
fn ready(&mut self) {
|
||||
self.update();
|
||||
if let Some(game) = Game::singleton() {
|
||||
game.signals()
|
||||
.on_players_updated()
|
||||
.connect_other(self, |s| s.update());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PlayerListing {
|
||||
pub fn update(&mut self) {
|
||||
if let Some(game) = Game::singleton()
|
||||
&& let Some(player) = game.bind().find_player(self.player_id.unwrap_or(0))
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user