use std::collections::HashMap; use anyhow::Result; use ecs::*; use engine::prelude::{ cgmath::{Vector3, Vector4}, *, }; #[derive(Clone, Copy, Debug)] 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)] struct InputSettings { mappings: HashMap<(String, Input), Control>, } impl Default for InputSettings { fn default() -> Self { Self { mappings: [ ( ("Joystick 1".to_string(), Input::Axis(0)), Control::Throttle, ), ( ("Joystick 1".to_string(), Input::Axis(1)), Control::StrafeHorizontal, ), ( ("Joystick 1".to_string(), Input::Axis(2)), Control::StrafeVertical, ), (("Joystick 1".to_string(), Input::Axis(3)), Control::Pitch), ( ("Joystick 1".to_string(), Input::Button(Button::One)), Control::PrimaryWeapon, ), (("Joystick 2".to_string(), Input::Axis(1)), Control::Yaw), (("Joystick 2".to_string(), Input::Axis(0)), Control::Roll), ( ("Joystick 2".to_string(), Input::Button(Button::One)), Control::SecondaryWeapon, ), ] .into_iter() .collect(), } } } impl InputSettings { pub fn map_axis(&self, device_name: impl ToString, axis: u8) -> Option { self.mappings .get(&(device_name.to_string(), Input::Axis(axis))) .map(|control| *control) } } pub struct Game; impl Game { pub fn update(&mut self, _world: &mut World) -> Result<()> { Ok(()) } pub fn event(&mut self, world: &mut World, event: EngineEvent<'_>) -> Result<()> { let player = world.resources.get::(); let (fighter_object, resources) = world.entity_resources(player.0)?; match event { EngineEvent::JoystickAxis(joystick, axis_index, value) => { let 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) = input_settings.map_axis(joystick.name(), axis_index) { 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 => (), } } } _ => (), } Ok(()) } } impl Game { pub fn setup_updates(world_builder: &mut WorldBuilder) -> Result<()> { world_builder.add_update( "player_rotation", 200, Self::player_orientation, EmptyFilter, )?; world_builder.add_update("camera_position", 1_000, Self::camera_update, EmptyFilter)?; Ok(()) } pub fn setup_scene(world: &mut World) -> Result<()> { let mut fighter = AssetHandler::create(world).create_entity("fighter")?; fighter.insert_component(FreeSpaceControl::new(FreeSpaceControlSettings::default())); let player = PlayerEntity(world.add_entity(fighter)?); world.resources.insert(player); world.resources.insert(InputSettings::default()); 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 = 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.update_buffer() } }