Tutorial-driven player movement and camera

This commit is contained in:
Alexey 2025-07-08 19:59:07 +03:00
commit 9470f3dd1f
5 changed files with 218 additions and 6 deletions

BIN
data/player.rgs Normal file

Binary file not shown.

Binary file not shown.

View file

@ -1,4 +1,7 @@
//! Game project. //! Game project.
use crate::{player::Player};
use fyrox::{ use fyrox::{
core::pool::Handle, core::visitor::prelude::*, core::reflect::prelude::*, core::pool::Handle, core::visitor::prelude::*, core::reflect::prelude::*,
event::Event, event::Event,
@ -11,14 +14,20 @@ use std::path::Path;
// Re-export the engine. // Re-export the engine.
pub use fyrox; pub use fyrox;
pub mod player;
#[derive(Default, Visit, Reflect, Debug)] #[derive(Default, Visit, Reflect, Debug)]
pub struct Game { pub struct Game {
scene: Handle<Scene>, scene: Handle<Scene>,
} }
impl Plugin for Game { impl Plugin for Game {
fn register(&self, _context: PluginRegistrationContext) { fn register(&self, context: PluginRegistrationContext) {
// Register your scripts here. // Register your scripts here.
context
.serialization_context
.script_constructors
.add::<Player>("Player");
} }
fn init(&mut self, scene_path: Option<&str>, context: PluginContext) { fn init(&mut self, scene_path: Option<&str>, context: PluginContext) {

145
game/src/player.rs Normal file
View file

@ -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<Node>,
}
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::<RigidBody>(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));
}
}
}
}

View file

@ -491,9 +491,9 @@
scene_settings: { scene_settings: {
"data/scene.rgs": ( "data/scene.rgs": (
camera_settings: ( camera_settings: (
position: (-1.2582655, 0.37696767, -0.41422594), position: (0.6421091, 0.11491381, 1.7991738),
yaw: 2.317344, yaw: 4.735702,
pitch: 0.2702732, pitch: 0.11656319,
projection: Perspective(( projection: Perspective((
fov: 1.3089969, fov: 1.3089969,
z_near: 0.025, z_near: 0.025,
@ -502,7 +502,7 @@
), ),
node_infos: { node_infos: {
( (
index: 1, index: 45,
generation: 1, generation: 1,
): ( ): (
is_expanded: true, is_expanded: true,
@ -519,17 +519,75 @@
): ( ): (
is_expanded: true, 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: ( recent: (
scenes: [ scenes: [
"data/player.rgs",
"data/scene.rgs", "data/scene.rgs",
], ],
), ),
windows: ( windows: (
window_position: (0.0, 0.0), window_position: (0.0, 0.0),
window_size: (979.0, 505.0), window_size: (1093.0, 505.0),
window_maximized: false, window_maximized: false,
layout: None, layout: None,
), ),