From 9470f3dd1f1dd87ff8ca65443012bc66983c3fea Mon Sep 17 00:00:00 2001 From: 2ndbeam <2ndbeam@disroot.org> Date: Tue, 8 Jul 2025 19:59:07 +0300 Subject: [PATCH] Tutorial-driven player movement and camera --- data/player.rgs | Bin 0 -> 10933 bytes data/scene.rgs | Bin 19135 -> 26047 bytes game/src/lib.rs | 11 +++- game/src/player.rs | 145 +++++++++++++++++++++++++++++++++++++++++++++ settings.ron | 68 +++++++++++++++++++-- 5 files changed, 218 insertions(+), 6 deletions(-) create mode 100644 data/player.rgs create mode 100644 game/src/player.rs diff --git a/data/player.rgs b/data/player.rgs new file mode 100644 index 0000000000000000000000000000000000000000..50d1d72dd747f4dc5e02726626ce37e97daff0e3 GIT binary patch literal 10933 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 literal 0 HcmV?d00001 diff --git a/data/scene.rgs b/data/scene.rgs index 3b96f9f0c7b70045d5cacdcc6e4e3bf9aed0327f..9bb1c4dc64f86aad3983c5395d40d7d6114936fc 100644 GIT binary patch delta 2540 zcmb_eeN0nV6mQ{S`KW6<#eoPET1pVsmZ4MmYD+sx`49vqY8K_$KH-hmzL)n}6z8lT z5tHfE<;3Y0lfhy#r!gbzl9`AWm6OeXs+yu=1sK9E+k{Jj0zLWk|>y>Dy~PHjy}A-gG%nQ4U4 zxD`$b#Js%d=>A-5qg0G8o z$xfc*SRW&TC$k_P0%R;PDih%KsuI{yU8ZXv9244a*Y5JlE z<^J-*Zx~57e5@{j7xlXESo3C8&Onp?WKj8v@zBM6XcrB%c|}$TV(L(mCYvPHpgDFk zHva&FMP;zZpwswB;1+?S`xwzIc1bW{&rL$x39v6m4=3GEDU*rq ze6Z)H%iN@=Z{5YRCjthg5=PAV>c+A2w%t3yW_`zKhlYA5T-Id6#pGHe>5A#}55i&|S*?r|WP>4WO(*YP&jy&* z5XWGduyC~;-6fIabgK2HImnBw_rF!ch?h2=>t#f@$cF^!F>`TtCC!BxtP>)#iSe&z zM5&txF3 zu|ATtDatXx7d}WF9#E0xB8J&uU;N_nv}#KV9PyMs$cAj zmCZt^-=-&2Fs8$hS_S&lWT-AqCz6Y{ZG?8Jjo`P>BVXE*3PMNhTM)a@;V2|rXK7BozCNl zNI?*~MY@;dz0FH=3~aJ4sKji@&y|b!vjKcm5#V-7rdl?D z&Exd?V7oFs{5U>zWUpPM0}@ALr!?~39>zDt$=@J_(XMIbgEKm?dh)=!>AP4p6BjrS znrKPFtm)-TV=8KRUtfFQ6Cns%6U7k~dEht#T`t-$uz{{AH-9h?Vhs>iZ)5}0RmW$6 zSYOF-khj>Vkt0JHF%gpy9Br*$qTRA=yY`6Bb9v9erxO=WR962F(0=K$p@Mz%aHvpn zS4|ETY@C^Z-=Lnm^q|f4SStdUS6W_dty^YCM=$5WM14F~6=P#}8B{q22z1mV{-@V#$ z-vn_}`_9cB`!c)K_j52XFa+cmXO?8<=W#1cY&-ai?S#Y9z44Bd>$!p^E2ybXo}j?8 z`M&TpCYA#Uci4c2t8AVt)+WTVVP6(Ah&S0=bK&FzO01JV7>Z5y*Vdix^QYZ$4q7zA$x8KAPc%*dR1^8r6OATL>ba*u=2;`i#vltXWlx>!an8C@)3=AaZ&5TL=m;vM3icA0i diff --git a/game/src/lib.rs b/game/src/lib.rs index 4692ecd..f17fa75 100644 --- a/game/src/lib.rs +++ b/game/src/lib.rs @@ -1,4 +1,7 @@ //! Game project. + +use crate::{player::Player}; + use fyrox::{ core::pool::Handle, core::visitor::prelude::*, core::reflect::prelude::*, event::Event, @@ -11,14 +14,20 @@ use std::path::Path; // Re-export the engine. pub use fyrox; +pub mod player; + #[derive(Default, Visit, Reflect, Debug)] pub struct Game { scene: Handle, } impl Plugin for Game { - fn register(&self, _context: PluginRegistrationContext) { + fn register(&self, context: PluginRegistrationContext) { // Register your scripts here. + context + .serialization_context + .script_constructors + .add::("Player"); } fn init(&mut self, scene_path: Option<&str>, context: PluginContext) { diff --git a/game/src/player.rs b/game/src/player.rs new file mode 100644 index 0000000..4f80bf5 --- /dev/null +++ b/game/src/player.rs @@ -0,0 +1,145 @@ +use fyrox::{ + core::{ + algebra::{UnitQuaternion, UnitVector3, Vector3}, + pool::Handle, + reflect::prelude::*, + visitor::prelude::*, + variable::InheritableVariable, + type_traits::prelude::* + }, + event::{DeviceEvent, ElementState, MouseButton, WindowEvent, Event}, + script::{ScriptContext, ScriptDeinitContext, ScriptTrait}, + graph::SceneGraph, + keyboard::{KeyCode, PhysicalKey}, + scene::{node::Node, rigidbody::RigidBody}, +}; + +#[derive(Visit, Reflect, Default, Debug, Clone, TypeUuidProvider, ComponentProvider)] +#[type_uuid(id = "d14f7a07-1ea0-4d20-ad74-017b2497c88e")] +#[visit(optional)] +pub struct Player { + #[reflect(hidden)] + move_forward: bool, + + #[reflect(hidden)] + move_backward: bool, + + #[reflect(hidden)] + move_left: bool, + + #[reflect(hidden)] + move_right: bool, + + #[reflect(hidden)] + yaw: f32, + + #[reflect(hidden)] + pitch: f32, + + camera: Handle, +} + +impl ScriptTrait for Player { + fn on_init(&mut self, context: &mut ScriptContext) { + // Put initialization logic here. + } + + fn on_start(&mut self, context: &mut ScriptContext) { + // There should be a logic that depends on other scripts in scene. + // It is called right after **all** scripts were initialized. + } + + fn on_deinit(&mut self, context: &mut ScriptDeinitContext) { + // Put de-initialization logic here. + } + + fn on_os_event(&mut self, event: &Event<()>, context: &mut ScriptContext) { + match event { + Event::DeviceEvent { + event: + DeviceEvent::MouseMotion { + delta: (dx, dy), .. + }, + .. + } => { + let mouse_speed = 0.35; + self.pitch = (self.pitch + *dy as f32 * mouse_speed).clamp(-89.9, 89.9); + self.yaw -= *dx as f32 * mouse_speed; + }, + Event::WindowEvent { + event: WindowEvent::KeyboardInput { event, .. }, + .. + } => { + if let PhysicalKey::Code(code) = event.physical_key { + let is_pressed = event.state == ElementState::Pressed; + match code { + KeyCode::KeyW => { + self.move_forward = is_pressed; + }, + KeyCode::KeyS => { + self.move_backward = is_pressed; + }, + KeyCode::KeyA => { + self.move_left = is_pressed; + }, + KeyCode::KeyD => { + self.move_right = is_pressed; + }, + _ => (), + } + } + }, + _ => (), + } + } + + fn on_update(&mut self, context: &mut ScriptContext) { + let mut look_vector = Vector3::default(); + let mut side_vector = Vector3::default(); + + if let Some(camera) = context.scene.graph.try_get_mut(self.camera) { + look_vector = camera.look_vector(); + side_vector = camera.side_vector(); + + let yaw = UnitQuaternion::from_axis_angle( + &Vector3::y_axis(), self.yaw.to_radians() + ); + let transform = camera.local_transform_mut(); + transform.set_rotation( + UnitQuaternion::from_axis_angle( + &UnitVector3::new_normalize(yaw * Vector3::x()), + self.pitch.to_radians(), + ) * yaw, + ); + } + + if let Some(rigid_body) = context.scene.graph.try_get_mut_of_type::(context.handle) { + let mut velocity = Vector3::new(0.0, 0.0, 0.0); + if self.move_forward { + velocity += look_vector; + } + if self.move_backward { + velocity -= look_vector; + } + if self.move_left { + velocity += side_vector; + } + if self.move_right { + velocity -= side_vector; + } + + let y_vel = rigid_body.lin_vel().y; + if let Some(normalized_velocity) = velocity.try_normalize(f32::EPSILON) { + let movement_speed = 240.0 * context.dt; + rigid_body.set_lin_vel(Vector3::new( + normalized_velocity.x * movement_speed, + y_vel, + normalized_velocity.z * movement_speed, + )); + } else { + rigid_body.set_lin_vel(Vector3::new(0.0, y_vel, 0.0)); + } + } + } +} + diff --git a/settings.ron b/settings.ron index 49e99ab..c8bc9a9 100644 --- a/settings.ron +++ b/settings.ron @@ -491,9 +491,9 @@ scene_settings: { "data/scene.rgs": ( camera_settings: ( - position: (-1.2582655, 0.37696767, -0.41422594), - yaw: 2.317344, - pitch: 0.2702732, + position: (0.6421091, 0.11491381, 1.7991738), + yaw: 4.735702, + pitch: 0.11656319, projection: Perspective(( fov: 1.3089969, z_near: 0.025, @@ -502,7 +502,7 @@ ), node_infos: { ( - index: 1, + index: 45, generation: 1, ): ( is_expanded: true, @@ -519,17 +519,75 @@ ): ( is_expanded: true, ), + ( + index: 46, + generation: 1, + ): ( + is_expanded: true, + ), + ( + index: 1, + generation: 1, + ): ( + is_expanded: true, + ), + ( + index: 69, + generation: 1, + ): ( + is_expanded: true, + ), + }, + ), + "/home/secondbeam/workspace/rust/fyrox/red_dragon_pon/data/player.rgs": ( + camera_settings: ( + position: (-1.9930856, 0.5251903, 1.349509), + yaw: 2.3208973, + pitch: 0.38800758, + projection: Perspective(( + fov: 1.3089969, + z_near: 0.025, + z_far: 128.0, + )), + ), + node_infos: {}, + ), + "data/player.rgs": ( + camera_settings: ( + position: (0.0, 1.0, 0.0), + yaw: 0.0, + pitch: 0.0, + projection: Perspective(( + fov: 1.3089969, + z_near: 0.025, + z_far: 128.0, + )), + ), + node_infos: { + ( + index: 1, + generation: 1, + ): ( + is_expanded: true, + ), + ( + index: 0, + generation: 1, + ): ( + is_expanded: true, + ), }, ), }, recent: ( scenes: [ + "data/player.rgs", "data/scene.rgs", ], ), windows: ( window_position: (0.0, 0.0), - window_size: (979.0, 505.0), + window_size: (1093.0, 505.0), window_maximized: false, layout: None, ),