chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "fyrox-scripts"
|
||||
version = "2.0.0-rc.1"
|
||||
authors = ["Dmitry Stepanov <d1maxa@yandex.ru>"]
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
description = "Standard scripts for the Fyrox engine"
|
||||
keywords = ["asset", "resource"]
|
||||
categories = ["game-development"]
|
||||
include = ["/src/**/*", "/Cargo.toml", "/LICENSE"]
|
||||
homepage = "https://fyrox.rs"
|
||||
documentation = "https://docs.rs/fyrox-scripts"
|
||||
repository = "https://github.com/FyroxEngine/Fyrox"
|
||||
rust-version = "1.94"
|
||||
|
||||
[dependencies]
|
||||
fyrox = { version = "2.0.0-rc.1", path = "../fyrox" }
|
||||
@@ -0,0 +1,296 @@
|
||||
// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
//! Flying camera controller script is used to create flying cameras, that can be rotated via mouse and moved via keyboard keys.
|
||||
//! See [`FlyingCameraController`] docs for more info and usage examples.
|
||||
|
||||
use fyrox::graph::SceneGraph;
|
||||
use fyrox::plugin::error::GameResult;
|
||||
use fyrox::{
|
||||
core::{
|
||||
algebra::{UnitQuaternion, UnitVector3, Vector3},
|
||||
math::curve::{Curve, CurveKey, CurveKeyKind},
|
||||
math::Vector3Ext,
|
||||
reflect::prelude::*,
|
||||
variable::InheritableVariable,
|
||||
visitor::prelude::*,
|
||||
},
|
||||
event::{DeviceEvent, ElementState, Event, WindowEvent},
|
||||
gui::{key::KeyBinding, message::KeyCode},
|
||||
script::{ScriptContext, ScriptTrait},
|
||||
utils,
|
||||
};
|
||||
use std::ops::Range;
|
||||
|
||||
/// Flying camera controller script is used to create flying cameras, that can be rotated via mouse and moved via keyboard keys.
|
||||
/// Use it, if you need to create a sort of "spectator" camera. To use it, all you need to do is to assign it to your camera
|
||||
/// node (or one if its parent nodes).
|
||||
#[derive(Visit, PartialEq, Reflect, Debug, Clone)]
|
||||
#[reflect(type_uuid = "8d9e2feb-8c61-482c-8ba4-b0b13b201113")]
|
||||
pub struct FlyingCameraController {
|
||||
/// Current yaw of the camera pivot (in radians).
|
||||
#[visit(optional)]
|
||||
pub yaw: InheritableVariable<f32>,
|
||||
|
||||
/// Current pitch of the camera (in radians).
|
||||
#[visit(optional)]
|
||||
pub pitch: InheritableVariable<f32>,
|
||||
|
||||
/// Maximum speed of the camera.
|
||||
#[visit(optional)]
|
||||
pub speed: InheritableVariable<f32>,
|
||||
|
||||
/// Mouse sensitivity.
|
||||
#[visit(optional)]
|
||||
pub sensitivity: InheritableVariable<f32>,
|
||||
|
||||
/// Angular limit of the pitch of the camera (in radians).
|
||||
#[visit(optional)]
|
||||
pub pitch_limit: InheritableVariable<Range<f32>>,
|
||||
|
||||
// KeyBinding belongs to fyrox-ui which is unideal, this is only used here because it has built-in
|
||||
// property editor, so it will be shown in the editor correctly. It might be worth to create a
|
||||
// separate property editor for this instead to be able to use KeyCode here.
|
||||
/// A key, that corresponds to forward movement.
|
||||
#[visit(optional)]
|
||||
pub move_forward_key: InheritableVariable<KeyBinding>,
|
||||
|
||||
/// A key, that corresponds to backward movement.
|
||||
#[visit(optional)]
|
||||
pub move_backward_key: InheritableVariable<KeyBinding>,
|
||||
|
||||
/// A key, that corresponds to left movement.
|
||||
#[visit(optional)]
|
||||
pub move_left_key: InheritableVariable<KeyBinding>,
|
||||
|
||||
/// A key, that corresponds to right movement.
|
||||
#[visit(optional)]
|
||||
pub move_right_key: InheritableVariable<KeyBinding>,
|
||||
|
||||
/// A curve, that defines a how speed of the camera changes when accelerating to the max speed.
|
||||
#[visit(optional)]
|
||||
pub acceleration_curve: InheritableVariable<Curve>,
|
||||
|
||||
/// A curve, that defines a how speed of the camera changes when decelerating to the zero speed.
|
||||
#[visit(optional)]
|
||||
pub deceleration_curve: InheritableVariable<Curve>,
|
||||
|
||||
/// Amount of time (in seconds) during which the camera will accelerate to the max speed.
|
||||
#[reflect(min_value = 0.0)]
|
||||
#[visit(optional)]
|
||||
pub acceleration_time: InheritableVariable<f32>,
|
||||
|
||||
/// Amount of time (in seconds) during which the camera will decelerate to the zero speed.
|
||||
#[reflect(min_value = 0.0)]
|
||||
#[visit(optional)]
|
||||
pub deceleration_time: InheritableVariable<f32>,
|
||||
|
||||
/// A coefficient, that defines how fast the camera will respond to pressed keys.
|
||||
#[reflect(min_value = 0.01, max_value = 1.0)]
|
||||
#[visit(optional)]
|
||||
pub reactivity: InheritableVariable<f32>,
|
||||
|
||||
#[reflect(hidden)]
|
||||
#[visit(optional)]
|
||||
pub velocity: InheritableVariable<Vector3<f32>>,
|
||||
|
||||
#[reflect(hidden)]
|
||||
#[visit(optional)]
|
||||
pub target_velocity: InheritableVariable<Vector3<f32>>,
|
||||
|
||||
#[reflect(hidden)]
|
||||
#[visit(skip)]
|
||||
pub acceleration_coeff: f32,
|
||||
|
||||
#[reflect(hidden)]
|
||||
#[visit(skip)]
|
||||
pub move_forward: bool,
|
||||
|
||||
#[reflect(hidden)]
|
||||
#[visit(skip)]
|
||||
pub move_backward: bool,
|
||||
|
||||
#[reflect(hidden)]
|
||||
#[visit(skip)]
|
||||
pub move_left: bool,
|
||||
|
||||
#[reflect(hidden)]
|
||||
#[visit(skip)]
|
||||
pub move_right: bool,
|
||||
}
|
||||
|
||||
impl Default for FlyingCameraController {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
yaw: Default::default(),
|
||||
pitch: Default::default(),
|
||||
speed: 5.0.into(),
|
||||
sensitivity: 0.7.into(),
|
||||
pitch_limit: ((-89.9f32).to_radians()..89.9f32.to_radians()).into(),
|
||||
move_forward_key: KeyBinding::Some(KeyCode::KeyW).into(),
|
||||
move_backward_key: KeyBinding::Some(KeyCode::KeyS).into(),
|
||||
move_left_key: KeyBinding::Some(KeyCode::KeyA).into(),
|
||||
move_right_key: KeyBinding::Some(KeyCode::KeyD).into(),
|
||||
acceleration_curve: Curve::from(vec![
|
||||
CurveKey::new(
|
||||
0.0,
|
||||
0.0,
|
||||
CurveKeyKind::Cubic {
|
||||
left_tangent: 0.0,
|
||||
right_tangent: 0.0,
|
||||
},
|
||||
),
|
||||
CurveKey::new(
|
||||
1.0,
|
||||
1.0,
|
||||
CurveKeyKind::Cubic {
|
||||
left_tangent: 0.0,
|
||||
right_tangent: 0.0,
|
||||
},
|
||||
),
|
||||
])
|
||||
.into(),
|
||||
deceleration_curve: Curve::from(vec![
|
||||
CurveKey::new(
|
||||
0.0,
|
||||
0.0,
|
||||
CurveKeyKind::Cubic {
|
||||
left_tangent: 0.0,
|
||||
right_tangent: 0.0,
|
||||
},
|
||||
),
|
||||
CurveKey::new(
|
||||
1.0,
|
||||
1.0,
|
||||
CurveKeyKind::Cubic {
|
||||
left_tangent: 0.0,
|
||||
right_tangent: 0.0,
|
||||
},
|
||||
),
|
||||
])
|
||||
.into(),
|
||||
acceleration_time: 0.25.into(),
|
||||
deceleration_time: 1.0.into(),
|
||||
velocity: Default::default(),
|
||||
target_velocity: Default::default(),
|
||||
acceleration_coeff: 0.0,
|
||||
reactivity: 0.3.into(),
|
||||
move_forward: false,
|
||||
move_backward: false,
|
||||
move_left: false,
|
||||
move_right: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ScriptTrait for FlyingCameraController {
|
||||
fn on_os_event(&mut self, event: &Event<()>, context: &mut ScriptContext) -> GameResult {
|
||||
match event {
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::KeyboardInput { event, .. },
|
||||
..
|
||||
} => {
|
||||
for (binding, state) in [
|
||||
(&self.move_forward_key, &mut self.move_forward),
|
||||
(&self.move_backward_key, &mut self.move_backward),
|
||||
(&self.move_left_key, &mut self.move_left),
|
||||
(&self.move_right_key, &mut self.move_right),
|
||||
] {
|
||||
if let KeyBinding::Some(key_code) = **binding {
|
||||
if utils::translate_key_from_ui(key_code) == event.physical_key {
|
||||
*state = event.state == ElementState::Pressed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Event::DeviceEvent {
|
||||
event: DeviceEvent::MouseMotion { delta, .. },
|
||||
..
|
||||
} => {
|
||||
let speed = *self.sensitivity * context.dt;
|
||||
*self.yaw -= (delta.0 as f32) * speed;
|
||||
*self.pitch = (*self.pitch + delta.1 as f32 * speed)
|
||||
.max(self.pitch_limit.start)
|
||||
.min(self.pitch_limit.end);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_update(&mut self, context: &mut ScriptContext) -> GameResult {
|
||||
let mut new_velocity = Vector3::default();
|
||||
|
||||
let this = context.scene.graph.try_get_node_mut(context.handle)?;
|
||||
|
||||
if self.move_forward {
|
||||
new_velocity += this.look_vector();
|
||||
}
|
||||
if self.move_backward {
|
||||
new_velocity -= this.look_vector();
|
||||
}
|
||||
if self.move_left {
|
||||
new_velocity += this.side_vector();
|
||||
}
|
||||
if self.move_right {
|
||||
new_velocity -= this.side_vector();
|
||||
}
|
||||
|
||||
if let Some(new_normalized_velocity) = new_velocity.try_normalize(f32::EPSILON) {
|
||||
self.acceleration_coeff = (self.acceleration_coeff
|
||||
+ context.dt / self.acceleration_time.max(context.dt))
|
||||
.min(1.0);
|
||||
*self.target_velocity = new_normalized_velocity.scale(
|
||||
*self.speed
|
||||
* self.acceleration_curve.value_at(self.acceleration_coeff)
|
||||
* context.dt,
|
||||
);
|
||||
} else {
|
||||
self.acceleration_coeff = (self.acceleration_coeff
|
||||
- context.dt / self.deceleration_time.max(context.dt))
|
||||
.max(0.0);
|
||||
if let Some(normalized_velocity) = self.target_velocity.try_normalize(f32::EPSILON) {
|
||||
*self.target_velocity = normalized_velocity.scale(
|
||||
*self.speed
|
||||
* self.deceleration_curve.value_at(self.acceleration_coeff)
|
||||
* context.dt,
|
||||
);
|
||||
} else {
|
||||
*self.target_velocity = Vector3::zeros();
|
||||
}
|
||||
}
|
||||
|
||||
self.velocity
|
||||
.follow(&self.target_velocity, *self.reactivity);
|
||||
|
||||
let yaw = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), *self.yaw);
|
||||
this.local_transform_mut()
|
||||
.set_rotation(
|
||||
UnitQuaternion::from_axis_angle(
|
||||
&UnitVector3::new_normalize(yaw * Vector3::x()),
|
||||
*self.pitch,
|
||||
) * yaw,
|
||||
)
|
||||
.offset(*self.velocity);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
//! A set of useful scripts that can be used to in your game.
|
||||
|
||||
use crate::camera::FlyingCameraController;
|
||||
use fyrox::script::constructor::ScriptConstructorContainer;
|
||||
|
||||
pub mod camera;
|
||||
|
||||
/// Registers every script from the crate in the given constructor container. Use it, if you want to register all
|
||||
/// available scripts at once. Typical usage could be like this:
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # use fyrox::{
|
||||
/// # core::pool::Handle, core::visitor::prelude::*, core::reflect::prelude::*,
|
||||
/// # plugin::{Plugin, PluginContext, PluginRegistrationContext, error::GameResult},
|
||||
/// # scene::Scene,
|
||||
/// # };
|
||||
/// #
|
||||
/// # #[derive(Visit, Reflect, PartialEq, Debug)]
|
||||
/// # #[reflect(non_cloneable, type_uuid = "38a3d4cf-65e1-4e86-a730-365804c51cff")]
|
||||
/// # struct Game;
|
||||
/// #
|
||||
/// # impl Plugin for Game {
|
||||
/// // This is PluginConstructor::register method of your GameConstructor.
|
||||
/// fn register(&self, context: PluginRegistrationContext) -> GameResult {
|
||||
/// fyrox_scripts::register(&context.serialization_context.script_constructors);
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn register(container: &ScriptConstructorContainer) {
|
||||
container.add::<FlyingCameraController>("Fyrox Flying Camera Controller");
|
||||
}
|
||||
Reference in New Issue
Block a user