mirror of
https://github.com/FyroxEngine/Fyrox.git
synced 2026-10-12 02:02:20 +00:00
417 lines
12 KiB
Rust
417 lines
12 KiB
Rust
use fyrox::fxhash::FxHashMap;
|
|
use fyrox::{
|
|
core::{
|
|
algebra::{UnitQuaternion, Vector2, Vector3},
|
|
futures::executor::block_on,
|
|
inspect::{Inspect, PropertyInfo},
|
|
pool::Handle,
|
|
uuid::Uuid,
|
|
visitor::prelude::*,
|
|
},
|
|
event::{DeviceEvent, ElementState, Event, VirtualKeyCode, WindowEvent},
|
|
gui::{
|
|
button::ButtonBuilder,
|
|
inspector::{FieldKind, PropertyChanged},
|
|
widget::WidgetBuilder,
|
|
UserInterface,
|
|
},
|
|
plugin::{Plugin, PluginContext, PluginRegistrationContext},
|
|
renderer::{
|
|
framework::{error::FrameworkError, gpu_texture::GpuTextureKind},
|
|
ui_renderer::UiRenderContext,
|
|
RenderPassStatistics, SceneRenderPass, SceneRenderPassContext,
|
|
},
|
|
scene::{
|
|
camera::Camera, node::Node, node::TypeUuidProvider, rigidbody::RigidBody, Scene,
|
|
SceneLoader,
|
|
},
|
|
script::{ScriptContext, ScriptTrait},
|
|
utils::translate_event,
|
|
};
|
|
use std::{cell::RefCell, rc::Rc, str::FromStr};
|
|
|
|
pub struct GamePlugin {
|
|
scene: Handle<Scene>,
|
|
ui: Rc<RefCell<UserInterface>>,
|
|
debug_draw: bool,
|
|
}
|
|
|
|
impl Default for GamePlugin {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
impl GamePlugin {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
scene: Default::default(),
|
|
ui: Rc::new(RefCell::new(UserInterface::new(Vector2::new(100.0, 100.0)))),
|
|
debug_draw: false,
|
|
}
|
|
}
|
|
}
|
|
|
|
struct UiRenderPass {
|
|
scene: Handle<Scene>,
|
|
ui: Rc<RefCell<UserInterface>>,
|
|
}
|
|
|
|
impl SceneRenderPass for UiRenderPass {
|
|
fn on_ldr_render(
|
|
&mut self,
|
|
ctx: SceneRenderPassContext,
|
|
) -> Result<RenderPassStatistics, FrameworkError> {
|
|
if ctx.scene_handle == self.scene {
|
|
let mut ui = self.ui.borrow_mut();
|
|
|
|
ctx.ui_renderer.render(UiRenderContext {
|
|
state: ctx.pipeline_state,
|
|
viewport: ctx.viewport,
|
|
frame_buffer: ctx.framebuffer,
|
|
frame_width: ctx.viewport.size.x as f32,
|
|
frame_height: ctx.viewport.size.y as f32,
|
|
drawing_context: ui.draw(),
|
|
white_dummy: ctx.white_dummy.clone(),
|
|
texture_cache: ctx.texture_cache,
|
|
})?;
|
|
}
|
|
|
|
Ok(Default::default())
|
|
}
|
|
}
|
|
|
|
impl GamePlugin {
|
|
pub fn set_scene(&mut self, scene: Handle<Scene>, context: PluginContext) {
|
|
self.scene = scene;
|
|
|
|
context
|
|
.renderer
|
|
.add_render_pass(Rc::new(RefCell::new(UiRenderPass {
|
|
scene,
|
|
ui: self.ui.clone(),
|
|
})));
|
|
|
|
let mut ui = self.ui.borrow_mut();
|
|
let ctx = &mut ui.build_ctx();
|
|
ButtonBuilder::new(WidgetBuilder::new().with_width(200.0).with_height(32.0))
|
|
.with_text("Click me")
|
|
.build(ctx);
|
|
}
|
|
}
|
|
|
|
impl TypeUuidProvider for GamePlugin {
|
|
fn type_uuid() -> Uuid {
|
|
Uuid::from_str("a9507fb2-0945-4fc1-91ce-115ae7c8a615").unwrap()
|
|
}
|
|
}
|
|
|
|
impl Plugin for GamePlugin {
|
|
fn on_register(&mut self, context: PluginRegistrationContext) {
|
|
context
|
|
.serialization_context
|
|
.script_constructors
|
|
.add::<GamePlugin, Player, &str>("Player");
|
|
|
|
context
|
|
.serialization_context
|
|
.script_constructors
|
|
.add::<GamePlugin, Jumper, &str>("Jumper");
|
|
}
|
|
|
|
fn on_standalone_init(&mut self, context: PluginContext) {
|
|
let mut scene = block_on(
|
|
block_on(SceneLoader::from_file(
|
|
"data/scene.rgs",
|
|
context.serialization_context.clone(),
|
|
))
|
|
.expect("Invalid scene!")
|
|
.finish(context.resource_manager.clone()),
|
|
);
|
|
|
|
for node in scene.graph.linear_iter_mut() {
|
|
if let Some(camera) = node.cast_mut::<Camera>() {
|
|
camera.set_enabled(true);
|
|
}
|
|
}
|
|
|
|
self.set_scene(context.scenes.add(scene), context);
|
|
}
|
|
|
|
fn on_enter_play_mode(&mut self, scene: Handle<Scene>, context: PluginContext) {
|
|
self.set_scene(scene, context);
|
|
}
|
|
|
|
fn on_leave_play_mode(&mut self, _context: PluginContext) {
|
|
self.scene = Handle::NONE;
|
|
}
|
|
|
|
fn on_unload(&mut self, _context: &mut PluginContext) {}
|
|
|
|
fn update(&mut self, context: &mut PluginContext) {
|
|
let scene = &mut context.scenes[self.scene];
|
|
|
|
if self.debug_draw {
|
|
let drawing_context = &mut scene.drawing_context;
|
|
drawing_context.clear_lines();
|
|
scene.graph.physics.draw(drawing_context);
|
|
}
|
|
|
|
let mut ui = self.ui.borrow_mut();
|
|
|
|
if let Some(data) = context.renderer.scene_data_map.get(&self.scene) {
|
|
if let GpuTextureKind::Rectangle { width, height } =
|
|
data.ldr_scene_frame_texture().borrow().kind()
|
|
{
|
|
ui.update(Vector2::new(width as f32, height as f32), context.dt);
|
|
}
|
|
}
|
|
|
|
while ui.poll_message().is_some() {}
|
|
}
|
|
|
|
fn id(&self) -> Uuid {
|
|
Self::type_uuid()
|
|
}
|
|
|
|
fn on_os_event(&mut self, event: &Event<()>, _context: PluginContext) {
|
|
if let Event::WindowEvent { event, .. } = event {
|
|
if let Some(e) = translate_event(event) {
|
|
let mut ui = self.ui.borrow_mut();
|
|
ui.process_os_event(&e);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Default, Debug, Clone)]
|
|
pub struct InputController {
|
|
walk_forward: bool,
|
|
walk_backward: bool,
|
|
walk_left: bool,
|
|
walk_right: bool,
|
|
jump: bool,
|
|
}
|
|
|
|
#[derive(Visit, Inspect, Debug, Clone)]
|
|
struct Player {
|
|
speed: f32,
|
|
yaw: f32,
|
|
|
|
#[visit(optional)]
|
|
pitch: f32,
|
|
|
|
#[visit(optional)]
|
|
camera: Handle<Node>,
|
|
|
|
#[visit(skip)]
|
|
#[inspect(skip)]
|
|
controller: InputController,
|
|
}
|
|
|
|
impl Default for Player {
|
|
fn default() -> Self {
|
|
Self {
|
|
speed: 0.2,
|
|
yaw: 0.0,
|
|
pitch: 0.0,
|
|
camera: Default::default(),
|
|
controller: Default::default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TypeUuidProvider for Player {
|
|
fn type_uuid() -> Uuid {
|
|
Uuid::from_str("4aa165aa-011b-479f-bc10-b90b2c4b5060").unwrap()
|
|
}
|
|
}
|
|
|
|
impl ScriptTrait for Player {
|
|
fn on_property_changed(&mut self, args: &PropertyChanged) -> bool {
|
|
if let FieldKind::Object(ref value) = args.value {
|
|
return match args.name.as_ref() {
|
|
Self::SPEED => value.try_override(&mut self.speed),
|
|
Self::YAW => value.try_override(&mut self.yaw),
|
|
Self::PITCH => value.try_override(&mut self.pitch),
|
|
Self::CAMERA => value.try_override(&mut self.camera),
|
|
_ => false,
|
|
};
|
|
}
|
|
false
|
|
}
|
|
|
|
fn remap_handles(&mut self, old_new_mapping: &FxHashMap<Handle<Node>, Handle<Node>>) {
|
|
if let Some(camera) = old_new_mapping.get(&self.camera) {
|
|
self.camera = *camera;
|
|
}
|
|
}
|
|
|
|
fn on_update(&mut self, context: ScriptContext) {
|
|
let ScriptContext {
|
|
dt, node, scene, ..
|
|
} = context;
|
|
|
|
node.local_transform_mut()
|
|
.set_rotation(UnitQuaternion::from_axis_angle(
|
|
&Vector3::y_axis(),
|
|
self.yaw,
|
|
));
|
|
|
|
if let Some(body) = node.cast_mut::<RigidBody>() {
|
|
let look_vector = body
|
|
.look_vector()
|
|
.try_normalize(f32::EPSILON)
|
|
.unwrap_or_else(Vector3::z);
|
|
|
|
let side_vector = body
|
|
.side_vector()
|
|
.try_normalize(f32::EPSILON)
|
|
.unwrap_or_else(Vector3::x);
|
|
|
|
let mut velocity = Vector3::default();
|
|
|
|
if self.controller.walk_right {
|
|
velocity -= side_vector;
|
|
}
|
|
if self.controller.walk_left {
|
|
velocity += side_vector;
|
|
}
|
|
if self.controller.walk_forward {
|
|
velocity += look_vector;
|
|
}
|
|
if self.controller.walk_backward {
|
|
velocity -= look_vector;
|
|
}
|
|
|
|
let speed = 2.0 * dt;
|
|
let velocity = velocity
|
|
.try_normalize(f32::EPSILON)
|
|
.map(|v| v.scale(speed))
|
|
.unwrap_or_default();
|
|
|
|
body.set_ang_vel(Default::default());
|
|
body.set_lin_vel(Vector3::new(
|
|
velocity.x / dt,
|
|
body.lin_vel().y,
|
|
velocity.z / dt,
|
|
));
|
|
}
|
|
|
|
if let Some(camera) = scene.graph.try_get_mut(self.camera) {
|
|
camera
|
|
.local_transform_mut()
|
|
.set_rotation(UnitQuaternion::from_axis_angle(
|
|
&Vector3::x_axis(),
|
|
self.pitch,
|
|
));
|
|
}
|
|
}
|
|
|
|
#[allow(clippy::collapsible_match)] // False positive
|
|
fn on_os_event(&mut self, event: &Event<()>, _context: ScriptContext) {
|
|
match event {
|
|
Event::DeviceEvent { event, .. } => {
|
|
if let DeviceEvent::MouseMotion { delta } = event {
|
|
let mouse_sens = 0.025;
|
|
|
|
self.yaw -= mouse_sens * delta.0 as f32;
|
|
self.pitch = (self.pitch + (delta.1 as f32) * mouse_sens)
|
|
.max(-90.0f32.to_radians())
|
|
.min(90.0f32.to_radians());
|
|
}
|
|
}
|
|
Event::WindowEvent { event, .. } => {
|
|
if let WindowEvent::KeyboardInput { input, .. } = event {
|
|
if let Some(key_code) = input.virtual_keycode {
|
|
match key_code {
|
|
VirtualKeyCode::W => {
|
|
self.controller.walk_forward = input.state == ElementState::Pressed
|
|
}
|
|
VirtualKeyCode::S => {
|
|
self.controller.walk_backward = input.state == ElementState::Pressed
|
|
}
|
|
VirtualKeyCode::A => {
|
|
self.controller.walk_left = input.state == ElementState::Pressed
|
|
}
|
|
VirtualKeyCode::D => {
|
|
self.controller.walk_right = input.state == ElementState::Pressed
|
|
}
|
|
VirtualKeyCode::Space => {
|
|
self.controller.jump = input.state == ElementState::Pressed
|
|
}
|
|
_ => (),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
|
|
fn plugin_uuid(&self) -> Uuid {
|
|
GamePlugin::type_uuid()
|
|
}
|
|
|
|
fn id(&self) -> Uuid {
|
|
Self::type_uuid()
|
|
}
|
|
}
|
|
|
|
#[derive(Visit, Inspect, Debug, Clone)]
|
|
struct Jumper {
|
|
timer: f32,
|
|
|
|
#[visit(optional)]
|
|
period: f32,
|
|
}
|
|
|
|
impl Default for Jumper {
|
|
fn default() -> Self {
|
|
Self {
|
|
timer: 0.0,
|
|
period: 0.5,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TypeUuidProvider for Jumper {
|
|
fn type_uuid() -> Uuid {
|
|
Uuid::from_str("942e9f5b-e036-4357-b514-91060d4059f5").unwrap()
|
|
}
|
|
}
|
|
|
|
impl ScriptTrait for Jumper {
|
|
fn on_property_changed(&mut self, args: &PropertyChanged) -> bool {
|
|
if let FieldKind::Object(ref value) = args.value {
|
|
return match args.name.as_ref() {
|
|
Self::TIMER => value.try_override(&mut self.timer),
|
|
Self::PERIOD => value.try_override(&mut self.period),
|
|
_ => false,
|
|
};
|
|
}
|
|
false
|
|
}
|
|
|
|
fn on_init(&mut self, _context: ScriptContext) {}
|
|
|
|
fn on_update(&mut self, context: ScriptContext) {
|
|
if let Some(rigid_body) = context.node.cast_mut::<RigidBody>() {
|
|
if self.timer > self.period {
|
|
rigid_body.apply_force(Vector3::new(0.0, 200.0, 0.0));
|
|
self.timer = 0.0;
|
|
}
|
|
|
|
self.timer += context.dt;
|
|
}
|
|
}
|
|
|
|
fn id(&self) -> Uuid {
|
|
Self::type_uuid()
|
|
}
|
|
|
|
fn plugin_uuid(&self) -> Uuid {
|
|
GamePlugin::type_uuid()
|
|
}
|
|
}
|