implement entering vehicles, variable engine parameters

This commit is contained in:
yuni 2024-03-28 13:26:14 +01:00
parent ec7fcc0ef4
commit 61324ffe7a
6 changed files with 112 additions and 13 deletions

View file

@ -2,6 +2,7 @@ use bevy::prelude::*;
use crate::{nature, settings, actor, audio, hud}; use crate::{nature, settings, actor, audio, hud};
const MIN_INTERACT_DISTANCE: f32 = 30.0; const MIN_INTERACT_DISTANCE: f32 = 30.0;
const NO_RIDE: u32 = 0;
pub struct ActorPlugin; pub struct ActorPlugin;
impl Plugin for ActorPlugin { impl Plugin for ActorPlugin {
@ -40,6 +41,7 @@ pub struct Actor {
pub m: f32, // mass pub m: f32, // mass
pub v: Vec3, // velocity pub v: Vec3, // velocity
pub angular_momentum: Quat, pub angular_momentum: Quat,
pub inside_entity: u32,
} }
impl Default for Actor { impl Default for Actor {
@ -48,12 +50,14 @@ impl Default for Actor {
hp: 100.0, hp: 100.0,
m: 100.0, m: 100.0,
v: Vec3::ZERO, v: Vec3::ZERO,
inside_entity: NO_RIDE,
angular_momentum: Quat::from_euler(EulerRot::XYZ, 0.001, 0.01, 0.003), angular_momentum: Quat::from_euler(EulerRot::XYZ, 0.001, 0.01, 0.003),
} }
} }
} }
#[derive(Component)] pub struct Player; #[derive(Component)] pub struct Player;
#[derive(Component)] pub struct PlayerDrivesThis;
#[derive(Component)] pub struct PlayerInConversation; #[derive(Component)] pub struct PlayerInConversation;
#[derive(Component)] pub struct InConversationWithPlayer; #[derive(Component)] pub struct InConversationWithPlayer;
@ -104,6 +108,27 @@ impl Default for LifeForm { fn default() -> Self { Self {
adrenaline_jolt: 0.0, adrenaline_jolt: 0.0,
}}} }}}
#[derive(Component)]
pub struct Vehicle;
#[derive(Component)]
pub struct Engine {
pub thrust_forward: f32,
pub thrust_back: f32,
pub thrust_sideways: f32,
pub reaction_wheels: f32,
}
impl Default for Engine {
fn default() -> Self {
Self {
thrust_forward: 1.0,
thrust_back: 1.0,
thrust_sideways: 1.0,
reaction_wheels: 1.0,
}
}
}
#[derive(Component)] #[derive(Component)]
pub struct Suit { pub struct Suit {
pub oxygen: f32, pub oxygen: f32,
@ -173,17 +198,20 @@ pub fn update_physics_lifeforms(
} }
pub fn handle_input( pub fn handle_input(
mut commands: Commands,
keyboard_input: Res<ButtonInput<KeyCode>>, keyboard_input: Res<ButtonInput<KeyCode>>,
settings: ResMut<settings::Settings>, settings: ResMut<settings::Settings>,
query: Query<(&Talker, &Transform)>, q_talker: Query<(&Talker, &Transform), Without<actor::Player>>,
player: Query<&Transform, With<actor::Player>>, mut player: Query<(&mut Actor, &mut Transform), With<actor::Player>>,
mut q_vehicles: Query<(Entity, &mut Visibility, &Transform), (With<actor::Vehicle>, Without<actor::Player>)>,
mut ew_conv: EventWriter<StartConversationEvent>, mut ew_conv: EventWriter<StartConversationEvent>,
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
) )
{ {
if keyboard_input.just_pressed(settings.key_interact) {
let mindist = MIN_INTERACT_DISTANCE * MIN_INTERACT_DISTANCE; let mindist = MIN_INTERACT_DISTANCE * MIN_INTERACT_DISTANCE;
if let Ok(player) = player.get_single() { if keyboard_input.just_pressed(settings.key_interact) {
for (talker, transform) in &query { if let Ok((_player_actor, player)) = player.get_single() {
for (talker, transform) in &q_talker {
if transform.translation.distance_squared(player.translation) <= mindist { if transform.translation.distance_squared(player.translation) <= mindist {
ew_conv.send(StartConversationEvent{talker: talker.clone()}); ew_conv.send(StartConversationEvent{talker: talker.clone()});
break; break;
@ -191,6 +219,20 @@ pub fn handle_input(
} }
} }
} }
else if keyboard_input.just_pressed(settings.key_vehicle) {
if let Ok((mut player_actor, mut player)) = player.get_single_mut() {
for (entity, mut visibility, vehicle_transform) in q_vehicles.iter_mut() {
if vehicle_transform.translation.distance_squared(player.translation) <= mindist {
player_actor.inside_entity = entity.index();
ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::EnterVehicle));
*player = *vehicle_transform;
*visibility = Visibility::Hidden;
commands.entity(entity).insert(PlayerDrivesThis);
break;
}
}
}
}
} }
pub fn handle_new_conversations( pub fn handle_new_conversations(

View file

@ -30,6 +30,7 @@ pub enum Sfx {
Switch, Switch,
Ping, Ping,
Connect, Connect,
EnterVehicle,
None, None,
} }
@ -142,6 +143,7 @@ pub fn play_sfx(
Sfx::IncomingChatMessage => sound_incoming_message.0.clone(), Sfx::IncomingChatMessage => sound_incoming_message.0.clone(),
Sfx::Ping => sound_ping.0.clone(), Sfx::Ping => sound_ping.0.clone(),
Sfx::Connect => sound_connect.0.clone(), Sfx::Connect => sound_connect.0.clone(),
Sfx::EnterVehicle => sound_switch.0.clone(),
Sfx::None => sound_ping.0.clone(), Sfx::None => sound_ping.0.clone(),
}, },
settings: PlaybackSettings::DESPAWN, settings: PlaybackSettings::DESPAWN,
@ -156,6 +158,7 @@ pub fn str2sfx(sfx_label: &str) -> Sfx {
"chat" => Sfx::IncomingChatMessage, "chat" => Sfx::IncomingChatMessage,
"ping" => Sfx::Ping, "ping" => Sfx::Ping,
"connect" => Sfx::Connect, "connect" => Sfx::Connect,
"entervehicle" => Sfx::EnterVehicle,
_ => Sfx::None, _ => Sfx::None,
}; };
} }

