use std::collections::HashMap; use anyhow::Result; use ecs::*; use engine::prelude::{ cgmath::{Vector3, Vector4, vec3}, *, }; use crate::{FREE_CAMERA_CONTROL, celestial_object::*}; #[derive(Clone, Copy, Debug, Resource)] struct PlayerEntity(Entity); #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] enum Input { Axis(u8), Button(Button), } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] enum Button { One, } #[derive(Clone, Copy, Debug)] enum Control { Throttle, StrafeHorizontal, StrafeVertical, Yaw, Pitch, Roll, PrimaryWeapon, SecondaryWeapon, } #[derive(Clone, Debug, Resource)] struct InputSettings { mappings: HashMap<(String, u32, Input), (Control, bool)>, } impl Default for InputSettings { fn default() -> Self { Self { mappings: [ ( ("Thrustmaster T.16000M".to_string(), 1, Input::Axis(0)), (Control::Pitch, false), ), ( ("Thrustmaster T.16000M".to_string(), 1, Input::Axis(1)), (Control::Throttle, true), ), ( ("Thrustmaster T.16000M".to_string(), 1, Input::Axis(2)), (Control::StrafeHorizontal, false), ), ( ("Thrustmaster T.16000M".to_string(), 1, Input::Axis(3)), (Control::StrafeVertical, false), ), ( ( "Thrustmaster T.16000M".to_string(), 1, Input::Button(Button::One), ), (Control::PrimaryWeapon, false), ), ( ("Thrustmaster T.16000M".to_string(), 0, Input::Axis(0)), (Control::Yaw, true), ), ( ("Thrustmaster T.16000M".to_string(), 0, Input::Axis(1)), (Control::Roll, false), ), ( ( "Thrustmaster T.16000M".to_string(), 0, Input::Button(Button::One), ), (Control::SecondaryWeapon, false), ), ] .into_iter() .collect(), } } } impl InputSettings { pub fn map_axis( &self, device_name: impl ToString, device_id: u32, axis: u8, ) -> Option<(Control, bool)> { self.mappings .get(&(device_name.to_string(), device_id, Input::Axis(axis))) .map(|control| *control) } } pub struct Game; impl Game { pub fn update(&mut self, world: &mut World) -> Result<()> { if FREE_CAMERA_CONTROL { let now = world.now(); let (scene, camera_control): (&mut Scene, &mut FreeCameraControl) = world.resources.get_mut()?; camera_control.update(now, scene.view_mut())?; } Ok(()) } pub fn event(&mut self, world: &mut World, event: EngineEvent<'_>) -> Result<()> { if let Some(event) = Self::motion_concepts(world, event)? { match event { EngineEvent::JoystickAdded(joystick) => { println!("joystick {} added", joystick.name()); } EngineEvent::JoystickRemoved(joystick) => { println!("joystick {} removed", joystick.name()); } _ => (), } } Ok(()) } fn motion_concepts<'a>( world: &mut World, event: EngineEvent<'a>, ) -> Result>> { if FREE_CAMERA_CONTROL { Self::free_camera(world, event) } else { Self::joystick_movement(world, event) } } fn free_camera<'a>( world: &mut World, event: EngineEvent<'a>, ) -> Result>> { match event { EngineEvent::MouseButtonDown(MouseButton::Middle) => { let camera_control: &mut FreeCameraControl = world.resources.get_mut()?; camera_control.mouse_down(); } EngineEvent::MouseButtonUp(MouseButton::Middle) => { let camera_control: &mut FreeCameraControl = world.resources.get_mut()?; camera_control.mouse_release(); } EngineEvent::MouseMotion(x, y) => { let (scene, camera_control): (&mut Scene, &mut FreeCameraControl) = world.resources.get_mut()?; camera_control.mouse_move(x, y, scene.view_mut())?; return Ok(Some(event)); } EngineEvent::KeyDown(key) => { let camera_control: &mut FreeCameraControl = world.resources.get_mut()?; match key { Keycode::W => camera_control.forward_back(1.0), Keycode::A => camera_control.left_right(-1.0), Keycode::S => camera_control.forward_back(-1.0), Keycode::D => camera_control.left_right(1.0), Keycode::Space => camera_control.up_down(1.0), Keycode::LCtrl => camera_control.up_down(-1.0), _ => return Ok(Some(event)), } } EngineEvent::KeyUp(key) => { let camera_control: &mut FreeCameraControl = world.resources.get_mut()?; match key { Keycode::W => camera_control.forward_back(-1.0), Keycode::A => camera_control.left_right(1.0), Keycode::S => camera_control.forward_back(1.0), Keycode::D => camera_control.left_right(-1.0), Keycode::Space => camera_control.up_down(-1.0), Keycode::LCtrl => camera_control.up_down(1.0), _ => return Ok(Some(event)), } } _ => return Ok(Some(event)), } Ok(None) } fn joystick_movement<'a>( world: &mut World, event: EngineEvent<'a>, ) -> Result>> { let player = world.resources.get::(); let (fighter_object, resources) = world.entity_resources(player.0)?; match event { EngineEvent::JoystickAxis(joystick, axis_index, value) => { let mut normalized = value as f32 * (i16::MAX as f32).recip(); let input_settings = resources.get::(); let player_control = fighter_object.get_component_mut::()?; if let Some((control, inverted)) = input_settings.map_axis(joystick.name(), joystick.id(), axis_index) { if inverted { normalized = -normalized }; match control { Control::Throttle => player_control.set_throttle(normalized), Control::StrafeHorizontal => { player_control.set_left_right_strafe(normalized) } Control::StrafeVertical => player_control.set_up_down_strafe(normalized), Control::Yaw => player_control.set_yaw(normalized), Control::Pitch => player_control.set_pitch(normalized), Control::Roll => player_control.set_roll(normalized), Control::PrimaryWeapon => (), Control::SecondaryWeapon => (), } } } _ => return Ok(Some(event)), } Ok(None) } } impl Game { pub fn setup_updates(world_builder: &mut WorldBuilder) -> Result<()> { world_builder.add_update( "player_rotation", 200, Self::player_orientation, EmptyFilter, )?; if !FREE_CAMERA_CONTROL { world_builder.add_update("camera_position", 1_000, Self::camera_update, EmptyFilter)?; } world_builder.add_update( "celestial velocity update", 100, Self::celestial_velocity_update, (EmptyFilter, EmptyFilter), )?; world_builder.add_update( "celestial buffer update", 110, Self::celestial_buffer_update, EmptyFilter, )?; Ok(()) } pub fn setup_scene(world: &mut World) -> Result<()> { let scene: &mut Scene = world.resources.get_mut()?; scene.view_mut().camera_mut().look_at(false); let mut fighter = AssetHandler::create(world).create_entity("fighter_edited")?; fighter.insert_component(FreeSpaceControl::new( 0.02, FreeSpaceControlSettings::default(), )); let player = PlayerEntity(world.add_entity(fighter)?); world.resources.insert(player); world.resources.insert(InputSettings::default()); let mut example_sun = CelestialObject::new(world, CelestialClass::Sun, 5, None)?; let sun_settings = example_sun.get_component_mut::()?; sun_settings.location = vec3(1_000_000_000.0, 1_000_000_000.0, 0.0); sun_settings.radius = 696_340_000.0; let sun_entity = world.add_entity(example_sun)?; let mut example_planet = CelestialObject::new(world, CelestialClass::Solid, 5, sun_entity)?; let sun_settings = example_planet.get_component_mut::()?; sun_settings.location.x = 10_000_000.0; sun_settings.radius = 6_378_000.0; world.add_entity(example_planet)?; let context = world.resources.get::(); let mut light = Light::point_light(context.device())?; light.set_position(vec3(10_000.0, 10_000.0, 10_000.0))?; light.set_power(50_000_000_000.0)?; light.set_color(vec3(1.0, 1.0, 1.0))?; let scene: &mut Scene = world.resources.get_mut()?; scene.add_light(light)?; world.commit_entity_changes() } } // updates impl Game { fn player_orientation( world: &mut World, _entity: Entity, draw: &mut Draw, control: &mut FreeSpaceControl, ) -> Result<()> { control.update(world.now()); draw.set_transform(control.transform()) } fn camera_update( world: &mut World, _entity: Entity, control: &mut FreeSpaceControl, ) -> Result<()> { let scene: &mut Scene = world.resources.get_mut()?; let view = scene.view_mut(); view.camera_mut() .set_center((control.translation() * Vector4::unit_w()).truncate()); view.camera_mut() .set_eye_dir(control.rotation() * Vector3::unit_y()); view.camera_mut() .set_up(control.rotation() * Vector3::unit_z()); view.update_buffer() } fn celestial_buffer_update( _: &mut World, _: Entity, draw: &mut Draw, control: &mut CelestialObjectSettings, ) -> Result<()> { draw.set_transform(control.model_matrix())?; Ok(()) } fn celestial_velocity_update( world: &mut World, (_, draw, lhs_control, reference): ( Entity, &mut Draw, &mut CelestialObjectSettings, &mut CelestialReference, ), (rhs_entity, rhs_control): (Entity, &mut CelestialObjectSettings), ) -> Result<()> { if reference.entity == rhs_entity { lhs_control.update(world.now(), draw, rhs_control)?; } Ok(()) } }