implement targeting based on player orientation
This commit is contained in:
parent
a37ba60eaf
commit
1906366463
|
@ -44,6 +44,7 @@ pub struct VehicleEnterExitEvent {
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct Actor {
|
pub struct Actor {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
|
pub name: Option<String>,
|
||||||
pub m: f32, // mass
|
pub m: f32, // mass
|
||||||
pub inside_entity: u32,
|
pub inside_entity: u32,
|
||||||
pub camdistance: f32,
|
pub camdistance: f32,
|
||||||
|
@ -52,6 +53,7 @@ impl Default for Actor {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
id: "".to_string(),
|
id: "".to_string(),
|
||||||
|
name: None,
|
||||||
m: 100.0,
|
m: 100.0,
|
||||||
inside_entity: NO_RIDE,
|
inside_entity: NO_RIDE,
|
||||||
camdistance: 15.0,
|
camdistance: 15.0,
|
||||||
|
|
|
@ -31,7 +31,7 @@ struct ParserState {
|
||||||
class: DefClass,
|
class: DefClass,
|
||||||
|
|
||||||
// Generic fields
|
// Generic fields
|
||||||
name: String,
|
name: Option<String>,
|
||||||
chat: String,
|
chat: String,
|
||||||
|
|
||||||
// Actor fields
|
// Actor fields
|
||||||
|
@ -86,7 +86,7 @@ impl Default for ParserState {
|
||||||
let default_engine = actor::Engine::default();
|
let default_engine = actor::Engine::default();
|
||||||
Self {
|
Self {
|
||||||
class: DefClass::None,
|
class: DefClass::None,
|
||||||
name: "NONAME".to_string(),
|
name: None,
|
||||||
chat: "".to_string(),
|
chat: "".to_string(),
|
||||||
|
|
||||||
id: "".to_string(),
|
id: "".to_string(),
|
||||||
|
@ -148,7 +148,7 @@ impl ParserState {
|
||||||
fn as_chatbranch(&self) -> chat::ChatBranch {
|
fn as_chatbranch(&self) -> chat::ChatBranch {
|
||||||
return chat::ChatBranch {
|
return chat::ChatBranch {
|
||||||
id: self.chat.clone(),
|
id: self.chat.clone(),
|
||||||
name: self.name.clone(),
|
name: self.name.clone().unwrap_or("".to_string()),
|
||||||
label: self.label.clone(),
|
label: self.label.clone(),
|
||||||
delay: self.delay.clone(),
|
delay: self.delay.clone(),
|
||||||
sound: if self.is_choice { "".to_string() } else { "chat".to_string() },
|
sound: if self.is_choice { "".to_string() } else { "chat".to_string() },
|
||||||
|
@ -474,7 +474,7 @@ pub fn load_defs(
|
||||||
}
|
}
|
||||||
["name", name] => {
|
["name", name] => {
|
||||||
debug!("Registering name: {}", name);
|
debug!("Registering name: {}", name);
|
||||||
state.name = name.to_string();
|
state.name = Some(name.to_string());
|
||||||
}
|
}
|
||||||
["msg", sleep, text] => {
|
["msg", sleep, text] => {
|
||||||
debug!("Registering message (sleep={}): {}", sleep, text);
|
debug!("Registering message (sleep={}): {}", sleep, text);
|
||||||
|
@ -584,6 +584,7 @@ fn spawn_entities(
|
||||||
let mut actor = commands.spawn_empty();
|
let mut actor = commands.spawn_empty();
|
||||||
actor.insert(actor::Actor {
|
actor.insert(actor::Actor {
|
||||||
id: state.id.clone(),
|
id: state.id.clone(),
|
||||||
|
name: state.name.clone(),
|
||||||
camdistance: state.camdistance,
|
camdistance: state.camdistance,
|
||||||
..default()
|
..default()
|
||||||
});
|
});
|
||||||
|
|
16
src/defs.txt
16
src/defs.txt
|
@ -1,5 +1,6 @@
|
||||||
actor 0 0 0 jupiter
|
actor 0 0 0 jupiter
|
||||||
id jupiter
|
id jupiter
|
||||||
|
name Jupiter
|
||||||
radius 71492e3
|
radius 71492e3
|
||||||
sphere yes
|
sphere yes
|
||||||
physics off
|
physics off
|
||||||
|
@ -36,6 +37,7 @@ actor 10 -30 20 MeteorAceGT
|
||||||
clickable no
|
clickable no
|
||||||
|
|
||||||
actor 0 0 0 io
|
actor 0 0 0 io
|
||||||
|
name Io
|
||||||
relativeto jupiter
|
relativeto jupiter
|
||||||
orbit 421700e3 0.65
|
orbit 421700e3 0.65
|
||||||
radius 1822e3
|
radius 1822e3
|
||||||
|
@ -46,6 +48,7 @@ actor 0 0 0 io
|
||||||
physics off
|
physics off
|
||||||
|
|
||||||
actor 0 0 0 europa
|
actor 0 0 0 europa
|
||||||
|
name Europa
|
||||||
relativeto jupiter
|
relativeto jupiter
|
||||||
orbit 670900e3 0.35
|
orbit 670900e3 0.35
|
||||||
radius 1561e3
|
radius 1561e3
|
||||||
|
@ -56,6 +59,7 @@ actor 0 0 0 europa
|
||||||
physics off
|
physics off
|
||||||
|
|
||||||
actor 0 0 0 ganymede
|
actor 0 0 0 ganymede
|
||||||
|
name Ganymede
|
||||||
relativeto jupiter
|
relativeto jupiter
|
||||||
orbit 1070400e3 0.93
|
orbit 1070400e3 0.93
|
||||||
radius 2634e3
|
radius 2634e3
|
||||||
|
@ -66,6 +70,7 @@ actor 0 0 0 ganymede
|
||||||
physics off
|
physics off
|
||||||
|
|
||||||
actor 0 0 0 callisto
|
actor 0 0 0 callisto
|
||||||
|
name Callisto
|
||||||
relativeto jupiter
|
relativeto jupiter
|
||||||
orbit 1882700e3 0.45
|
orbit 1882700e3 0.45
|
||||||
radius 2410e3
|
radius 2410e3
|
||||||
|
@ -76,6 +81,7 @@ actor 0 0 0 callisto
|
||||||
physics off
|
physics off
|
||||||
|
|
||||||
actor 0 0 0 moonlet
|
actor 0 0 0 moonlet
|
||||||
|
name Thebe
|
||||||
relativeto jupiter
|
relativeto jupiter
|
||||||
id thebe
|
id thebe
|
||||||
orbit 221900e3 0.66
|
orbit 221900e3 0.66
|
||||||
|
@ -84,12 +90,14 @@ actor 0 0 0 moonlet
|
||||||
angularmomentum 0 0.25 0
|
angularmomentum 0 0.25 0
|
||||||
|
|
||||||
actor 3000 0 0 moonlet
|
actor 3000 0 0 moonlet
|
||||||
|
name Moonlet
|
||||||
relativeto player
|
relativeto player
|
||||||
scale 500
|
scale 500
|
||||||
mass 10000000
|
mass 10000000
|
||||||
angularmomentum 0 0.15 0
|
angularmomentum 0 0.15 0
|
||||||
|
|
||||||
actor -200 -110 1000 satellite
|
actor -200 -110 1000 satellite
|
||||||
|
name "Communications Satellite"
|
||||||
relativeto player
|
relativeto player
|
||||||
scale 40
|
scale 40
|
||||||
wants maxrotation 0
|
wants maxrotation 0
|
||||||
|
@ -101,6 +109,7 @@ actor -200 -110 1000 satellite
|
||||||
mass 10
|
mass 10
|
||||||
|
|
||||||
actor 1000 20 300 monolith
|
actor 1000 20 300 monolith
|
||||||
|
name "Mysterious Monolith 1"
|
||||||
relativeto player
|
relativeto player
|
||||||
scale 2
|
scale 2
|
||||||
mass 1000
|
mass 1000
|
||||||
|
@ -110,6 +119,7 @@ actor 1000 20 300 monolith
|
||||||
thrust 0 0 0 30 1
|
thrust 0 0 0 30 1
|
||||||
|
|
||||||
actor 10000 2000 -3500 monolith
|
actor 10000 2000 -3500 monolith
|
||||||
|
name "Mysterious Monolith 2"
|
||||||
relativeto player
|
relativeto player
|
||||||
scale 2
|
scale 2
|
||||||
mass 1000
|
mass 1000
|
||||||
|
@ -119,6 +129,7 @@ actor 10000 2000 -3500 monolith
|
||||||
thrust 0 0 0 30 1
|
thrust 0 0 0 30 1
|
||||||
|
|
||||||
actor -8000 -1000 -100 monolith
|
actor -8000 -1000 -100 monolith
|
||||||
|
name "Mysterious Monolith 3"
|
||||||
relativeto player
|
relativeto player
|
||||||
scale 2
|
scale 2
|
||||||
mass 1000
|
mass 1000
|
||||||
|
@ -128,6 +139,7 @@ actor -8000 -1000 -100 monolith
|
||||||
thrust 0 0 0 30 1
|
thrust 0 0 0 30 1
|
||||||
|
|
||||||
actor -3300 10 0 pizzeria
|
actor -3300 10 0 pizzeria
|
||||||
|
name "Pizzeria Asteroid"
|
||||||
relativeto player
|
relativeto player
|
||||||
id pizzeria
|
id pizzeria
|
||||||
scale 40
|
scale 40
|
||||||
|
@ -144,17 +156,21 @@ actor -3300 10 0 pizzeria
|
||||||
camdistance 50
|
camdistance 50
|
||||||
mass 3000
|
mass 3000
|
||||||
angularmomentum 0 0 0.2
|
angularmomentum 0 0 0.2
|
||||||
|
clickable no
|
||||||
actor -100 63 -13 pizzasign
|
actor -100 63 -13 pizzasign
|
||||||
|
name "Pizzeria Sign"
|
||||||
relativeto pizzeria
|
relativeto pizzeria
|
||||||
scale 20
|
scale 20
|
||||||
mass 200
|
mass 200
|
||||||
rotationy 0.45
|
rotationy 0.45
|
||||||
angularmomentum 0 0 0
|
angularmomentum 0 0 0
|
||||||
actor -16 -10 0 lightorb
|
actor -16 -10 0 lightorb
|
||||||
|
name "Light Orb"
|
||||||
relativeto pizzeria
|
relativeto pizzeria
|
||||||
scale 0.5
|
scale 0.5
|
||||||
light FF8F4A 1000000
|
light FF8F4A 1000000
|
||||||
actor -14 -3 -2 lightorb
|
actor -14 -3 -2 lightorb
|
||||||
|
name "Light Orb"
|
||||||
relativeto pizzeria
|
relativeto pizzeria
|
||||||
scale 0.5
|
scale 0.5
|
||||||
light FF8F4A 1000000
|
light FF8F4A 1000000
|
||||||
|
|
60
src/hud.rs
60
src/hud.rs
|
@ -306,6 +306,24 @@ fn setup(
|
||||||
..default()
|
..default()
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
TextSection::new(
|
||||||
|
"\nTarget: ",
|
||||||
|
TextStyle {
|
||||||
|
font: asset_server.load(FONT),
|
||||||
|
font_size: settings.font_size_hud,
|
||||||
|
color: Color::GRAY,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
),
|
||||||
|
TextSection::new(
|
||||||
|
"",
|
||||||
|
TextStyle {
|
||||||
|
font: asset_server.load(FONT),
|
||||||
|
font_size: settings.font_size_hud,
|
||||||
|
color: Color::GRAY,
|
||||||
|
..default()
|
||||||
|
}
|
||||||
|
),
|
||||||
TextSection::new(
|
TextSection::new(
|
||||||
"\n☢ HAZARD\n\n",
|
"\n☢ HAZARD\n\n",
|
||||||
TextStyle {
|
TextStyle {
|
||||||
|
@ -427,7 +445,7 @@ fn update(
|
||||||
mut query_chat: Query<&mut Text, (With<ChatText>, Without<GaugesText>)>,
|
mut query_chat: Query<&mut Text, (With<ChatText>, Without<GaugesText>)>,
|
||||||
query_all_actors: Query<&actor::Actor>,
|
query_all_actors: Query<&actor::Actor>,
|
||||||
settings: Res<settings::Settings>,
|
settings: Res<settings::Settings>,
|
||||||
q_target: Query<&Position, With<IsTargeted>>,
|
q_target: Query<(&Position, &actor::Actor), With<IsTargeted>>,
|
||||||
) {
|
) {
|
||||||
// TODO only when hud is actually on
|
// TODO only when hud is actually on
|
||||||
if timer.0.tick(time.delta()).just_finished() || log.needs_rerendering {
|
if timer.0.tick(time.delta()).just_finished() || log.needs_rerendering {
|
||||||
|
@ -471,7 +489,7 @@ fn update(
|
||||||
|
|
||||||
// Target display
|
// Target display
|
||||||
let target: Option<DVec3>;
|
let target: Option<DVec3>;
|
||||||
if let Ok(targetpos) = q_target.get_single() {
|
if let Ok((targetpos, actr)) = q_target.get_single() {
|
||||||
target = Some(targetpos.0);
|
target = Some(targetpos.0);
|
||||||
}
|
}
|
||||||
else if q_target.is_empty() {
|
else if q_target.is_empty() {
|
||||||
|
@ -488,6 +506,16 @@ fn update(
|
||||||
else {
|
else {
|
||||||
text.sections[7].value = format!("ERROR: MULTIPLE TARGETS");
|
text.sections[7].value = format!("ERROR: MULTIPLE TARGETS");
|
||||||
}
|
}
|
||||||
|
if q_target.is_empty() {
|
||||||
|
text.sections[21].value = "Jupiter".to_string();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let targets: Vec<String> = q_target
|
||||||
|
.iter()
|
||||||
|
.map(|(_pos, act)| act.name.clone().unwrap_or("<unnamed>".to_string()))
|
||||||
|
.collect();
|
||||||
|
text.sections[21].value = targets.join(", ");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -570,18 +598,38 @@ fn handle_input(
|
||||||
ew_togglemusic.send(audio::ToggleMusicEvent());
|
ew_togglemusic.send(audio::ToggleMusicEvent());
|
||||||
}
|
}
|
||||||
if mouse_input.just_pressed(settings.key_selectobject) {
|
if mouse_input.just_pressed(settings.key_selectobject) {
|
||||||
ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::Switch));
|
//ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::Switch));
|
||||||
if q_target.is_empty() {
|
if q_target.is_empty() {
|
||||||
if let Ok(camtrans) = q_camera.get_single() {
|
if let Ok(camtrans) = q_camera.get_single() {
|
||||||
|
let mut closest_entity: Option<Entity> = None;
|
||||||
|
let mut closest_distance: f32 = f32::MAX;
|
||||||
|
let target_vector = (camtrans.rotation * Vec3::new(0.0, 0.0, -1.0))
|
||||||
|
.normalize_or_zero();
|
||||||
|
let field_of_view = 20.0f32.to_radians();
|
||||||
|
let max_angle = field_of_view / 2.0;
|
||||||
|
let max_cosine_of_angle = max_angle.cos();
|
||||||
|
//let maximum_cosine_of_angle = (field_of_view / 2.0).cos();
|
||||||
for (entity, trans) in &q_objects {
|
for (entity, trans) in &q_objects {
|
||||||
// Use Transform instead of Position because we're basing this
|
// 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.
|
// not on the player mesh but on the camera, which doesn't have a position.
|
||||||
if trans.translation.distance(camtrans.translation) < 50.0 {
|
let pos_vector = (trans.translation - camtrans.translation)
|
||||||
commands.entity(entity).insert(IsTargeted);
|
.normalize_or_zero();
|
||||||
break;
|
let cosine_of_angle = target_vector.dot(pos_vector);
|
||||||
|
let angle = cosine_of_angle.acos();
|
||||||
|
if angle <= max_angle {
|
||||||
|
// It's in the field of view!
|
||||||
|
//commands.entity(entity).insert(IsTargeted);
|
||||||
|
let distance = trans.translation.distance(camtrans.translation);
|
||||||
|
if distance < closest_distance {
|
||||||
|
closest_distance = distance;
|
||||||
|
closest_entity = Some(entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let Some(entity) = closest_entity {
|
||||||
|
commands.entity(entity).insert(IsTargeted);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for entity in &q_target {
|
for entity in &q_target {
|
||||||
|
|
Loading…
Reference in a new issue