Add map selection and entering game

This commit is contained in:
Sofia 2026-07-17 23:09:11 +03:00
parent c594af3bd1
commit 73c7c5b850
10 changed files with 170 additions and 5 deletions

View File

@ -0,0 +1,7 @@
[gd_resource type="Map" format=3 uid="uid://b4rw48yjf7q3q"]
[ext_resource type="PackedScene" uid="uid://lahirbqfppvw" path="res://scenes/main.tscn" id="1_k5804"]
[resource]
name = "Default Map"
scene = ExtResource("1_k5804")

View File

@ -0,0 +1,7 @@
[gd_resource type="Map" format=3 uid="uid://crti664evgfmj"]
[ext_resource type="PackedScene" uid="uid://lahirbqfppvw" path="res://scenes/main.tscn" id="1_gr7ev"]
[resource]
name = "Default Map 2"
scene = ExtResource("1_gr7ev")

View File

@ -1,3 +1,7 @@
[gd_scene format=3 uid="uid://bii6018k3ip3t"]
[ext_resource type="Map" uid="uid://b4rw48yjf7q3q" path="res://maps/default_map.tres" id="1_glms7"]
[ext_resource type="Map" uid="uid://crti664evgfmj" path="res://maps/default_map_2.tres" id="2_udu3i"]
[node name="game_manager" type="GameManager" unique_id=1442044769]
maps = Array[Map]([ExtResource("1_glms7"), ExtResource("2_udu3i")])

View File

@ -5,11 +5,12 @@
[sub_resource type="LabelSettings" id="LabelSettings_1cgct"]
font_size = 32
[node name="lobby" type="LobbyPanel" unique_id=915192272 node_paths=PackedStringArray("players_list", "name_field", "ready_button")]
[node name="lobby" type="LobbyPanel" unique_id=915192272 node_paths=PackedStringArray("players_list", "name_field", "ready_button", "map_selection")]
players_list = NodePath("v_box_container/players_list")
name_field = NodePath("v_box_container/h_box_container/text_edit")
player_listing_prefab = ExtResource("1_o1atq")
ready_button = NodePath("ready_button")
map_selection = NodePath("v_box_container2/option_button")
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
@ -73,3 +74,13 @@ offset_top = 504.0
offset_right = 278.0
offset_bottom = 555.0
text = "Not Ready"
[node name="v_box_container2" type="VBoxContainer" parent="." unique_id=653902328]
layout_mode = 0
offset_left = 716.0
offset_top = 146.0
offset_right = 824.0
offset_bottom = 204.0
[node name="option_button" type="OptionButton" parent="v_box_container2" unique_id=426342653]
layout_mode = 2

View File

