engine/examples/free_space/src/game.rs

385 lines
12 KiB
Rust
Raw Normal View History

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-04-05 08:27:57 +00:00
cgmath::{Vector3, Vector4, vec3},
2025-03-12 07:19:59 +00:00
*,
};
2025-03-11 12:49:23 +00:00
2025-03-14 13:19:49 +00:00
use crate::{FREE_CAMERA_CONTROL, celestial_object::*};
2025-03-13 13:39:24 +00:00
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)),
2025-03-14 13:19:49 +00:00
(Control::Throttle, true),
2025-03-13 13:39:24 +00:00
),
(
("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 {
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-13 13:39:24 +00:00
camera_control.update(now, scene.view_mut())?;
}
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>();
camera_control.mouse_down();
}
2025-03-13 13:39:24 +00:00
EngineEvent::MouseButtonUp(MouseButton::Middle) => {
let camera_control = world.resources.get_mut::<FreeCameraControl>();
camera_control.mouse_release();
}
EngineEvent::MouseMotion(x, y) => {
2025-03-13 13:39:24 +00:00
let mut resources = world.resources.multi_mut();
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));
}
EngineEvent::KeyDown(key) => {
2025-03-13 13:39:24 +00:00
let camera_control = world.resources.get_mut::<FreeCameraControl>();
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-13 13:39:24 +00:00
_ => return Ok(Some(event)),
}
}
EngineEvent::KeyUp(key) => {
2025-03-13 13:39:24 +00:00
let camera_control = world.resources.get_mut::<FreeCameraControl>();
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-13 13:39:24 +00:00
_ => return Ok(Some(event)),
}
}
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-14 12:25:11 +00:00
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,
)?;
2025-03-11 17:58:40 +00:00
Ok(())
}
pub fn setup_scene(world: &mut World) -> Result<()> {
2025-03-14 13:19:49 +00:00
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);
2025-03-12 07:19:59 +00:00
world.resources.insert(InputSettings::default());
2025-03-11 17:58:40 +00:00
2025-03-14 12:25:11 +00:00
let mut example_sun = CelestialObject::new(world, CelestialClass::Sun, 5, None)?;
let sun_settings = example_sun.get_component_mut::<CelestialObjectSettings>()?;
2025-03-14 13:19:49 +00:00
sun_settings.location = vec3(1_000_000_000.0, 1_000_000_000.0, 0.0);
sun_settings.radius = 696_340_000.0;
2025-03-14 12:25:11 +00:00
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::<CelestialObjectSettings>()?;
2025-03-14 13:19:49 +00:00
sun_settings.location.x = 10_000_000.0;
sun_settings.radius = 6_378_000.0;
2025-03-13 21:09:11 +00:00
world.add_entity(example_planet)?;
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<()> {
let scene = world.resources.get_mut::<Scene>();
let view = scene.view_mut();
view.camera_mut()
2025-04-05 08:27:57 +00:00
.set_center((control.translation() * Vector4::unit_w()).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
}
2025-03-14 12:25:11 +00:00
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(())
}
2025-03-11 12:49:23 +00:00
}