From a37ba60eaf5e23780e1e682e8b5b569e038f4a2b Mon Sep 17 00:00:00 2001 From: hut Date: Fri, 5 Apr 2024 18:14:12 +0200 Subject: [PATCH] WIP targeting world objects with mouse click --- src/commands.rs | 10 +++++++++- src/defs.txt | 2 ++ src/hud.rs | 51 +++++++++++++++++++++++++++++++++++++++++++++++-- src/settings.rs | 2 ++ 4 files changed, 62 insertions(+), 3 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index b66ba0f..495a879 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -3,7 +3,7 @@ extern crate regex; use bevy::prelude::*; use bevy_xpbd_3d::prelude::*; use bevy::math::DVec3; -use crate::{actor, chat, nature, world}; +use crate::{actor, chat, hud, nature, world}; use regex::Regex; use std::f32::consts::PI; use std::f64::consts::PI as PI64; @@ -49,6 +49,7 @@ struct ParserState { is_alive: bool, is_suited: bool, is_vehicle: bool, + is_clickable: bool, has_physics: bool, wants_maxrotation: Option, wants_maxvelocity: Option, @@ -102,6 +103,7 @@ impl Default for ParserState { is_alive: false, is_suited: false, is_vehicle: false, + is_clickable: true, has_physics: true, wants_maxrotation: None, wants_maxvelocity: None, @@ -263,6 +265,9 @@ pub fn load_defs( ["vehicle", "yes"] => { state.is_vehicle = true; } + ["clickable", "no"] => { + state.is_clickable = false; + } ["moon", "yes"] => { state.model_scale *= 3.0; } @@ -652,6 +657,9 @@ fn spawn_entities( ..default() }); } + if state.is_clickable { + actor.insert(hud::IsClickable); + } if let Some(value) = state.wants_maxrotation { actor.insert(actor::WantsMaxRotation(value)); } diff --git a/src/defs.txt b/src/defs.txt index 555102e..044d0f3 100644 --- a/src/defs.txt +++ b/src/defs.txt @@ -21,6 +21,7 @@ actor 0 593051 0 suit thrust 1.2 1 1 300 1.5 rotationy 0.65 engine monopropellant + clickable no actor 10 -30 20 MeteorAceGT relativeto player @@ -32,6 +33,7 @@ actor 10 -30 20 MeteorAceGT camdistance 50 mass 3000 angularmomentum 0.1 0.1 0.3 + clickable no actor 0 0 0 io relativeto jupiter diff --git a/src/hud.rs b/src/hud.rs index 66704b3..e01387e 100644 --- a/src/hud.rs +++ b/src/hud.rs @@ -2,6 +2,7 @@ use crate::{actor, audio, chat, nature, settings}; use bevy::prelude::*; use bevy::diagnostic::{DiagnosticsStore, FrameTimeDiagnosticsPlugin}; use bevy_xpbd_3d::prelude::*; +use bevy::math::DVec3; use std::collections::VecDeque; use std::time::SystemTime; @@ -34,6 +35,8 @@ impl Plugin for HudPlugin { #[derive(Component)] struct ChatText; #[derive(Component)] struct Reticule; #[derive(Component)] struct ToggleableHudElement; +#[derive(Component)] pub struct IsClickable; +#[derive(Component)] pub struct IsTargeted; #[derive(Resource)] struct FPSUpdateTimer(Timer); @@ -424,6 +427,7 @@ fn update( mut query_chat: Query<&mut Text, (With, Without)>, query_all_actors: Query<&actor::Actor>, settings: Res, + q_target: Query<&Position, With>, ) { // TODO only when hud is actually on if timer.0.tick(time.delta()).just_finished() || log.needs_rerendering { @@ -459,13 +463,31 @@ fn update( text.sections[13].value = format!("{vitals:.0}%"); let all_actors = query_all_actors.iter().len(); text.sections[15].value = format!("{all_actors:.0}"); - let (x, y, z) = (pos.x / 1.0e3, pos.y / 1.0e3, pos.z / 1.0e3); - text.sections[7].value = format!("{x:.0}km / {z:.0}km / {y:.0}km"); let integrity = suit.integrity * 100.0; text.sections[17].value = format!("{integrity:.0}%"); let speed = cam_v.length(); let kmh = speed * 60.0 * 60.0 / 1000.0; text.sections[19].value = format!("{speed:.0}m/s | {kmh:.0}km/h"); + + // Target display + let target: Option; + if let Ok(targetpos) = q_target.get_single() { + target = Some(targetpos.0); + } + else if q_target.is_empty() { + target = Some(DVec3::new(0.0, 0.0, 0.0)); + } + else { + target = None; + } + if let Some(target_pos) = target { + let dist = pos.0 - target_pos; + let (x, y, z) = (dist.x, dist.y, dist.z); + text.sections[7].value = format!("{x:.0}m / {z:.0}m / {y:.0}m"); + } + else { + text.sections[7].value = format!("ERROR: MULTIPLE TARGETS"); + } } } @@ -517,12 +539,17 @@ fn update( } fn handle_input( + mut commands: Commands, keyboard_input: Res>, + mouse_input: Res>, mut settings: ResMut, mut q_hud: Query<&mut Visibility, With>, mut ew_sfx: EventWriter, mut ew_togglemusic: EventWriter, mut ambient_light: ResMut, + q_objects: Query<(Entity, &Transform), (With, Without)>, + q_target: Query>, + q_camera: Query<&Transform, With>, ) { if keyboard_input.just_pressed(settings.key_togglehud) { if settings.hud_active { @@ -542,4 +569,24 @@ fn handle_input( ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::Switch)); ew_togglemusic.send(audio::ToggleMusicEvent()); } + if mouse_input.just_pressed(settings.key_selectobject) { + ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::Switch)); + if q_target.is_empty() { + if let Ok(camtrans) = q_camera.get_single() { + for (entity, trans) in &q_objects { + // Use Transform instead of Position because we're basing this + // not on the player mesh but on the camera, which doesn't have a position. + if trans.translation.distance(camtrans.translation) < 50.0 { + commands.entity(entity).insert(IsTargeted); + break; + } + } + } + } + else { + for entity in &q_target { + commands.entity(entity).remove::(); + } + } + } } diff --git a/src/settings.rs b/src/settings.rs index 911ea3b..e486684 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -13,6 +13,7 @@ pub struct Settings { pub font_size_conversations: f32, pub hud_active: bool, pub third_person: bool, + pub key_selectobject: MouseButton, pub key_togglehud: KeyCode, pub key_exit: KeyCode, pub key_restart: KeyCode, @@ -86,6 +87,7 @@ impl Default for Settings { font_size_conversations: 32.0, hud_active: false, third_person: false, + key_selectobject: MouseButton::Left, key_togglehud: KeyCode::Tab, key_exit: KeyCode::Escape, key_restart: KeyCode::F12,