View file

@ -52,7 +52,8 @@ fn run_camera_controller(
mut mouse_events: EventReader<MouseMotion>, mut mouse_events: EventReader<MouseMotion>,
key_input: Res<ButtonInput<KeyCode>>, key_input: Res<ButtonInput<KeyCode>>,
thruster_sound_controller: Query<&AudioSink, With<audio::ComponentThrusterSound>>, thruster_sound_controller: Query<&AudioSink, With<audio::ComponentThrusterSound>>,
mut query: Query<(&mut Transform, &mut CameraController, &mut actor::Actor), With<Camera>>, q_engine: Query<&actor::Engine, With<actor::PlayerDrivesThis>>,
mut query: Query<(&mut Transform, &mut CameraController, &mut actor::Actor, &actor::Engine), With<Camera>>,
) { ) {
let dt = time.delta_seconds(); let dt = time.delta_seconds();
let mut play_thruster_sound = false; let mut play_thruster_sound = false;
@ -63,7 +64,7 @@ fn run_camera_controller(
focused = window_result.unwrap().focused; focused = window_result.unwrap().focused;
} }
if let Ok((mut transform, mut controller, mut actor)) = query.get_single_mut() { if let Ok((mut transform, mut controller, mut actor, player_engine)) = query.get_single_mut() {
if !controller.initialized { if !controller.initialized {
controller.initialized = true; controller.initialized = true;
transform.rotation = transform.rotation =
@ -120,8 +121,14 @@ fn run_camera_controller(
controller.velocity = Vec3::ZERO; controller.velocity = Vec3::ZERO;
} }
} }
let forward = *transform.forward();
let right = *transform.right(); let engine = if let Ok(engine) = q_engine.get_single() { engine } else { player_engine };
let forward = *transform.forward() * (if axis_input.z > 0.0 {
engine.thrust_forward
} else {
engine.thrust_back
});
let right = *transform.right() * engine.thrust_sideways;
actor.v += controller.velocity.x * dt * right actor.v += controller.velocity.x * dt * right
+ controller.velocity.y * dt * Vec3::Y + controller.velocity.y * dt * Vec3::Y
+ controller.velocity.z * dt * forward; + controller.velocity.z * dt * forward;

View file

@ -79,6 +79,8 @@ actor 3650 230 5000 asteroid1
actor 10 -30 20 bike actor 10 -30 20 bike
scale 5 scale 5
vehicle yes
thrust 50 0 10 0.5
actor 10 0 70 suit actor 10 0 70 suit
name Icarus name Icarus

View file

@ -23,6 +23,7 @@ pub struct Settings {
pub key_run: KeyCode, pub key_run: KeyCode,
pub key_stop: KeyCode, pub key_stop: KeyCode,
pub key_interact: KeyCode, pub key_interact: KeyCode,
pub key_vehicle: KeyCode,
pub key_reply1: KeyCode, pub key_reply1: KeyCode,
pub key_reply2: KeyCode, pub key_reply2: KeyCode,
pub key_reply3: KeyCode, pub key_reply3: KeyCode,
@ -70,6 +71,7 @@ impl Default for Settings {
key_run: KeyCode::KeyR, key_run: KeyCode::KeyR,
key_stop: KeyCode::Space, key_stop: KeyCode::Space,
key_interact: KeyCode::KeyE, key_interact: KeyCode::KeyE,
key_vehicle: KeyCode::KeyV,
key_reply1: KeyCode::Digit1, key_reply1: KeyCode::Digit1,
key_reply2: KeyCode::Digit2, key_reply2: KeyCode::Digit2,
key_reply3: KeyCode::Digit3, key_reply3: KeyCode::Digit3,

View file

@ -90,6 +90,10 @@ pub fn setup(
integrity: 0.3, integrity: 0.3,
..default() ..default()
}, },
actor::Engine {
thrust_forward: 1.2,
..default()
},
Camera3dBundle { Camera3dBundle {
camera: Camera { camera: Camera {
hdr: true, // HDR is required for bloom hdr: true, // HDR is required for bloom
@ -236,6 +240,11 @@ struct ParserState {
is_lifeform: bool, is_lifeform: bool,
is_alive: bool, is_alive: bool,
is_suited: bool, is_suited: bool,
is_vehicle: bool,
thrust_forward: f32,
thrust_sideways: f32,
thrust_back: f32,
reaction_wheels: f32,
// Chat fields // Chat fields
delay: f64, delay: f64,
@ -249,6 +258,7 @@ struct ParserState {
impl Default for ParserState { impl Default for ParserState {
fn default() -> Self { fn default() -> Self {
let default_actor = actor::Actor::default(); let default_actor = actor::Actor::default();
let default_engine = actor::Engine::default();
Self { Self {
class: DefClass::None, class: DefClass::None,
name: "NONAME".to_string(), name: "NONAME".to_string(),
@ -263,6 +273,11 @@ impl Default for ParserState {
is_lifeform: false, is_lifeform: false,
is_alive: false, is_alive: false,
is_suited: false, is_suited: false,
is_vehicle: false,
thrust_forward: default_engine.thrust_forward,
thrust_sideways: default_engine.thrust_forward,
thrust_back: default_engine.thrust_back,
reaction_wheels: default_engine.reaction_wheels,
delay: 0.0, delay: 0.0,
text: "".to_string(), text: "".to_string(),
@ -322,6 +337,13 @@ impl ParserState {
conv_id: self.chat.clone(), conv_id: self.chat.clone(),
..default() ..default()
}; };
let component_vehicle = actor::Vehicle;
let component_engine = actor::Engine {
thrust_forward: self.thrust_forward,
thrust_back: self.thrust_back,
thrust_sideways: self.thrust_sideways,
reaction_wheels: self.reaction_wheels,
};
let component_suit = actor::Suit::default(); let component_suit = actor::Suit::default();
let component_model = SceneBundle { let component_model = SceneBundle {
transform: Transform { transform: Transform {
@ -363,6 +385,15 @@ impl ParserState {
component_model, component_model,
)); ));
} }
else {
if self.is_vehicle {
commands.spawn((
component_actor,
component_model,
component_vehicle,
component_engine,
));
}
else { else {
commands.spawn(( commands.spawn((
component_actor, component_actor,
@ -370,6 +401,7 @@ impl ParserState {
)); ));
} }
} }
}
self.reset(); self.reset();
} }
fn spawn_entities(&mut self, commands: &mut Commands, asset_server: &Res<AssetServer>) { fn spawn_entities(&mut self, commands: &mut Commands, asset_server: &Res<AssetServer>) {
@ -448,6 +480,9 @@ pub fn load_defs(
state.is_lifeform = true; state.is_lifeform = true;
state.is_suited = true; state.is_suited = true;
} }
["vehicle", "yes"] => {
state.is_vehicle = true;
}
["pronoun", pronoun] => { ["pronoun", pronoun] => {
state.pronoun = pronoun.to_string(); state.pronoun = pronoun.to_string();
} }
@ -482,6 +517,14 @@ pub fn load_defs(
continue; continue;
} }
} }
["thrust", forward, back, sideways, reaction_wheels] => {
if let (Ok(forward_float), Ok(back_float), Ok(sideways_float), Ok(reaction_wheels_float)) = (forward.parse::<f32>(), back.parse::<f32>(), sideways.parse::<f32>(), reaction_wheels.parse::<f32>()) {
state.thrust_forward = forward_float;
state.thrust_back = back_float;
state.thrust_sideways = sideways_float;
state.reaction_wheels = reaction_wheels_float;
}
}
// Parsing chats // Parsing chats
["chat", chat_name] => { ["chat", chat_name] => {