move chatbox to the top left, implement fading of old messages

This commit is contained in:
yuni 2024-04-15 03:57:21 +02:00
parent 2a7714661f
commit 2d5348956e

View file

@ -9,8 +9,9 @@ use std::time::SystemTime;
pub const HUD_REFRESH_TIME: f32 = 0.1; pub const HUD_REFRESH_TIME: f32 = 0.1;
pub const FONT: &str = "fonts/Yupiter-Regular.ttf"; pub const FONT: &str = "fonts/Yupiter-Regular.ttf";
pub const LOG_MAX: usize = 20; pub const LOG_MAX: usize = 4;
pub const LOG_MAX_TIME_S: u64 = 20; pub const LOG_MAX_TIME_S: f64 = 15.0;
pub const LOG_MAX_ROWS: usize = 30;
pub const AMBIENT_LIGHT: f32 = 0.0; // Space is DARK pub const AMBIENT_LIGHT: f32 = 0.0; // Space is DARK
pub const AMBIENT_LIGHT_AR: f32 = 15.0; pub const AMBIENT_LIGHT_AR: f32 = 15.0;
//pub const REPLY_NUMBERS: [char; 10] = ['❶', '❷', '❸', '❹', '❺', '❻', '❼', '❽', '❾', '⓿']; //pub const REPLY_NUMBERS: [char; 10] = ['❶', '❷', '❸', '❹', '❺', '❻', '❼', '❽', '❾', '⓿'];
@ -83,7 +84,15 @@ struct Message {
text: String, text: String,
sender: String, sender: String,
level: LogLevel, level: LogLevel,
time: u64, time: f64,
}
impl Message {
pub fn get_freshness(&self) -> f64 {
if let Ok(epoch) = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) {
return (1.0 - (epoch.as_secs_f64() - self.time) / LOG_MAX_TIME_S).clamp(0.0, 1.0);
}
return 1.0;
}
} }
#[derive(Component)] #[derive(Component)]
@ -128,16 +137,17 @@ impl Log {
text, text,
sender, sender,
level, level,
time: epoch.as_secs(), time: epoch.as_secs_f64(),
}); });
self.needs_rerendering = true; self.needs_rerendering = true;
} }
} }
#[allow(dead_code)]
pub fn remove_old(&mut self) { pub fn remove_old(&mut self) {
if let Some(message) = self.logs.front() { if let Some(message) = self.logs.front() {
if let Ok(epoch) = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) { if let Ok(epoch) = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) {
if epoch.as_secs() - message.time > LOG_MAX_TIME_S { if epoch.as_secs_f64() - message.time > LOG_MAX_TIME_S {
self.logs.pop_front(); self.logs.pop_front();
} }
} }
@ -169,12 +179,6 @@ fn setup(
color: Color::GRAY, color: Color::GRAY,
..default() ..default()
}; };
let style_choices = TextStyle {
font: asset_server.load(FONT),
font_size: settings.font_size_hud,
color: Color::WHITE,
..default()
};
let mut bundle_fps = TextBundle::from_sections([ let mut bundle_fps = TextBundle::from_sections([
TextSection::new("", style.clone()), TextSection::new("", style.clone()),
TextSection::new("", style.clone()), TextSection::new("", style.clone()),
@ -206,23 +210,50 @@ fn setup(
// Add Chat Box // Add Chat Box
let bundle_chatbox = TextBundle::from_sections([ let bundle_chatbox = TextBundle::from_sections([
TextSection::new("Warning: System Log Uninitialized", style.clone()), TextSection::new("", style.clone()),
TextSection::new("\n", style.clone()), TextSection::new("", style.clone()),
TextSection::new("\n\n\n", style_choices), TextSection::new("", style.clone()),
TextSection::new("", style.clone()),
TextSection::new("", style.clone()),
TextSection::new("", style.clone()),
TextSection::new("", style.clone()),
TextSection::new("", style.clone()),
TextSection::new("", style.clone()),
TextSection::new("", style.clone()),
TextSection::new("", style.clone()),
TextSection::new("", style.clone()),
TextSection::new("", style.clone()),
TextSection::new("", style.clone()),
TextSection::new("", style.clone()),
TextSection::new("", style.clone()),
TextSection::new("", style.clone()),
TextSection::new("", style.clone()),
TextSection::new("", style.clone()),
TextSection::new("", style.clone()),
TextSection::new("", style.clone()),
TextSection::new("", style.clone()),
TextSection::new("", style.clone()),
TextSection::new("", style.clone()),
TextSection::new("", style.clone()),
TextSection::new("", style.clone()),
TextSection::new("", style.clone()),
TextSection::new("", style.clone()),
TextSection::new("", style.clone()),
TextSection::new("", style.clone()),
]).with_style(Style { ]).with_style(Style {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::VMin(0.0), top: Val::VMin(0.0),
left: Val::VMin(0.0), left: Val::VMin(0.0),
..default() ..default()
}).with_text_justify(JustifyText::Left); }).with_text_justify(JustifyText::Left);
commands.spawn(( commands.spawn((
NodeBundle { NodeBundle {
style: Style { style: Style {
width: Val::Percent(50.), width: Val::Percent(45.0),
align_items: AlignItems::Start, align_items: AlignItems::Start,
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::Vh(10.0), top: Val::VMin(2.0),
left: Val::Vw(25.0), left: Val::VMin(3.0),
..default() ..default()
}, },
..default() ..default()
@ -290,6 +321,7 @@ fn update_hud(
if timer.0.tick(time.delta()).just_finished() || log.needs_rerendering { if timer.0.tick(time.delta()).just_finished() || log.needs_rerendering {
let q_camera_result = q_camera.get_single(); let q_camera_result = q_camera.get_single();
let player = player.get_single(); let player = player.get_single();
let mut freshest_line: f64 = 0.0;
if player.is_ok() && q_camera_result.is_ok() { if player.is_ok() && q_camera_result.is_ok() {
let (hp, suit, gforce) = player.unwrap(); let (hp, suit, gforce) = player.unwrap();
let (pos, cam_v) = q_camera_result.unwrap(); let (pos, cam_v) = q_camera_result.unwrap();
@ -395,6 +427,49 @@ fn update_hud(
} }
if let Ok(mut chat) = query_chat.get_single_mut() { if let Ok(mut chat) = query_chat.get_single_mut() {
let mut row = 0;
let bright = Color::rgb(0.8, 0.75, 0.78);
// Chat Log and System Log
let logfilter = if settings.hud_active {
|_msg: &&Message| { true }
} else {
|msg: &&Message| { match msg.level {
LogLevel::Chat => true,
LogLevel::Warning => true,
LogLevel::Info => true,
_ => false
}}
};
let mut messages: Vec<&Message> = log.logs.iter()
.filter(logfilter)
.rev()
.take(15)
.collect();
messages.reverse();
for msg in &messages {
if msg.sender.is_empty() {
chat.sections[row].value = msg.text.clone() + "\n";
}
else {
chat.sections[row].value = format!("{}: {}\n", msg.sender, msg.text);
}
let freshness = msg.get_freshness();
let clr: f32 = (freshness.powf(1.5) as f32).clamp(0.1, 1.0);
freshest_line = freshest_line.max(freshness);
chat.sections[row].style.color = Color::rgba(0.7, 0.7, 0.7, clr);
row += 1;
}
// Highlight most recent line if in a conversation
if row > 0 && (q_choices.is_empty() || freshest_line > 0.5) {
chat.sections[row-1].style.color = bright;
}
// Add padding between chat and choices
chat.sections[row].value = "\n".to_string();
row += 1;
// Choices // Choices
let mut choices: Vec<String> = Vec::new(); let mut choices: Vec<String> = Vec::new();
let mut count = 0; let mut count = 0;
@ -414,36 +489,25 @@ fn update_hud(
choices.push(" ".to_string()); choices.push(" ".to_string());
} }
} }
chat.sections[2].value = choices.join("\n"); for choice in choices {
chat.sections[row].value = choice + "\n";
chat.sections[row].style.color = bright;
row += 1;
}
// Chat Log and System Log // Blank the remaining rows
let logfilter = if settings.hud_active { while row < LOG_MAX_ROWS {
|_msg: &&Message| { true } chat.sections[row].value = "".to_string();
} else { row += 1;
|msg: &&Message| { match msg.level { }
LogLevel::Chat => true,
LogLevel::Warning => true,
LogLevel::Info => true,
_ => false
}}
};
let mut logs_vec: Vec<String> = log.logs.iter()
.filter(logfilter)
.map(|s| if s.sender.is_empty() {
format!("{}", s.text)
} else {
format!("{}: {}", s.sender, s.text)
})
.rev()
.take(3)
.collect();
logs_vec.reverse();
chat.sections[0].value = logs_vec.join("\n");
} }
log.needs_rerendering = false; log.needs_rerendering = false;
if q_choices.is_empty() && freshest_line < 0.2 {
log.remove_old(); log.remove_old();
} }
} }
}
fn handle_input( fn handle_input(
keyboard_input: Res<ButtonInput<KeyCode>>, keyboard_input: Res<ButtonInput<KeyCode>>,