1
0
Fork 0
mirror of https://github.com/doukutsu-rs/doukutsu-rs synced 2025-04-01 23:34:54 +00:00
doukutsu-rs/src/components/hud.rs

235 lines
7.6 KiB
Rust

use ggez::{Context, GameResult};
use crate::common::Rect;
use crate::components::draw_common::{Alignment, draw_number};
use crate::entity::GameEntity;
use crate::frame::Frame;
use crate::inventory::Inventory;
use crate::player::Player;
use crate::shared_game_state::SharedGameState;
pub struct HUD {
pub alignment: Alignment,
pub weapon_x_pos: usize,
pub visible: bool,
pub has_player2: bool,
ammo: u16,
max_ammo: u16,
xp: u16,
max_xp: u16,
max_level: bool,
life: u16,
max_life: u16,
life_bar: u16,
life_bar_counter: u16,
air: u16,
air_counter: u16,
current_level: usize,
weapon_count: usize,
current_weapon: isize,
weapon_types: [u8; 16],
}
impl HUD {
pub fn new(alignment: Alignment) -> HUD {
HUD {
alignment,
weapon_x_pos: 16,
visible: false,
has_player2: false,
ammo: 0,
max_ammo: 0,
xp: 0,
max_xp: 0,
max_level: false,
life: 0,
max_life: 0,
life_bar: 0,
life_bar_counter: 0,
air: 0,
air_counter: 0,
current_level: 0,
weapon_count: 0,
current_weapon: 0,
weapon_types: [0; 16],
}
}
}
impl GameEntity<(&Player, &Inventory)> for HUD {
fn tick(&mut self, state: &mut SharedGameState, (player, inventory): (&Player, &Inventory)) -> GameResult {
let (ammo, max_ammo) = inventory.get_current_ammo();
let (xp, max_xp, max_level) = inventory.get_current_max_exp(&state.constants);
self.ammo = ammo;
self.max_ammo = max_ammo;
self.xp = xp;
self.max_xp = max_xp;
self.max_level = max_level;
self.life = player.life;
self.max_life = player.max_life;
self.air = player.air;
self.air_counter = player.air_counter;
self.weapon_count = inventory.get_weapon_count();
self.current_weapon = inventory.get_current_weapon_idx() as isize;
self.current_level = inventory.get_current_level() as usize;
for (a, slot) in self.weapon_types.iter_mut().enumerate() {
*slot = if let Some(weapon) = inventory.get_weapon(a) {
weapon.wtype as u8
} else {
0
};
}
// update health bar
if self.life_bar < self.life as u16 {
self.life_bar = self.life as u16;
}
if self.life_bar > self.life as u16 {
self.life_bar_counter += 1;
if self.life_bar_counter > 30 {
self.life_bar -= 1;
}
} else {
self.life_bar_counter = 0;
}
if self.weapon_x_pos > 16 {
self.weapon_x_pos -= 2;
} else if self.weapon_x_pos < 16 {
self.weapon_x_pos += 2;
}
Ok(())
}
fn draw(&self, state: &mut SharedGameState, ctx: &mut Context, frame: &Frame) -> GameResult {
if !self.visible {
return Ok(());
}
// none
let weap_x = self.weapon_x_pos as f32;
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "TextBox")?;
let (bar_offset, num_offset, weapon_offset) = match self.alignment {
Alignment::Left => (0.0, 0.0, 0.0),
Alignment::Right => (state.canvas_size.0 - 112.0, state.canvas_size.0 - 48.0, state.canvas_size.0 - 104.0),
};
let air_offset = if self.has_player2 {
50.0 * match self.alignment {
Alignment::Left => -1.0,
Alignment::Right => 1.0,
}
} else {
0.0
};
if self.max_ammo == 0 {
batch.add_rect(bar_offset + weap_x + 48.0, 16.0,
&Rect::new_size(80, 48, 16, 8));
batch.add_rect(bar_offset + weap_x + 48.0, 24.0,
&Rect::new_size(80, 48, 16, 8));
}
// per
batch.add_rect(bar_offset + weap_x + 32.0, 24.0,
&Rect::new_size(72, 48, 8, 8));
// lv
batch.add_rect(num_offset + weap_x, 32.0,
&Rect::new_size(80, 80, 16, 8));
// xp box
batch.add_rect(bar_offset + weap_x + 24.0, 32.0,
&Rect::new_size(0, 72, 40, 8));
if self.max_level {
batch.add_rect(bar_offset + weap_x + 24.0, 32.0,
&Rect::new_size(40, 72, 40, 8));
} else if self.max_xp > 0 {
// xp bar
let bar_width = (self.xp as f32 / self.max_xp as f32 * 40.0) as u16;
batch.add_rect(bar_offset + weap_x + 24.0, 32.0,
&Rect::new_size(0, 80, bar_width, 8));
}
if self.max_life != 0 {
// heart/hp number box
batch.add_rect(num_offset + 16.0, 40.0,
&Rect::new_size(0, 40, 24, 8));
// life box
batch.add_rect(bar_offset + 40.0, 40.0,
&Rect::new_size(24, 40, 40, 8));
// yellow bar
batch.add_rect(bar_offset + 40.0, 40.0,
&Rect::new_size(0, 32, (self.life_bar * 40) / self.max_life, 8));
// life
batch.add_rect(bar_offset + 40.0, 40.0,
&Rect::new_size(0, 24, (self.life * 40) / self.max_life, 8));
}
if self.air_counter > 0 {
let rect = if self.air % 30 > 10 {
Rect::new_size(112, 72, 32, 8)
} else {
Rect::new_size(112, 80, 32, 8)
};
batch.add_rect((state.canvas_size.0 / 2.0).floor() - 40.0 + air_offset,
(state.canvas_size.1 / 2.0).floor(), &rect);
}
batch.draw(ctx)?;
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "ArmsImage")?;
if self.weapon_count != 0 {
let mut rect = Rect::new(0, 0, 0, 16);
for a in 0..self.weapon_count {
let mut pos_x = ((a as isize - self.current_weapon) as f32 * 16.0) + weap_x;
if pos_x < 8.0 {
pos_x += 48.0 + self.weapon_count as f32 * 16.0;
} else if pos_x >= 24.0 {
pos_x += 48.0;
}
if pos_x >= 72.0 + ((self.weapon_count - 1) as f32 * 16.0) {
pos_x -= 48.0 + self.weapon_count as f32 * 16.0;
} else if pos_x < 72.0 && pos_x >= 24.0 {
pos_x -= 48.0;
}
let wtype = unsafe { *self.weapon_types.get_unchecked(a) };
if wtype != 0 {
rect.left = wtype as u16 * 16;
rect.right = rect.left + 16;
batch.add_rect(pos_x + weapon_offset, 16.0, &rect);
}
}
}
batch.draw(ctx)?;
if self.air_counter > 0 && self.air_counter % 6 < 4 {
draw_number((state.canvas_size.0 / 2.0).floor() + 8.0 + air_offset,
(state.canvas_size.1 / 2.0).floor(),
(self.air / 10) as usize, Alignment::Left, state, ctx)?;
}
if self.max_ammo != 0 {
draw_number(num_offset + weap_x + 64.0, 16.0, self.ammo as usize, Alignment::Right, state, ctx)?;
draw_number(num_offset + weap_x + 64.0, 24.0, self.max_ammo as usize, Alignment::Right, state, ctx)?;
}
draw_number(num_offset + weap_x + 24.0, 32.0, self.current_level, Alignment::Right, state, ctx)?;
draw_number(num_offset + 40.0, 40.0, self.life_bar as usize, Alignment::Right, state, ctx)?;
Ok(())
}
}