From 93809e7fd6077f6a9f1d9af102cf8cad1ced908f Mon Sep 17 00:00:00 2001 From: Sofia Date: Sat, 18 Jul 2026 00:12:40 +0300 Subject: [PATCH] Add mouse look --- godot/project.godot | 1 + godot/scenes/map0.tscn | 25 +++++++++++++ godot/scenes/player.tscn | 18 ++++++++++ rust/src/lib.rs | 1 + rust/src/player.rs | 76 ++++++++++++++++++++++++++++++++++++++++ rust/src/ui/cli.rs | 9 +++++ 6 files changed, 130 insertions(+) create mode 100644 godot/scenes/map0.tscn create mode 100644 godot/scenes/player.tscn create mode 100644 rust/src/player.rs diff --git a/godot/project.godot b/godot/project.godot index da08419..75e6f7f 100644 --- a/godot/project.godot +++ b/godot/project.godot @@ -40,6 +40,7 @@ toggle_cli={ "deadzone": 0.2, "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":167,"key_label":0,"unicode":167,"location":0,"echo":false,"script":null) , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194332,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194343,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) ] } diff --git a/godot/scenes/map0.tscn b/godot/scenes/map0.tscn new file mode 100644 index 0000000..974afb5 --- /dev/null +++ b/godot/scenes/map0.tscn @@ -0,0 +1,25 @@ +[gd_scene format=3 uid="uid://7iooamjot1tg"] + +[ext_resource type="PackedScene" uid="uid://ct70bpbca8one" path="res://scenes/player.tscn" id="1_y4ph1"] + +[sub_resource type="PlaneMesh" id="PlaneMesh_1cgct"] + +[node name="map_0" type="Node3D" unique_id=1710628675] + +[node name="net_stats_label" type="NetStatsLabel" parent="." unique_id=1821474986] +offset_left = 1.0 +offset_top = 497.0 +offset_right = 370.0 +offset_bottom = 649.0 +vertical_alignment = 2 + +[node name="terrain" type="MeshInstance3D" parent="." unique_id=1474127252] +transform = Transform3D(100, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0) +mesh = SubResource("PlaneMesh_1cgct") + +[node name="player" parent="." unique_id=1910472598 instance=ExtResource("1_y4ph1")] +look_sensitivity = 2.0 +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.002088, 0) + +[node name="directional_light_3d" type="DirectionalLight3D" parent="." unique_id=793524416] +transform = Transform3D(1, 0, 0, 0, 0.7274598, 0.6861503, 0, -0.6861503, 0.7274598, -5.1267624, 3.3997262, 3.715582) diff --git a/godot/scenes/player.tscn b/godot/scenes/player.tscn new file mode 100644 index 0000000..9cc4487 --- /dev/null +++ b/godot/scenes/player.tscn @@ -0,0 +1,18 @@ +[gd_scene format=3 uid="uid://ct70bpbca8one"] + +[sub_resource type="CapsuleMesh" id="CapsuleMesh_1cgct"] + +[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_1cgct"] + +[node name="player" type="Player" unique_id=1910472598 node_paths=PackedStringArray("camera")] +look_sensitivity = 1.0 +camera = NodePath("camera_3d") + +[node name="mesh_instance_3d" type="MeshInstance3D" parent="." unique_id=700336478] +mesh = SubResource("CapsuleMesh_1cgct") + +[node name="collision_shape_3d" type="CollisionShape3D" parent="." unique_id=1110995513] +shape = SubResource("CapsuleShape3D_1cgct") + +[node name="camera_3d" type="Camera3D" parent="." unique_id=1773137418] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5391109, 0) diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 908cd6f..e401f7b 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -5,6 +5,7 @@ use godot::prelude::*; pub mod game_manager; pub mod map_resource; pub mod net; +pub mod player; pub mod ui; struct MyExtension; diff --git a/rust/src/player.rs b/rust/src/player.rs new file mode 100644 index 0000000..f0839cd --- /dev/null +++ b/rust/src/player.rs @@ -0,0 +1,76 @@ +use std::f32::consts::PI; + +use godot::{ + classes::{ + Camera3D, CharacterBody3D, ICharacterBody3D, Input, InputEvent, InputEventMouseMotion, + input::MouseMode, + }, + prelude::*, +}; + +use crate::ui::cli::CommandLinePanel; + +#[derive(GodotClass)] +#[class(base=CharacterBody3D, init)] +pub struct Player { + #[export] + look_sensitivity: f32, + #[export] + camera: Option>, + + locked: bool, + + base: Base, +} + +#[godot_api] +impl ICharacterBody3D for Player { + fn ready(&mut self) { + if !CommandLinePanel::singleton().bind().opened { + self.set_lock(true); + } + + CommandLinePanel::singleton() + .signals() + .on_open() + .connect_other(self, |s| s.set_lock(false)); + CommandLinePanel::singleton() + .signals() + .on_close() + .connect_other(self, |s| { + s.set_lock(true); + }); + } + + fn process(&mut self, delta: f64) {} + + fn input(&mut self, event: Gd) { + if self.locked { + if let Ok(event) = event.try_cast::() { + let x = event.get_relative().x * 0.001 * self.look_sensitivity; + let y = event.get_relative().y * 0.001 * self.look_sensitivity; + + if let Some(camera) = self.camera.as_mut() { + let curr_rotation = camera.get_rotation(); + let x_rot = + (curr_rotation.x - y * self.look_sensitivity).clamp(-PI / 2., PI / 2.); + camera.set_rotation(Vector3::RIGHT * x_rot); + } + + let y_rot = -x * self.look_sensitivity; + self.base_mut().rotate_y(y_rot); + } + } + } +} + +impl Player { + fn set_lock(&mut self, locked: bool) { + self.locked = locked; + if self.locked { + Input::singleton().set_mouse_mode(MouseMode::CAPTURED); + } else { + Input::singleton().set_mouse_mode(MouseMode::VISIBLE); + } + } +} diff --git a/rust/src/ui/cli.rs b/rust/src/ui/cli.rs index 7a59aad..236f320 100644 --- a/rust/src/ui/cli.rs +++ b/rust/src/ui/cli.rs @@ -109,6 +109,11 @@ impl IPanel for CommandLinePanel { fn input(&mut self, event: Gd) { if event.is_action_pressed("toggle_cli") { self.opened = !self.opened; + if self.opened { + self.signals().on_open().emit(); + } else { + self.signals().on_close().emit(); + } if let Some(input_field) = &mut self.input_field { if self.opened { input_field.grab_focus(); @@ -131,6 +136,10 @@ impl CommandLinePanel { pub fn on_join(port: String); #[signal] pub fn on_disconnect(); + #[signal] + pub fn on_open(); + #[signal] + pub fn on_close(); pub fn singleton() -> Gd { get_autoload_by_name::(CLI_GLOBAL_NAME)