@ -3,6 +3,8 @@ use std::net::SocketAddr;
use godot::{prelude::*, tools::get_autoload_by_name};
use serde::{Deserialize, Serialize};
use crate::map_resource::Map;
pub const GAME_MANAGER_GLOBAL: &str = "GameManagerGlobal";
#[derive(GodotClass)]
@ -10,6 +12,9 @@ pub const GAME_MANAGER_GLOBAL: &str = "GameManagerGlobal";
pub struct GameManager {
pub game: Option<Gd<Game>>,
base: Base<Node>,
#[export]
pub maps: Array<Gd<Map>>,
}
#[godot_api]
@ -20,6 +25,8 @@ impl GameManager {
pub fn on_new_player(id: u16);
#[signal]
pub fn on_player_disconnected(id: u16);
#[signal]
pub fn on_map_changed(id: u8);
pub fn singleton() -> Gd<GameManager> {
get_autoload_by_name::<GameManager>(GAME_MANAGER_GLOBAL)
@ -31,6 +38,7 @@ impl GameManager {
}
let mut game = Game::new_alloc();
game.bind_mut().is_host = is_host;
game.bind_mut().maps = self.maps.clone();
self.run_deferred(|s| {
if let Some(game) = &s.game {
@ -43,6 +51,9 @@ impl GameManager {
game.signals()
.on_players_updated()
.connect_other(s, |s| s.signals().on_players_updated().emit());
game.signals()
.on_map_changed()
.connect_other(s, |s, id| s.signals().on_map_changed().emit(id));
}
});
@ -55,10 +66,15 @@ impl GameManager {
#[derive(GodotClass)]
#[class(base=Node, init)]
pub struct Game {
pub selected_map_idx: u8,
pub selected_map: Option<Gd<Map>>,
pub maps: Array<Gd<Map>>,
is_host: bool,
player_counter: u16,
pub self_id: Option<u16>,
pub players: Vec<Player>,
game_started: bool,
base: Base<Node>,
}
@ -71,6 +87,8 @@ impl Game {
pub fn on_new_player(id: u16);
#[signal]
pub fn on_player_disconnected(id: u16);
#[signal]
pub fn on_map_changed(id: u8);
pub fn singleton() -> Option<Gd<Game>> {
GameManager::singleton()
@ -78,6 +96,26 @@ impl Game {
.map(|g| g.cast::<Game>())
}
pub fn change_map_selection(&mut self, map_idx: u8, emit: bool) {
self.selected_map_idx = map_idx;
if let Some(map) = self.maps.get(map_idx as usize) {
self.selected_map = Some(map);
if emit {
self.run_deferred(move |s| s.signals().on_map_changed().emit(map_idx));
}
}
}
pub fn start_game(&mut self) {
self.game_started = true;
godot_print!("{:?}", self.selected_map);
if let Some(map) = &self.selected_map {
if let Some(scene) = &map.bind().scene {
self.base().get_tree().change_scene_to_packed(scene);
}
}
}
pub fn set_self(&mut self, id: u16) {
self.self_id = Some(id);
}

View File

@ -3,6 +3,7 @@ use std::net::SocketAddr;
use godot::prelude::*;
pub mod game_manager;
pub mod map_resource;
pub mod net;
pub mod ui;

27
rust/src/map_resource.rs Normal file
View File

@ -0,0 +1,27 @@
use godot::prelude::*;
#[derive(GodotClass)]
#[class(base=Resource, init, tool)]
pub struct Map {
#[export]
pub name: GString,
#[export]
pub scene: Option<Gd<PackedScene>>,
base: Base<Resource>,
}
#[godot_api]
impl IResource for Map {
fn on_notification(&mut self, what: godot::classes::notify::ObjectNotification) {}
fn to_string(&self) -> GString {
"Hello there".to_gstring()
}
fn setup_local_to_scene(&mut self) {}
fn reset_state(&mut self) {}
fn set_path_cache(&self, path: GString) {}
}

View File

@ -196,6 +196,17 @@ impl INode for NetworkManager {
.update_player_ready(player_id, is_ready);
}
}
Package::SelectMap(map_id) => {
if let Some(game) = &mut Game::singleton() {
game.bind_mut().change_map_selection(map_id, true);
}
}
Package::GameStarted => {
if let Some(game) = &mut Game::singleton() {
godot_print!("Game started");
game.bind_mut().start_game();
}
}
_ => {}
},
}
@ -236,6 +247,11 @@ impl INode for NetworkManager {
sent_player.connection_addr =
SocketAddr::from(([0, 0, 0, 0], 0));
peer.broadcast_reliable(Package::NewPlayer(sent_player));
peer.send_reliable(
&connection.address,
Package::SelectMap(game.bind().selected_map_idx),
);
}
}
teanet::PeerMessage::Disconnected(connection, connection_error) => {
@ -416,6 +432,8 @@ pub enum Package {
NewPlayer(Player),
PlayerLeft(Player),
SetReady(u16, bool),
SelectMap(u8),
GameStarted,
}
pub enum PeerKind {

View File

@ -1,10 +1,11 @@
use godot::{
classes::{Button, IPanel, Label, Panel, TextEdit, VBoxContainer},
classes::{Button, IPanel, Label, OptionButton, Panel, TextEdit, VBoxContainer},
prelude::*,
};
use crate::{
game_manager::{Game, GameManager},
map_resource::Map,
net::network_manager::{NetworkManager, Package, PeerKind},
ui::player_listing::PlayerListing,
};
@ -20,6 +21,8 @@ pub struct LobbyPanel {
player_listing_prefab: Option<Gd<PackedScene>>,
#[export]
ready_button: Option<Gd<Button>>,
#[export]
map_selection: Option<Gd<OptionButton>>,
is_ready: bool,
@ -41,6 +44,10 @@ impl IPanel for LobbyPanel {
.signals()
.on_players_updated()
.connect_other(self, |s| s.update_players(false));
GameManager::singleton()
.signals()
.on_map_changed()
.connect_other(self, |s, id| s.update_map_selection(id));
if let Some(ready_button) = &self.ready_button {
ready_button
@ -48,6 +55,30 @@ impl IPanel for LobbyPanel {
.pressed()
.connect_other(self, |s| s.on_ready());
}
if let Some(map_selection) = &self.map_selection {
map_selection
.signals()
.item_selected()
.connect_other(self, |s, id| {
s.update_map_selection(id as u8);
});
}
if let Some(game) = Game::singleton() {
if let Some(map_selection) = &mut self.map_selection {
for map in game.bind().maps.iter_shared() {
map_selection.add_item(&map.bind().name);
}
let is_host = if let Some(peer) = &NetworkManager::singleton().bind().peer {
peer.is_host()
} else {
false
};
map_selection.set_disabled(!is_host);
map_selection.select(0);
}
}
self.update_map_selection(0);
if let Some(name_field) = &self.name_field {
name_field
@ -143,8 +174,29 @@ impl LobbyPanel {
peer.send_reliable(socket_addr, Package::SetReady(0, self.is_ready));
}
PeerKind::Server(_, _) => {
godot_print!("Start game!");
PeerKind::Server(peer, _) => {
if let Some(game) = &mut Game::singleton() {
game.bind_mut().start_game();
}
peer.broadcast_reliable(Package::GameStarted);
}
}
}
}
pub fn update_map_selection(&mut self, idx: u8) {
if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer {
match peer {
PeerKind::Client(..) => {
if let Some(map_selection) = &mut self.map_selection {
map_selection.select(idx as i32);
}
}
PeerKind::Server(peer, _) => {
if let Some(game) = &mut Game::singleton() {
game.bind_mut().change_map_selection(idx, false);
}
peer.broadcast_reliable(Package::SelectMap(idx));
}
}
}

@ -1 +1 @@
Subproject commit 4d843d2ccb5566a4bc7dc4f3af2bdf181ebf0c38
Subproject commit a947f3a8cbad03b939dedfc1486de75226d90c0a