Compare commits
4 Commits
6992bc5eff
...
e64bcc0427
| Author | SHA1 | Date | |
|---|---|---|---|
| e64bcc0427 | |||
| ba1b1bf6f1 | |||
| f5f375db1e | |||
| 2384eb90ba |
@ -1,6 +1,10 @@
|
||||
[gd_scene format=3 uid="uid://djmb2jqcpkuep"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://d3377ecff6nyn" path="res://scenes/replay_finished.tscn" id="1_q5ujf"]
|
||||
[ext_resource type="PackedScene" uid="uid://c1gs6cqek1qlq" path="res://scenes/ui/hud.tscn" id="2_a451s"]
|
||||
[ext_resource type="PackedScene" uid="uid://lahirbqfppvw" path="res://scenes/main.tscn" id="2_r7g00"]
|
||||
|
||||
[node name="standalone_replay_global" type="StandaloneReplayManager" unique_id=730657724]
|
||||
replay_finished_screen = ExtResource("1_q5ujf")
|
||||
main_menu = ExtResource("2_r7g00")
|
||||
hud_scene = ExtResource("2_a451s")
|
||||
|
||||
@ -2,21 +2,13 @@
|
||||
|
||||
[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/effects.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://2sfy0vq0fqt3" path="res://scenes/ui/player_listing.tscn" id="4_okac2"]
|
||||
[ext_resource type="PackedScene" uid="uid://ffh5txda3j1" path="res://scenes/ui/chat_box.tscn" id="5_cv68x"]
|
||||
[ext_resource type="PackedScene" uid="uid://c1gs6cqek1qlq" path="res://scenes/ui/hud.tscn" id="5_cv68x"]
|
||||
[ext_resource type="Texture2D" uid="uid://bdfqu6p74pfwe" path="res://raw_assets/crosshair/Crosshair 1.png" id="6_7awel"]
|
||||
[ext_resource type="AudioStream" uid="uid://bfg31e3s4jv8c" path="res://raw_assets/sfx/Hit.mp3" id="7_dguuj"]
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_oh8vq"]
|
||||
|
||||
[sub_resource type="LabelSettings" id="LabelSettings_7awel"]
|
||||
font_size = 32
|
||||
font_color = Color(1, 0, 0, 1)
|
||||
outline_size = 10
|
||||
outline_color = Color(0, 0, 0, 1)
|
||||
|
||||
[node name="player" type="LocalPlayer" unique_id=863055906 node_paths=PackedStringArray("camera", "soldier_mesh", "collider", "effects", "dead_cam_target", "respawn_label", "camera_origin", "weapon_node", "pause_panel", "exit_to_lobby", "settings_panel", "scoreboard", "chatbox", "health_label", "hit_sound")]
|
||||
[node name="player" type="LocalPlayer" unique_id=863055906 node_paths=PackedStringArray("camera", "soldier_mesh", "collider", "effects", "dead_cam_target", "respawn_label", "camera_origin", "weapon_node", "hud", "hit_sound")]
|
||||
look_sensitivity = 1.5
|
||||
camera = NodePath("camera_3d")
|
||||
move_speed = 7.0
|
||||
@ -27,12 +19,7 @@ dead_cam_target = NodePath("dead_camera_target")
|
||||
respawn_label = NodePath("respawn_label")
|
||||
camera_origin = NodePath("camera_3d")
|
||||
weapon_node = NodePath("camera_3d/weapon_node")
|
||||
pause_panel = NodePath("pause_menu")
|
||||
exit_to_lobby = NodePath("pause_menu/v_box_container/exit_to_lobby")
|
||||
settings_panel = NodePath("settings")
|
||||
scoreboard = NodePath("scoreboard")
|
||||
chatbox = NodePath("chat_box")
|
||||
health_label = NodePath("health_label")
|
||||
hud = NodePath("hud")
|
||||
hit_sound = NodePath("hit_sound")
|
||||
health = 100
|
||||
punch_cooldown = 1.0
|
||||
@ -91,99 +78,11 @@ grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
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
|
||||
|
||||
[node name="pause_menu" type="Panel" parent="." unique_id=1542204162]
|
||||
visible = false
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -67.75
|
||||
offset_top = -101.25
|
||||
offset_right = 67.75
|
||||
offset_bottom = 101.25
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="v_box_container" type="VBoxContainer" parent="pause_menu" unique_id=839758321]
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -20.0
|
||||
offset_top = -20.0
|
||||
offset_right = 20.0
|
||||
offset_bottom = 20.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
alignment = 1
|
||||
|
||||
[node name="settings" type="Button" parent="pause_menu/v_box_container" unique_id=676182211]
|
||||
layout_mode = 2
|
||||
text = "Settings"
|
||||
|
||||
[node name="exit_to_lobby" type="Button" parent="pause_menu/v_box_container" unique_id=1816170399]
|
||||
layout_mode = 2
|
||||
text = "Exit to Lobby"
|
||||
|
||||
[node name="exit" type="Button" parent="pause_menu/v_box_container" unique_id=641638697]
|
||||
layout_mode = 2
|
||||
text = "Exit"
|
||||
|
||||
[node name="settings" parent="." unique_id=999912383 instance=ExtResource("3_beej8")]
|
||||
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
|
||||
|
||||
[node name="chat_box" parent="." unique_id=1125601400 instance=ExtResource("5_cv68x")]
|
||||
in_game = true
|
||||
|
||||
[node name="health_label" type="Label" parent="." unique_id=651212450]
|
||||
anchors_preset = 2
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 34.0
|
||||
offset_top = -45.0
|
||||
offset_right = 74.0
|
||||
offset_bottom = -22.0
|
||||
grow_vertical = 0
|
||||
text = "100"
|
||||
label_settings = SubResource("LabelSettings_7awel")
|
||||
vertical_alignment = 2
|
||||
|
||||
[node name="hit_sound" type="AudioStreamPlayer" parent="." unique_id=1224745673]
|
||||
stream = ExtResource("7_dguuj")
|
||||
bus = &"SFX"
|
||||
|
||||
[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="." method="exit"]
|
||||
[node name="hud" parent="." unique_id=2049159590 instance=ExtResource("5_cv68x")]
|
||||
|
||||
[connection signal="on_exit" from="hud" to="." method="exit"]
|
||||
[connection signal="on_exit_to_lobby" from="hud" to="." method="exit_to_lobby"]
|
||||
|
||||
121
godot/scenes/ui/hud.tscn
Normal file
121
godot/scenes/ui/hud.tscn
Normal file
@ -0,0 +1,121 @@
|
||||
[gd_scene format=3 uid="uid://c1gs6cqek1qlq"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://n3u0jr4wiib1" path="res://scenes/ui/settings.tscn" id="1_bo48s"]
|
||||
[ext_resource type="PackedScene" uid="uid://2sfy0vq0fqt3" path="res://scenes/ui/player_listing.tscn" id="2_8qguk"]
|
||||
[ext_resource type="PackedScene" uid="uid://ffh5txda3j1" path="res://scenes/ui/chat_box.tscn" id="3_136eg"]
|
||||
|
||||
[sub_resource type="LabelSettings" id="LabelSettings_oj5la"]
|
||||
font_size = 32
|
||||
font_color = Color(1, 0, 0, 1)
|
||||
outline_size = 10
|
||||
outline_color = Color(0, 0, 0, 1)
|
||||
|
||||
[node name="hud" type="Hud" unique_id=1365644678 node_paths=PackedStringArray("pause_panel", "settings_button", "exit_to_lobby", "exit", "settings_panel", "scoreboard", "chatbox", "health_label")]
|
||||
pause_panel = NodePath("pause_menu")
|
||||
settings_button = NodePath("pause_menu/v_box_container/settings")
|
||||
exit_to_lobby = NodePath("pause_menu/v_box_container/exit_to_lobby")
|
||||
exit = NodePath("pause_menu/v_box_container/exit")
|
||||
settings_panel = NodePath("settings")
|
||||
scoreboard = NodePath("scoreboard")
|
||||
chatbox = NodePath("chat_box")
|
||||
health_label = NodePath("health_label")
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="score_view" type="SimpleScoreView" parent="." unique_id=981879809]
|
||||
layout_mode = 1
|
||||
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
|
||||
|
||||
[node name="pause_menu" type="Panel" parent="." unique_id=990293559]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -67.75
|
||||
offset_top = -101.25
|
||||
offset_right = 67.75
|
||||
offset_bottom = 101.25
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="v_box_container" type="VBoxContainer" parent="pause_menu" unique_id=1801932370]
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -20.0
|
||||
offset_top = -20.0
|
||||
offset_right = 20.0
|
||||
offset_bottom = 20.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
alignment = 1
|
||||
|
||||
[node name="settings" type="Button" parent="pause_menu/v_box_container" unique_id=1671674264]
|
||||
layout_mode = 2
|
||||
text = "Settings"
|
||||
|
||||
[node name="exit_to_lobby" type="Button" parent="pause_menu/v_box_container" unique_id=313653211]
|
||||
layout_mode = 2
|
||||
text = "Exit to Lobby"
|
||||
|
||||
[node name="exit" type="Button" parent="pause_menu/v_box_container" unique_id=1097485912]
|
||||
layout_mode = 2
|
||||
text = "Exit"
|
||||
|
||||
[node name="settings" parent="." unique_id=999912383 instance=ExtResource("1_bo48s")]
|
||||
visible = false
|
||||
layout_mode = 1
|
||||
|
||||
[node name="scoreboard" type="PanelContainer" parent="." unique_id=99762392]
|
||||
custom_minimum_size = Vector2(0, -1)
|
||||
layout_mode = 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=43264288]
|
||||
player_listing_scene = ExtResource("2_8qguk")
|
||||
layout_mode = 2
|
||||
alignment = 1
|
||||
metadata/_edit_lock_ = true
|
||||
|
||||
[node name="chat_box" parent="." unique_id=1125601400 instance=ExtResource("3_136eg")]
|
||||
in_game = true
|
||||
layout_mode = 0
|
||||
|
||||
[node name="health_label" type="Label" parent="." unique_id=676741647]
|
||||
layout_mode = 1
|
||||
anchors_preset = 2
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 34.0
|
||||
offset_top = -45.0
|
||||
offset_right = 74.0
|
||||
offset_bottom = -22.0
|
||||
grow_vertical = 0
|
||||
text = "100"
|
||||
label_settings = SubResource("LabelSettings_oj5la")
|
||||
vertical_alignment = 2
|
||||
@ -2,8 +2,8 @@ use std::{f32::consts::PI, ops::Neg};
|
||||
|
||||
use godot::{
|
||||
classes::{
|
||||
AudioStreamPlayer, Button, Camera3D, CharacterBody3D, CollisionShape3D, ICharacterBody3D,
|
||||
Input, InputEvent, InputEventMouseMotion, Label, Panel, PanelContainer, input::MouseMode,
|
||||
AudioStreamPlayer, Camera3D, CharacterBody3D, CollisionShape3D, ICharacterBody3D, Input,
|
||||
InputEvent, InputEventMouseMotion, Label, input::MouseMode,
|
||||
},
|
||||
obj::WithBaseField,
|
||||
prelude::*,
|
||||
@ -30,7 +30,7 @@ use crate::{
|
||||
weapon::{BallWeapon, Raygun, Shotgun, Weapon, WeaponType},
|
||||
},
|
||||
replay::ReplayEvent,
|
||||
ui::{chatbox::ChatBox, cli::CommandLinePanel, settings::SettingsPanel},
|
||||
ui::{cli::CommandLinePanel, hud::Hud},
|
||||
};
|
||||
|
||||
#[derive(GodotClass)]
|
||||
@ -56,18 +56,10 @@ pub struct LocalPlayer {
|
||||
camera_origin: Option<Gd<Node3D>>,
|
||||
#[export]
|
||||
weapon_node: Option<Gd<Node3D>>,
|
||||
|
||||
#[export]
|
||||
pause_panel: Option<Gd<Panel>>,
|
||||
#[export]
|
||||
exit_to_lobby: Option<Gd<Button>>,
|
||||
#[export]
|
||||
settings_panel: Option<Gd<SettingsPanel>>,
|
||||
#[export]
|
||||
scoreboard: Option<Gd<PanelContainer>>,
|
||||
#[export]
|
||||
chatbox: Option<Gd<ChatBox>>,
|
||||
#[export]
|
||||
health_label: Option<Gd<Label>>,
|
||||
hud: Option<Gd<Hud>>,
|
||||
|
||||
#[export]
|
||||
hit_sound: Option<Gd<AudioStreamPlayer>>,
|
||||
#[export]
|
||||
@ -223,9 +215,6 @@ impl IPlayer for LocalPlayer {
|
||||
s.kill(source);
|
||||
}
|
||||
}
|
||||
if let Some(health_label) = &mut s.health_label {
|
||||
health_label.set_text(&s.health.max(0).to_string());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -305,6 +294,10 @@ impl IPlayer for LocalPlayer {
|
||||
fn is_replay_mode(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn get_health(&self) -> i32 {
|
||||
self.health
|
||||
}
|
||||
}
|
||||
|
||||
#[godot_api]
|
||||
@ -323,28 +316,6 @@ impl ICharacterBody3D for LocalPlayer {
|
||||
self.set_lock(true);
|
||||
}
|
||||
|
||||
CommandLinePanel::singleton()
|
||||
.signals()
|
||||
.on_open()
|
||||
.connect_other(self, |s| s.update_lock());
|
||||
CommandLinePanel::singleton()
|
||||
.signals()
|
||||
.on_close()
|
||||
.connect_other(self, |s| {
|
||||
s.update_lock();
|
||||
});
|
||||
|
||||
if let Some(chatbox) = self.chatbox.clone() {
|
||||
chatbox
|
||||
.signals()
|
||||
.on_opened()
|
||||
.connect_other(self, |s| s.update_lock());
|
||||
chatbox
|
||||
.signals()
|
||||
.on_closed()
|
||||
.connect_other(self, |s| s.update_lock());
|
||||
}
|
||||
|
||||
self.swap_weapon(WeaponType::Raygun, false);
|
||||
|
||||
if let Some(camera) = &mut self.camera {
|
||||
@ -357,11 +328,13 @@ impl ICharacterBody3D for LocalPlayer {
|
||||
remover.bind_mut().active = true;
|
||||
}
|
||||
|
||||
self.run_deferred(|s| {
|
||||
if let Some(exit_to_lobby) = &mut s.exit_to_lobby {
|
||||
exit_to_lobby.set_visible(NetworkManager::singleton().bind().is_host());
|
||||
}
|
||||
});
|
||||
if let Some(mut hud) = self.hud.clone() {
|
||||
hud.bind_mut().player_id = self.player_id.unwrap_or(0);
|
||||
hud.bind_mut()
|
||||
.signals()
|
||||
.on_lock_changed()
|
||||
.connect_other(self, |s, lock| s.set_lock(lock));
|
||||
}
|
||||
}
|
||||
|
||||
fn process(&mut self, delta: f64) {
|
||||
@ -436,10 +409,6 @@ impl ICharacterBody3D for LocalPlayer {
|
||||
camera.set_global_position(new_pos);
|
||||
}
|
||||
|
||||
if let Some(scoreboard) = &mut self.scoreboard {
|
||||
scoreboard.set_visible(Input::singleton().is_action_pressed("scoreboard"));
|
||||
}
|
||||
|
||||
if self.movement_dir.length_squared() > 0. && self.base().is_on_floor() && !self.is_dead {
|
||||
if let Some(effects) = &mut self.effects {
|
||||
effects.bind_mut().walk();
|
||||
@ -478,19 +447,6 @@ impl ICharacterBody3D for LocalPlayer {
|
||||
}
|
||||
|
||||
fn input(&mut self, event: Gd<InputEvent>) {
|
||||
if event.is_action_pressed("pause") {
|
||||
if let Some(pause_panel) = &mut self.pause_panel {
|
||||
let is_visible = pause_panel.is_visible();
|
||||
pause_panel.set_visible(!is_visible);
|
||||
if !pause_panel.is_visible() {
|
||||
if let Some(settings_panel) = &mut self.settings_panel {
|
||||
settings_panel.set_visible(false);
|
||||
}
|
||||
}
|
||||
self.update_lock();
|
||||
}
|
||||
}
|
||||
|
||||
if self.locked {
|
||||
if event.is_action_pressed("shoot") {
|
||||
if let Some(pos) = self.raycast_from_camera() {
|
||||
@ -637,22 +593,6 @@ impl LocalPlayer {
|
||||
damage: i32,
|
||||
);
|
||||
|
||||
fn update_lock(&mut self) {
|
||||
self.run_deferred(|s| {
|
||||
let paused = if let Some(panel) = &s.pause_panel {
|
||||
panel.is_visible()
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let chat_visible = if let Some(chat) = &s.chatbox {
|
||||
chat.bind().is_editing()
|
||||
} else {
|
||||
false
|
||||
};
|
||||
s.set_lock(!CommandLinePanel::singleton().bind().opened && !paused && !chat_visible);
|
||||
});
|
||||
}
|
||||
|
||||
fn set_lock(&mut self, locked: bool) {
|
||||
self.locked = locked;
|
||||
if self.locked {
|
||||
|
||||
@ -57,6 +57,7 @@ pub trait IPlayer {
|
||||
fn drop_ball(&mut self, with_velocity: bool) -> bool;
|
||||
fn get_camera_origin(&self) -> Option<Gd<Node3D>>;
|
||||
fn is_replay_mode(&self) -> bool;
|
||||
fn get_health(&self) -> i32;
|
||||
}
|
||||
|
||||
pub trait PlayerCommon {
|
||||
|
||||
@ -230,6 +230,10 @@ impl IPlayer for RemotePlayer {
|
||||
fn is_replay_mode(&self) -> bool {
|
||||
self.replay_mode
|
||||
}
|
||||
|
||||
fn get_health(&self) -> i32 {
|
||||
self.health
|
||||
}
|
||||
}
|
||||
|
||||
#[godot_api]
|
||||
|
||||
@ -19,6 +19,7 @@ use crate::{
|
||||
DamageSource, IPlayer, NetTransform, ball::Ball, remote_player::RemotePlayer,
|
||||
weapon::WeaponType,
|
||||
},
|
||||
ui::hud::Hud,
|
||||
};
|
||||
|
||||
pub const STANDALONE_REPLAY_GLOBAL: &str = "StandaloneReplayGlobal";
|
||||
@ -28,11 +29,16 @@ pub const STANDALONE_REPLAY_GLOBAL: &str = "StandaloneReplayGlobal";
|
||||
pub struct StandaloneReplayManager {
|
||||
#[export]
|
||||
replay_finished_screen: Option<Gd<PackedScene>>,
|
||||
#[export]
|
||||
main_menu: Option<Gd<PackedScene>>,
|
||||
#[export]
|
||||
hud_scene: Option<Gd<PackedScene>>,
|
||||
|
||||
loading_replay: bool,
|
||||
map: Option<Gd<Map>>,
|
||||
pub playback: Option<Gd<ReplayPlayback>>,
|
||||
replay: Option<Replay>,
|
||||
hud: Option<Gd<Hud>>,
|
||||
|
||||
base: Base<Node>,
|
||||
}
|
||||
@ -85,6 +91,22 @@ impl StandaloneReplayManager {
|
||||
playback.bind_mut().spectated_player_id = 0;
|
||||
self.playback = Some(playback.clone());
|
||||
self.base_mut().add_child(&playback);
|
||||
|
||||
if let Some(scene) = &self.hud_scene {
|
||||
let hud = scene.instantiate_as::<Hud>();
|
||||
|
||||
hud.signals().on_exit_to_lobby().connect_other(self, |s| {
|
||||
s.on_done();
|
||||
});
|
||||
|
||||
hud.signals().on_exit().connect_other(self, |s| {
|
||||
s.clear();
|
||||
s.go_to_menu();
|
||||
});
|
||||
|
||||
self.hud = Some(hud.clone());
|
||||
playback.add_child(&hud);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -98,10 +120,19 @@ impl StandaloneReplayManager {
|
||||
pub fn clear(&mut self) {
|
||||
self.replay.take();
|
||||
self.map.take();
|
||||
if let Some(mut hud) = self.hud.take() {
|
||||
hud.queue_free();
|
||||
}
|
||||
if let Some(mut playback) = self.playback.take() {
|
||||
playback.queue_free();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn go_to_menu(&mut self) {
|
||||
if let Some(scene) = &self.main_menu {
|
||||
self.base().get_tree().change_scene_to_packed(scene);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(GodotClass)]
|
||||
@ -122,6 +153,8 @@ pub struct ReplayPlayback {
|
||||
|
||||
pub finished: bool,
|
||||
|
||||
pub running_goals: HashMap<u8, u16>,
|
||||
|
||||
base: Base<Node>,
|
||||
}
|
||||
|
||||
@ -129,6 +162,8 @@ pub struct ReplayPlayback {
|
||||
impl ReplayPlayback {
|
||||
#[signal]
|
||||
pub fn on_finished();
|
||||
#[signal]
|
||||
pub fn on_data_changed();
|
||||
}
|
||||
|
||||
#[godot_api]
|
||||
@ -150,10 +185,11 @@ impl INode for ReplayPlayback {
|
||||
fn physics_process(&mut self, delta: f64) {
|
||||
self.current_time += delta;
|
||||
|
||||
while let Some(frame) = self.replay.frames.get(self.current_frame_idx)
|
||||
while let Some(frame) = self.replay.frames.get(self.current_frame_idx).cloned()
|
||||
&& frame.time <= self.current_time
|
||||
{
|
||||
self.player_data = frame.player_data.clone();
|
||||
self.running_goals = frame.goals.clone();
|
||||
|
||||
if let ReplayBall::World(ball_state) = &frame.ball_data {
|
||||
if let Some(ball) = &mut self.ball {
|
||||
@ -264,6 +300,8 @@ impl INode for ReplayPlayback {
|
||||
}
|
||||
}
|
||||
self.current_frame_idx += 1;
|
||||
|
||||
self.signals().on_data_changed().emit();
|
||||
}
|
||||
|
||||
self.fast_forwarding = false;
|
||||
|
||||
149
rust/src/ui/hud.rs
Normal file
149
rust/src/ui/hud.rs
Normal file
@ -0,0 +1,149 @@
|
||||
use godot::{
|
||||
classes::{Button, Control, IControl, Input, InputEvent, Label, Panel, PanelContainer},
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
game_manager::Game,
|
||||
net::network_manager::NetworkManager,
|
||||
ui::{chatbox::ChatBox, cli::CommandLinePanel, settings::SettingsPanel},
|
||||
};
|
||||
|
||||
#[derive(GodotClass)]
|
||||
#[class(base=Control, init)]
|
||||
pub struct Hud {
|
||||
pub player_id: u16,
|
||||
|
||||
#[export]
|
||||
pause_panel: Option<Gd<Panel>>,
|
||||
#[export]
|
||||
settings_button: Option<Gd<Button>>,
|
||||
#[export]
|
||||
exit_to_lobby: Option<Gd<Button>>,
|
||||
#[export]
|
||||
exit: Option<Gd<Button>>,
|
||||
#[export]
|
||||
settings_panel: Option<Gd<SettingsPanel>>,
|
||||
#[export]
|
||||
scoreboard: Option<Gd<PanelContainer>>,
|
||||
#[export]
|
||||
chatbox: Option<Gd<ChatBox>>,
|
||||
#[export]
|
||||
health_label: Option<Gd<Label>>,
|
||||
|
||||
lock: bool,
|
||||
|
||||
base: Base<Control>,
|
||||
}
|
||||
|
||||
#[godot_api]
|
||||
impl IControl for Hud {
|
||||
fn ready(&mut self) {
|
||||
self.run_deferred(|s| {
|
||||
if let Some(exit_to_lobby) = &mut s.exit_to_lobby {
|
||||
exit_to_lobby.set_visible(NetworkManager::singleton().bind().is_host());
|
||||
}
|
||||
});
|
||||
|
||||
CommandLinePanel::singleton()
|
||||
.signals()
|
||||
.on_open()
|
||||
.connect_other(self, |s| s.update_lock());
|
||||
CommandLinePanel::singleton()
|
||||
.signals()
|
||||
.on_close()
|
||||
.connect_other(self, |s| {
|
||||
s.update_lock();
|
||||
});
|
||||
|
||||
if let Some(chatbox) = self.chatbox.clone() {
|
||||
chatbox
|
||||
.signals()
|
||||
.on_opened()
|
||||
.connect_other(self, |s| s.update_lock());
|
||||
chatbox
|
||||
.signals()
|
||||
.on_closed()
|
||||
.connect_other(self, |s| s.update_lock());
|
||||
}
|
||||
|
||||
if let Some(exit_to_lobby) = &self.exit_to_lobby {
|
||||
exit_to_lobby
|
||||
.signals()
|
||||
.pressed()
|
||||
.connect_other(self, |s| s.signals().on_exit_to_lobby().emit());
|
||||
}
|
||||
|
||||
if let Some(exit) = &self.exit {
|
||||
exit.signals()
|
||||
.pressed()
|
||||
.connect_other(self, |s| s.signals().on_exit().emit());
|
||||
}
|
||||
if let Some(settings_btn) = &self.settings_button {
|
||||
settings_btn.signals().pressed().connect_other(self, |s| {
|
||||
if let Some(settings) = &mut s.settings_panel {
|
||||
settings.set_visible(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
self.update_lock();
|
||||
}
|
||||
|
||||
fn process(&mut self, _: f64) {
|
||||
if let Some(scoreboard) = &mut self.scoreboard {
|
||||
scoreboard.set_visible(Input::singleton().is_action_pressed("scoreboard"));
|
||||
}
|
||||
if let Some(game) = Game::singleton()
|
||||
&& let Some(player) = game.bind().find_player(self.player_id)
|
||||
&& let Some(character) = &player.character
|
||||
&& let Some(health_label) = &mut self.health_label
|
||||
{
|
||||
health_label.set_text(&character.dyn_bind().get_health().to_string());
|
||||
}
|
||||
}
|
||||
|
||||
fn input(&mut self, event: Gd<InputEvent>) {
|
||||
if event.is_action_pressed("pause") {
|
||||
if let Some(pause_panel) = &mut self.pause_panel {
|
||||
let is_visible = pause_panel.is_visible();
|
||||
pause_panel.set_visible(!is_visible);
|
||||
if !pause_panel.is_visible() {
|
||||
if let Some(settings_panel) = &mut self.settings_panel {
|
||||
settings_panel.set_visible(false);
|
||||
}
|
||||
}
|
||||
self.update_lock();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[godot_api]
|
||||
impl Hud {
|
||||
#[signal]
|
||||
pub fn on_lock_changed(lock: bool);
|
||||
#[signal]
|
||||
pub fn on_exit_to_lobby();
|
||||
#[signal]
|
||||
pub fn on_exit();
|
||||
|
||||
pub fn update_lock(&mut self) {
|
||||
let paused = if let Some(panel) = &self.pause_panel {
|
||||
panel.is_visible()
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let chat_visible = if let Some(chat) = &self.chatbox {
|
||||
chat.bind().is_editing()
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let prev_lock = self.lock;
|
||||
self.lock = !CommandLinePanel::singleton().bind().opened && !paused && !chat_visible;
|
||||
if prev_lock != self.lock {
|
||||
let lock = self.lock;
|
||||
self.signals().on_lock_changed().emit(lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,6 +2,7 @@ pub mod chatbox;
|
||||
pub mod cli;
|
||||
pub mod credits;
|
||||
pub mod game_finished_screen;
|
||||
pub mod hud;
|
||||
pub mod lobby;
|
||||
pub mod lobby_player_listing;
|
||||
pub mod main_menu;
|
||||
|
||||
@ -48,11 +48,22 @@ impl IHBoxContainer for PlayerListing {
|
||||
.on_player_killed()
|
||||
.connect_other(self, |s, _| s.update());
|
||||
}
|
||||
self.run_deferred(|s| {
|
||||
if let Some(replay_playback) =
|
||||
&mut StandaloneReplayManager::singleton().bind_mut().playback
|
||||
{
|
||||
replay_playback
|
||||
.signals()
|
||||
.on_data_changed()
|
||||
.connect_other(s, |s| s.update());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl PlayerListing {
|
||||
pub fn update(&mut self) {
|
||||
godot_print!("update");
|
||||
if let Some(player_id) = self.player_id {
|
||||
if let Some(game) = Game::singleton() {
|
||||
if let Some(player) = game.bind().find_player(player_id) {
|
||||
@ -79,46 +90,35 @@ impl PlayerListing {
|
||||
}
|
||||
ping_icon.set_modulate(color);
|
||||
}
|
||||
} 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");
|
||||
}
|
||||
}
|
||||
} else if let Some(playback) = &StandaloneReplayManager::singleton().bind().playback {
|
||||
if let Some(player) = playback.bind().replay.players.get(&player_id) {
|
||||
if let Some(name_label) = &mut self.name_label {
|
||||
name_label.set_text(&player.name);
|
||||
}
|
||||
}
|
||||
if let Some(player) = playback.bind().player_data.get(&player_id) {
|
||||
if let Some(kills_label) = &mut self.kills_label {
|
||||
kills_label.set_text(&player.kills.to_string());
|
||||
}
|
||||
if let Some(deaths_label) = &mut self.deaths_label {
|
||||
deaths_label.set_text(&player.deaths.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");
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@ use godot::{
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
use crate::game_manager::Game;
|
||||
use crate::{game_manager::Game, replay::StandaloneReplayManager};
|
||||
|
||||
#[derive(GodotClass)]
|
||||
#[class(base=HBoxContainer, init)]
|
||||
@ -35,6 +35,23 @@ impl IHBoxContainer for SimpleScoreView {
|
||||
game.signals()
|
||||
.on_goal()
|
||||
.connect_other(s, |s| s.update_goals());
|
||||
} else if let Some(playback) = &StandaloneReplayManager::singleton().bind().playback {
|
||||
for (id, team) in playback.bind().replay.teams.iter().enumerate() {
|
||||
let mut goals_label = Label::new_alloc();
|
||||
goals_label.set_modulate(team.color.clone().into());
|
||||
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);
|
||||
}
|
||||
playback
|
||||
.signals()
|
||||
.on_data_changed()
|
||||
.connect_other(s, |s| s.update_goals());
|
||||
}
|
||||
s.update_goals();
|
||||
});
|
||||
@ -51,6 +68,14 @@ impl SimpleScoreView {
|
||||
label.set_text(&goals.to_string());
|
||||
}
|
||||
}
|
||||
} else if let Some(playback) = &StandaloneReplayManager::singleton().bind().playback {
|
||||
for (id, _) in playback.bind().replay.teams.iter().enumerate() {
|
||||
if let Some(goals) = playback.bind().running_goals.get(&(id as u8))
|
||||
&& let Some(label) = self.team_goals.get_mut(&(id as u8))
|
||||
{
|
||||
label.set_text(&goals.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user