2025-03-11 17:58:40 +00:00
|
|
|
use std::collections::HashMap;
|
|
|
|
|
2025-03-11 12:49:23 +00:00
|
|
|
use anyhow::Result;
|
|
|
|
|
|
|
|
use ecs::*;
|
2025-03-12 07:19:59 +00:00
|
|
|
use engine::prelude::{
|
2025-03-12 15:56:56 +00:00
|
|
|
cgmath::{Vector3, Vector4, vec3, vec4},
|
2025-03-12 07:19:59 +00:00
|
|
|
*,
|
|
|
|
};
|
2025-03-11 12:49:23 +00:00
|
|
|
|
2025-03-13 13:39:24 +00:00
|
|
|
use crate::FREE_CAMERA_CONTROL;
|
|
|
|
|
2025-03-11 17:58:40 +00:00
|
|
|
#[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)]
|
2025-03-12 07:19:59 +00:00
|
|
|
struct InputSettings {
|
2025-03-13 13:39:24 +00:00
|
|
|
mappings: HashMap<(String, u32, Input), (Control, bool)>,
|
2025-03-11 17:58:40 +00:00
|
|
|
}
|
|
|
|
|
2025-03-12 07:19:59 +00:00
|
|
|
impl Default for InputSettings {
|
2025-03-11 17:58:40 +00:00
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
mappings: [
|
|
|
|
(
|
2025-03-13 13:39:24 +00:00
|
|
|
("Thrustmaster T.16000M".to_string(), 1, Input::Axis(0)),
|
|
|
|
(Control::Pitch, false),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
("Thrustmaster T.16000M".to_string(), 1, Input::Axis(1)),
|
|
|
|
(Control::Throttle, false),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
("Thrustmaster T.16000M".to_string(), 1, Input::Axis(2)),
|
|
|
|
(Control::StrafeHorizontal, false),
|
2025-03-11 17:58:40 +00:00
|
|
|
),
|
|
|
|
(
|
2025-03-13 13:39:24 +00:00
|
|
|
("Thrustmaster T.16000M".to_string(), 1, Input::Axis(3)),
|
|
|
|
(Control::StrafeVertical, false),
|
2025-03-11 17:58:40 +00:00
|
|
|
),
|
|
|
|
(
|
2025-03-13 13:39:24 +00:00
|
|
|
(
|
|
|
|
"Thrustmaster T.16000M".to_string(),
|
|
|
|
1,
|
|
|
|
Input::Button(Button::One),
|
|
|
|
),
|
|
|
|
(Control::PrimaryWeapon, false),
|
2025-03-11 17:58:40 +00:00
|
|
|
),
|
|
|
|
(
|
2025-03-13 13:39:24 +00:00
|
|
|
("Thrustmaster T.16000M".to_string(), 0, Input::Axis(0)),
|
|
|
|
(Control::Yaw, true),
|
2025-03-11 17:58:40 +00:00
|
|
|
),
|
|
|
|
(
|
2025-03-13 13:39:24 +00:00
|
|
|
("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),
|
2025-03-11 17:58:40 +00:00
|
|
|
),
|
|
|
|
]
|
|
|
|
.into_iter()
|
|
|
|
.collect(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-12 07:19:59 +00:00
|
|
|
impl InputSettings {
|
2025-03-13 13:39:24 +00:00
|
|
|
pub fn map_axis(
|
|
|
|
&self,
|
|
|
|
device_name: impl ToString,
|
|
|
|
device_id: u32,
|
|
|
|
axis: u8,
|
|
|
|
) -> Option<(Control, bool)> {
|
2025-03-11 17:58:40 +00:00
|
|
|
self.mappings
|
2025-03-13 13:39:24 +00:00
|
|
|
.get(&(device_name.to_string(), device_id, Input::Axis(axis)))
|
2025-03-11 17:58:40 +00:00
|
|
|
.map(|control| *control)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-11 12:49:23 +00:00
|
|
|
pub struct Game;
|
|
|
|
|
|
|
|
impl Game {
|
2025-03-12 14:24:39 +00:00
|
|
|
pub fn update(&mut self, world: &mut World) -> Result<()> {
|
2025-03-13 13:39:24 +00:00
|
|
|
if FREE_CAMERA_CONTROL {
|
|
|
|
let now = world.now();
|
|
|
|
let mut resources = world.resources.multi_mut();
|
|
|
|
let scene = resources.get::<Scene>();
|
|
|
|
let camera_control = resources.get::<FreeCameraControl>();
|
2025-03-12 14:24:39 +00:00
|
|
|
|
2025-03-13 13:39:24 +00:00
|
|
|
camera_control.update(now, scene.view_mut())?;
|
|
|
|
}
|
2025-03-12 14:24:39 +00:00
|
|
|
|
2025-03-11 12:49:23 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn event(&mut self, world: &mut World, event: EngineEvent<'_>) -> Result<()> {
|
2025-03-13 13:39:24 +00:00
|
|
|
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(())
|
|
|
|
}
|
2025-03-11 17:58:40 +00:00
|
|
|
|
2025-03-13 13:39:24 +00:00
|
|
|
fn motion_concepts<'a>(
|
|
|
|
world: &mut World,
|
|
|
|
event: EngineEvent<'a>,
|
|
|
|
) -> Result<Option<EngineEvent<'a>>> {
|
|
|
|
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<Option<EngineEvent<'a>>> {
|
2025-03-11 12:49:23 +00:00
|
|
|
match event {
|
2025-03-13 13:39:24 +00:00
|
|
|
EngineEvent::MouseButtonDown(MouseButton::Middle) => {
|
|
|
|
let camera_control = world.resources.get_mut::<FreeCameraControl>();
|
2025-03-12 14:24:39 +00:00
|
|
|
camera_control.mouse_down();
|
|
|
|
}
|
2025-03-13 13:39:24 +00:00
|
|
|
EngineEvent::MouseButtonUp(MouseButton::Middle) => {
|
|
|
|
let camera_control = world.resources.get_mut::<FreeCameraControl>();
|
2025-03-12 14:24:39 +00:00
|
|
|
camera_control.mouse_release();
|
|
|
|
}
|
|
|
|
EngineEvent::MouseMotion(x, y) => {
|
2025-03-13 13:39:24 +00:00
|
|
|
let mut resources = world.resources.multi_mut();
|
2025-03-12 14:24:39 +00:00
|
|
|
let scene = resources.get::<Scene>();
|
|
|
|
let camera_control = resources.get::<FreeCameraControl>();
|
|
|
|
|
|
|
|
camera_control.mouse_move(x, y, scene.view_mut())?;
|
2025-03-13 13:39:24 +00:00
|
|
|
|
|
|
|
return Ok(Some(event));
|
2025-03-12 14:24:39 +00:00
|
|
|
}
|
|
|
|
EngineEvent::KeyDown(key) => {
|
2025-03-13 13:39:24 +00:00
|
|
|
let camera_control = world.resources.get_mut::<FreeCameraControl>();
|
2025-03-12 14:24:39 +00:00
|
|
|
|
|
|
|
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),
|
2025-03-13 13:39:24 +00:00
|
|
|
Keycode::Space => camera_control.up_down(1.0),
|
|
|
|
Keycode::LCtrl => camera_control.up_down(-1.0),
|
2025-03-12 14:24:39 +00:00
|
|
|
|
2025-03-13 13:39:24 +00:00
|
|
|
_ => return Ok(Some(event)),
|
2025-03-12 14:24:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
EngineEvent::KeyUp(key) => {
|
2025-03-13 13:39:24 +00:00
|
|
|
let camera_control = world.resources.get_mut::<FreeCameraControl>();
|
2025-03-12 14:24:39 +00:00
|
|
|
|
|
|
|
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),
|
2025-03-13 13:39:24 +00:00
|
|
|
Keycode::Space => camera_control.up_down(-1.0),
|
|
|
|
Keycode::LCtrl => camera_control.up_down(1.0),
|
2025-03-12 14:24:39 +00:00
|
|
|
|
2025-03-13 13:39:24 +00:00
|
|
|
_ => return Ok(Some(event)),
|
2025-03-12 14:24:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-13 13:39:24 +00:00
|
|
|
_ => return Ok(Some(event)),
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(None)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn joystick_movement<'a>(
|
|
|
|
world: &mut World,
|
|
|
|
event: EngineEvent<'a>,
|
|
|
|
) -> Result<Option<EngineEvent<'a>>> {
|
|
|
|
let player = world.resources.get::<PlayerEntity>();
|
|
|
|
let (fighter_object, resources) = world.entity_resources(player.0)?;
|
|
|
|
|
|
|
|
match event {
|
2025-03-12 07:19:59 +00:00
|
|
|
EngineEvent::JoystickAxis(joystick, axis_index, value) => {
|
2025-03-13 13:39:24 +00:00
|
|
|
let mut normalized = value as f32 * (i16::MAX as f32).recip();
|
2025-03-12 07:19:59 +00:00
|
|
|
let input_settings = resources.get::<InputSettings>();
|
|
|
|
let player_control = fighter_object.get_component_mut::<FreeSpaceControl>()?;
|
|
|
|
|
2025-03-13 13:39:24 +00:00
|
|
|
if let Some((control, inverted)) =
|
|
|
|
input_settings.map_axis(joystick.name(), joystick.id(), axis_index)
|
|
|
|
{
|
|
|
|
if inverted {
|
|
|
|
normalized = -normalized
|
|
|
|
};
|
|
|
|
|
2025-03-12 07:19:59 +00:00
|
|
|
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 => (),
|
|
|
|
}
|
|
|
|
}
|
2025-03-11 12:49:23 +00:00
|
|
|
}
|
2025-03-11 17:58:40 +00:00
|
|
|
|
2025-03-13 13:39:24 +00:00
|
|
|
_ => return Ok(Some(event)),
|
2025-03-11 12:49:23 +00:00
|
|
|
}
|
|
|
|
|
2025-03-13 13:39:24 +00:00
|
|
|
Ok(None)
|
2025-03-11 12:49:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Game {
|
|
|
|
pub fn setup_updates(world_builder: &mut WorldBuilder) -> Result<()> {
|
2025-03-11 17:58:40 +00:00
|
|
|
world_builder.add_update(
|
|
|
|
"player_rotation",
|
|
|
|
200,
|
|
|
|
Self::player_orientation,
|
|
|
|
EmptyFilter,
|
|
|
|
)?;
|
|
|
|
|
2025-03-13 13:39:24 +00:00
|
|
|
if !FREE_CAMERA_CONTROL {
|
|
|
|
world_builder.add_update("camera_position", 1_000, Self::camera_update, EmptyFilter)?;
|
|
|
|
}
|
2025-03-12 07:19:59 +00:00
|
|
|
|
2025-03-11 17:58:40 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn setup_scene(world: &mut World) -> Result<()> {
|
2025-03-12 15:56:56 +00:00
|
|
|
let mut fighter = AssetHandler::create(world).create_entity("fighter_edited")?;
|
2025-03-13 13:39:24 +00:00
|
|
|
fighter.insert_component(FreeSpaceControl::new(
|
|
|
|
0.02,
|
|
|
|
FreeSpaceControlSettings::default(),
|
|
|
|
));
|
2025-03-11 17:58:40 +00:00
|
|
|
|
|
|
|
let player = PlayerEntity(world.add_entity(fighter)?);
|
|
|
|
world.resources.insert(player);
|
2025-03-12 07:19:59 +00:00
|
|
|
world.resources.insert(InputSettings::default());
|
2025-03-11 17:58:40 +00:00
|
|
|
|
2025-03-12 15:56:56 +00:00
|
|
|
let context = world.resources.get::<Context>();
|
|
|
|
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 = world.resources.get_mut::<Scene>();
|
|
|
|
scene.add_light(light)?;
|
|
|
|
|
2025-03-11 17:58:40 +00:00
|
|
|
world.commit_entity_changes()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// updates
|
|
|
|
impl Game {
|
|
|
|
fn player_orientation(
|
|
|
|
world: &mut World,
|
|
|
|
_entity: Entity,
|
|
|
|
draw: &mut Draw,
|
|
|
|
control: &mut FreeSpaceControl,
|
|
|
|
) -> Result<()> {
|
2025-03-12 07:19:59 +00:00
|
|
|
control.update(world.now());
|
|
|
|
draw.set_transform(control.transform())
|
|
|
|
}
|
2025-03-11 12:49:23 +00:00
|
|
|
|
2025-03-12 07:19:59 +00:00
|
|
|
fn camera_update(
|
|
|
|
world: &mut World,
|
|
|
|
_entity: Entity,
|
|
|
|
control: &mut FreeSpaceControl,
|
|
|
|
) -> Result<()> {
|
2025-03-12 14:24:39 +00:00
|
|
|
const DEFAULT_CENTER: Vector4<f32> = vec4(0.0, 0.0, 0.0, 1.0);
|
|
|
|
|
2025-03-12 07:19:59 +00:00
|
|
|
let scene = world.resources.get_mut::<Scene>();
|
|
|
|
let view = scene.view_mut();
|
|
|
|
|
|
|
|
view.camera_mut()
|
2025-03-12 14:24:39 +00:00
|
|
|
.set_center((control.translation() * DEFAULT_CENTER).truncate());
|
2025-03-12 07:19:59 +00:00
|
|
|
view.camera_mut()
|
2025-03-13 13:39:24 +00:00
|
|
|
.set_eye_dir(control.rotation() * Vector3::unit_y());
|
|
|
|
view.camera_mut()
|
|
|
|
.set_up(control.rotation() * Vector3::unit_z());
|
2025-03-12 07:19:59 +00:00
|
|
|
|
|
|
|
view.update_buffer()
|
2025-03-11 12:49:23 +00:00
|
|
|
}
|
|
|
|
}
|