diff --git a/.forgejo/workflows/rust.yml b/.forgejo/workflows/rust.yml index 84e04f9..01a4dfd 100644 --- a/.forgejo/workflows/rust.yml +++ b/.forgejo/workflows/rust.yml @@ -59,10 +59,11 @@ jobs: target key: "${{runner.os}} Rust ${{steps.rust-toolchain.outputs.cachekey}}" - run: mkdir .ci-destdir - - run: cargo install --path . --locked --root .ci-destdir + - run: cargo install --path . --locked --root . - run: find .ci-destdir - uses: forgejo/upload-artifact@v3 with: name: Powercreep - path: - .ci-destdir/* + path: | + bin + assets diff --git a/assets/entities/human.png b/assets/entities/human.png new file mode 100644 index 0000000..cd10a96 Binary files /dev/null and b/assets/entities/human.png differ diff --git a/assets/entities/human_captured.png b/assets/entities/human_captured.png new file mode 100644 index 0000000..505bfc8 Binary files /dev/null and b/assets/entities/human_captured.png differ diff --git a/assets/entities/human_overworld.png b/assets/entities/human_overworld.png new file mode 100644 index 0000000..43609bf Binary files /dev/null and b/assets/entities/human_overworld.png differ diff --git a/build.rs b/build.rs index 15a5cd1..e718dc4 100644 --- a/build.rs +++ b/build.rs @@ -122,16 +122,20 @@ impl AssetsWriter { writeln!(file, "{indent}impl Assets {{")?; writeln!( file, - "{indent}\tpub fn load(c: &mut comfy::EngineContext<'_>) {{" + "{indent}\tpub fn load(_ctx: &mut comfy::EngineContext<'_>) {{" )?; for asset_const_name in root.assets.values() { - writeln!(file, "{indent}\t\tc.load_texture_from_bytes({asset_const_name:?}, {asset_const_name});")?; + writeln!(file, "{indent}\t\t_ctx.load_texture_from_bytes({asset_const_name:?}, {asset_const_name});")?; } for asset_const_name in root.sound_assets.values() { - writeln!(file, "{indent}\t\tcomfy::load_sound_from_bytes({asset_const_name:?}, {asset_const_name}, Default::default());")?; + writeln!(file, "{indent}\t\tcomfy::load_sound_from_bytes({asset_const_name:?}, {asset_const_name},")?; + writeln!( + file, + "{indent}\t\t\tcomfy::StaticSoundSettings::new().loop_region(..));" + )?; } for group_name in root.groups.keys() { - writeln!(file, "{indent}\t\t{group_name}::Assets::load(c);")?; + writeln!(file, "{indent}\t\t{group_name}::Assets::load(_ctx);")?; } writeln!(file, "{indent}\t}}")?; writeln!(file, "{indent}}}")?; diff --git a/src/activities/house/furniture.rs b/src/activities/house/furniture.rs index 0377185..916eecc 100644 --- a/src/activities/house/furniture.rs +++ b/src/activities/house/furniture.rs @@ -1,5 +1,5 @@ use comfy::{error, texture_id, EngineContext, HashSet, Lazy, Mutex, TextureHandle}; -use std::{fmt::Debug, fs, io, sync::Arc}; +use std::{fmt::Debug, fs, io, path::PathBuf, sync::Arc}; static ASSETS_LOADED: Lazy>>> = Lazy::new(|| Arc::new(Mutex::new(HashSet::new()))); @@ -39,10 +39,13 @@ impl FurnitureAsset { if loaded.contains(&path) { return Some(texture_id(&path)); } - let bytes = match fs::read(format!( - "{}/assets/furniture/{path}", - env!("CARGO_MANIFEST_DIR") - )) { + + let mut asset_path = PathBuf::from(format!("assets/furniture/{path}")); + if !asset_path.exists() { + asset_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(asset_path); + } + + let bytes = match fs::read(asset_path) { Ok(bytes) => bytes, Err(err) if err.kind() == io::ErrorKind::NotFound => return None, Err(err) => { diff --git a/src/activities/house/mod.rs b/src/activities/house/mod.rs index 72fe2cc..8679bba 100644 --- a/src/activities/house/mod.rs +++ b/src/activities/house/mod.rs @@ -3,45 +3,82 @@ mod grid; mod player; mod room; -use comfy::{main_camera_mut, random_i32, vec2, EngineContext}; +use crate::assets::ASSETS; +use comfy::{ + delta, main_camera_mut, play_sound_id, random_i32, stop_sound_id, vec2, + EngineContext, RandomRange as _ +}; use grid::Grid; +use indexmap::IndexSet; use log::error; use player::Player; use room::Room; +use super::Activity; + const MAX_ROOMS: i32 = 6; #[derive(Debug)] pub struct HouseState { current_room_id: usize, room_count: usize, + human_count: usize, rooms: Vec, + human_rooms: Vec, //grid: Grid, player: Player, - human_layer: bool //Human, magnetic, electric + human_layer: bool, //Human, magnetic, electric + exit_time: f32, + + /// The energy level remaining in the house. Should decrease by itself, and much + /// faster when inhabited by the ghost. + pub charge: f32, + pub max_charge: f32, + + pub sound_playing: bool } impl HouseState { pub fn generate_new_house(ctx: &mut EngineContext<'_>) -> Self { let room_count = random_i32(2, MAX_ROOMS) as usize; + let human_count = random_i32(1, room_count as i32) as usize; + + let mut possible_rooms: IndexSet = (0 .. room_count).collect(); + let mut human_rooms = Vec::new(); + for _ in 0 .. human_count { + if !possible_rooms.is_empty() { + let random_idx = usize::gen_range(0, possible_rooms.len()); + + human_rooms.push(possible_rooms.swap_remove_index(random_idx).unwrap()); + } + } let mut rooms = Vec::new(); - for _ in 0 .. room_count { - rooms.push(Room::new(ctx)); + for i in 0 .. room_count { + rooms.push(Room::new(ctx, human_rooms.contains(&i))); } let player = Player::new(rooms.first().unwrap()); + let max_charge = f32::gen_range(2_000.0, 5_000.0); HouseState { current_room_id: 0, room_count, + human_count, rooms, + human_rooms, player, - human_layer: false + human_layer: false, + exit_time: 0.0, + // TODO this should be lower depending on the time elapsed + charge: max_charge, + max_charge, + + sound_playing: false } } } -pub fn draw(state: &crate::State, _ctx: &comfy::EngineContext<'_>) { +pub fn draw(state: &crate::State, _ctx: &EngineContext<'_>) { let Some(house) = state.house() else { error!("How can I render a house when I'm not in one?!?"); return; @@ -61,13 +98,27 @@ pub fn draw(state: &crate::State, _ctx: &comfy::EngineContext<'_>) { house.player.draw(); } -pub fn update(state: &mut crate::State, ctx: &mut comfy::EngineContext<'_>) { +pub fn update(state: &mut crate::State, ctx: &mut EngineContext<'_>) { + if state.overworld.sound_playing { + stop_sound_id(ASSETS.music.galactic_rap_speedup); + state.overworld.sound_playing = false; + } + let mut camera = main_camera_mut(); camera.center = vec2(0.0, 0.0); + drop(camera); - let house = state.house_mut(ctx); + let Some(house) = state.house_mut(ctx) else { + error!("WTF I cannot update a house without a house"); + return; + }; let current_room = house.rooms.get(house.current_room_id).unwrap(); - house.player.update(¤t_room.grid); + house.player.update(¤t_room); + + if !house.sound_playing { + play_sound_id(ASSETS.music.mesmerizing_galaxy_loop); + house.sound_playing = true; + } if house.player.is_moving_to_right_room(current_room) { if house.current_room_id < (house.room_count - 1) { @@ -88,4 +139,18 @@ pub fn update(state: &mut crate::State, ctx: &mut comfy::EngineContext<'_>) { house.player.reset_on_room(current_room, true); } } + + if house.player.successfull_attack { + house.human_layer = true; + } + + if house.human_layer { + house.exit_time += delta(); + } + + if house.exit_time >= 2.0 { + state.score += 500.0; + state.ghost.overworld_pos -= vec2(0.0, 1.0); + state.activity = Activity::Overworld; + } } diff --git a/src/activities/house/player.rs b/src/activities/house/player.rs index d78cfbb..d3200be 100644 --- a/src/activities/house/player.rs +++ b/src/activities/house/player.rs @@ -2,7 +2,11 @@ use super::{ room::{Room, SCALE}, Grid }; -use comfy::{delta, draw_circle, is_key_down, vec2, KeyCode, Vec2, RED}; +use comfy::{ + delta, draw_circle, draw_sprite, is_key_down, is_key_pressed, main_camera_mut, + texture_id, vec2, KeyCode, Vec2, RED, WHITE +}; +use log::error; use std::collections::HashSet; #[derive(Debug)] @@ -13,7 +17,8 @@ pub struct Player { current_acceleration: f32, movement_time: f32, connection: usize, - next_connections: Vec + next_connections: Vec, + pub successfull_attack: bool } impl Player { @@ -28,15 +33,24 @@ impl Player { current_acceleration: 0.0, movement_time: 0.0, connection: 0, - next_connections: vec![1] + next_connections: vec![1], + successfull_attack: false } } pub fn draw(&self) { - draw_circle(self.position, 0.5, RED, 0); + //draw_circle(self.position, 0.5, RED, 0); + draw_sprite( + texture_id("ghost_house"), + self.position, + WHITE, + 5, + vec2(1.25, 1.25) + ); } - pub fn update(&mut self, grid: &Grid) { + pub fn update(&mut self, room: &Room) { + let grid = &room.grid; let allowed_movement = get_allowed_movement(self, grid); move_player(self, allowed_movement); @@ -44,6 +58,8 @@ impl Player { if !on_current_connection(self, grid) && !update_connections(self, grid) { snap_to_closest_node(self, grid); } + + attack_human_routine(self, room); } pub fn is_moving_to_right_room(&self, room: &Room) -> bool { @@ -353,3 +369,42 @@ fn snap_to_closest_node(player: &mut Player, grid: &Grid) { player.position = *closest_node; } + +fn attack_human_routine(player: &mut Player, room: &Room) { + let range = 1.0; + + if is_key_pressed(KeyCode::Space) { + //In some node range? + let mut in_range = false; + for node in &room.grid.nodes { + if in_node_range(&player.position, node, range) { + in_range = true; + break; + } + } + + if in_range { + let (human_pos, human_nodes) = room.get_human_information(); + + let mut human_attacked = false; + + if human_pos.is_some() { + for node_index in human_nodes { + if in_node_range( + &player.position, + room.grid.nodes.get(*node_index).unwrap(), + range + ) { + human_attacked = true; + } + } + } + + if human_attacked { + player.successfull_attack = true; + } else { + main_camera_mut().shake(1.0, 1.0); + } + } + } +} diff --git a/src/activities/house/room.rs b/src/activities/house/room.rs index f25ae5d..2c7c85c 100644 --- a/src/activities/house/room.rs +++ b/src/activities/house/room.rs @@ -1,8 +1,9 @@ use super::{furniture::Furniture, grid::Grid}; -use crate::game; +use crate::game::{self, ZLayer}; use comfy::{ draw_rect, draw_rect_outline, draw_sprite, error, random_i32, vec2, EngineContext, HashSet, Index, RandomRange as _, Vec2, GREEN, PURPLE, RED, WHITE + PURPLE, RED, WHITE }; use indexmap::IndexSet; @@ -30,7 +31,9 @@ pub struct Room { _room_type: RoomType, pub size: (u8, u8), //(width, height) pub grid: Grid, - furnitures: Vec + furnitures: Vec, + human_pos: Option, + human_nodes: Vec } impl RoomType { @@ -47,20 +50,60 @@ impl RoomType { } impl Room { - pub fn new(ctx: &mut EngineContext<'_>) -> Self { + pub fn new(ctx: &mut EngineContext<'_>, with_human: bool) -> Self { let room_type = RoomType::random(); let size = Self::random_size(&room_type); let furnitures = Self::random_room_furniture(&room_type, size, ctx); + let grid = Self::create_grid(size.0, size.1); + + let (human_pos, human_nodes) = if with_human { + let mut human_pos = vec2(random_i32(1, size.0 as i32) as f32 + 0.5, 1.0f32); + human_pos -= vec2(size.0 as f32 / 2.0, size.1 as f32 / 2.0); + human_pos *= SCALE; + + let node_index_left = grid + .nodes + .iter() + .enumerate() + .filter(|(_i, &node)| node.y <= size.1 as f32 / 6.0) + .filter(|(_i, &node)| node.x <= (human_pos.x - 0.5 * SCALE)) + .max_by_key(|(_i, &node)| node.x as i32) + .map(|(i, _)| i) + .unwrap(); + let node_index_right = grid + .nodes + .iter() + .enumerate() + .filter(|(_i, &node)| node.y <= size.1 as f32 / 6.0) + .filter(|(_i, &node)| node.x >= (human_pos.x + 0.5 * SCALE)) + .min_by_key(|(_i, &node)| node.x as i32) + .map(|(i, _)| i) + .unwrap(); + + ( + Some(human_pos), + (node_index_left ..= node_index_right).collect() + ) + } else { + (None, Vec::new()) + }; + Room { _room_type: room_type, size, - grid: Self::create_grid(size.0, size.1), - furnitures + grid, + furnitures, + human_pos, + human_nodes } } + pub fn get_human_information(&self) -> (Option, &Vec) { + (self.human_pos, &self.human_nodes) + } + fn random_size(room_type: &RoomType) -> (u8, u8) { //Kitchen + Living Room 5-8 //Bath + sleepingroom 4-6 @@ -443,6 +486,24 @@ impl Room { } } + if human_layer { + if let Some(human_pos) = self.human_pos { + //draw_circle(human_pos, 0.5, RED, 20); + draw_sprite( + texture_id("human_house"), + human_pos, + WHITE, + ZLayer::Human.into(), + vec2(1.0, 2.0) * SCALE + ); + } + } + + /* Debug draw + for node_index in &self.human_nodes { + draw_circle(*self.grid.nodes.get(*node_index).unwrap(), 0.5, GREEN, ZLayer::Human.into()); + }*/ + self.grid.draw(); } } diff --git a/src/activities/overworld/mod.rs b/src/activities/overworld/mod.rs index 3ad9c12..a702a08 100644 --- a/src/activities/overworld/mod.rs +++ b/src/activities/overworld/mod.rs @@ -1,14 +1,30 @@ -use crate::{activities::Activity, game::ZLayer, State}; +use crate::{ + activities::Activity, + assets::ASSETS, + game::{ZLayer, GHOST_DISCHARGE_RATE, GHOST_DISCHARGE_RATE_MOVEMENT}, + State +}; use comfy::{ - delta, draw_circle, draw_rect_outline, draw_sprite, error, info, is_key_down, - main_camera_mut, EngineContext, IVec2, KeyCode, Vec2, RED, WHITE + draw_rect_outline, draw_sprite, error, info, is_key_down, main_camera_mut, + play_sound_id, stop_sound_id, texture_id, vec2, EngineContext, IVec2, KeyCode, Vec2, + RED, WHITE }; use std::time::Instant; use worldgen::MovementCost; pub mod worldgen; -pub fn draw(state: &crate::State, _engine: &comfy::EngineContext<'_>) { +pub fn setup(_state: &State, ctx: &EngineContext<'_>) { + ctx.load_texture_from_bytes( + "human_overworld", + include_bytes!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/assets/entities/human_overworld.png" + )) + ); +} + +pub fn draw(state: &State, _ctx: &EngineContext<'_>) { for (coords, tile) in state.overworld.iter_tiles() { for (i, texture) in tile.textures().iter().rev().enumerate() { let i = i as i32; @@ -24,12 +40,32 @@ pub fn draw(state: &crate::State, _engine: &comfy::EngineContext<'_>) { } } } - draw_circle(state.ghost.overworld_pos, 0.5, RED, ZLayer::Ghost.into()); + + let mut ghost_pos = state.ghost.overworld_pos; + ghost_pos.y += 0.5; + draw_sprite( + texture_id("human_overworld"), + ghost_pos, + WHITE, + ZLayer::Ghost.into(), + vec2(1.0, 1.25) + ); } -fn update_move_player(state: &mut State, _ctx: &mut EngineContext<'_>) { +fn update_move_player(state: &mut State, ctx: &mut EngineContext<'_>) { let now = Instant::now(); + if !state.overworld.sound_playing { + if let Some(house) = state.house_mut(ctx) { + if house.sound_playing { + stop_sound_id(ASSETS.music.mesmerizing_galaxy_loop); + house.sound_playing = false; + } + } + play_sound_id(ASSETS.music.galactic_rap_speedup); + state.overworld.sound_playing = true; + } + // Are there any pending position updates? If so, we ignore all user input and execute // the pending updates. if state.ghost.overworld_movement_pending != Vec2::ZERO { @@ -177,9 +213,9 @@ pub fn update(state: &mut State, ctx: &mut EngineContext<'_>) { // energie lost { let ghost = &mut state.ghost; - ghost.charge -= 70.0 * ctx.delta; + ghost.charge -= GHOST_DISCHARGE_RATE * ctx.delta; if ghost.overworld_movement_pending != Vec2::ZERO { - ghost.charge -= 70.0 * ctx.delta; + ghost.charge -= GHOST_DISCHARGE_RATE_MOVEMENT * ctx.delta; } } diff --git a/src/activities/overworld/worldgen.rs b/src/activities/overworld/worldgen.rs index 83e9067..4739c4e 100644 --- a/src/activities/overworld/worldgen.rs +++ b/src/activities/overworld/worldgen.rs @@ -422,7 +422,9 @@ impl Chunk { #[derive(Debug, Default)] pub struct Overworld { - chunks: HashMap + chunks: HashMap, + + pub sound_playing: bool } fn world_to_chunk_and_local_coords(world_coords: IVec2) -> (IVec2, UVec2) { diff --git a/src/game.rs b/src/game.rs index 5c481b3..6352858 100644 --- a/src/game.rs +++ b/src/game.rs @@ -75,8 +75,7 @@ pub enum ZLayer { MapMax = -1, Human = 0, Ghost = 1, - UI = 100, - GameOver = 1000 + UI = 100 } impl From for i32 { @@ -102,23 +101,76 @@ impl Add for ZLayer { } } -pub fn setup(_state: &mut State, ctx: &mut EngineContext<'_>) { +pub fn setup(state: &mut State, ctx: &mut EngineContext<'_>) { Assets::load(ctx); + overworld::setup(state, ctx); //house::setup(state, ctx); + + ctx.load_texture_from_bytes( + "ghost_house", + include_bytes!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/assets/entities/ghost.png" + )) + ); + + ctx.load_texture_from_bytes( + "human_house", + include_bytes!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/assets/entities/human_captured.png" + )) + ); } -pub fn update(state: &mut State, engine: &mut EngineContext<'_>) { - if state.ghost.charge > 0.0 { - state.score += engine.delta * 10.0; +/// The amount of energy a ghost consumes idle. +pub const GHOST_DISCHARGE_RATE: f32 = 70.0; +/// The amount of energy additionally consumed by a moving ghost. +pub const GHOST_DISCHARGE_RATE_MOVEMENT: f32 = 70.0; +/// The amount of energy a house consumes idle. +pub const HOUSE_DISCHARGE_RATE: f32 = 30.0; +/// The amount of energy a ghost can charge when inside a house. +pub const GHOST_CHARGE_RATE: f32 = 200.0; + +pub fn update(state: &mut State, ctx: &mut EngineContext<'_>) { + // Update the score. It's based on time. + state.score += ctx.delta * 10.0; + + // Update the currently active activity. + match state.activity { + Activity::House(_) => house::update(state, ctx), + Activity::Overworld => overworld::update(state, ctx) + } + + // We update the charge of houses here - the charge will always decrease, even if the + // house is not the current activity. + for (house_pos, house) in &mut state.houses { + house.charge -= ctx.delta * HOUSE_DISCHARGE_RATE; + match state.activity { - Activity::House(_) => house::update(state, engine), - Activity::Overworld => overworld::update(state, engine) + Activity::House(pos) if *house_pos == pos => { + // The ghost is currently inside the house. Increase its discarge rate. + house.charge -= ctx.delta * GHOST_DISCHARGE_RATE; + if house.charge < 0.0 { + state.ghost.charge += house.charge; + house.charge = 0.0; + } + + // And possibly also charge the ghost when inside a house. + if state.ghost.charge < state.ghost.max_charge { + let charge_transfer = (ctx.delta * GHOST_CHARGE_RATE) + .min(state.ghost.max_charge - state.ghost.charge) + .min(house.charge); + state.ghost.charge += charge_transfer; + house.charge -= charge_transfer; + } + }, + _ => {} } } - { - crate::game_over::update(state, engine); - } + + // Make sure the ghost's charge never drops below 0. state.ghost.charge = state.ghost.charge.max(0.0); } @@ -128,7 +180,4 @@ pub fn draw(state: &State, engine: &EngineContext<'_>) { Activity::Overworld => overworld::draw(state, engine) } crate::ui::draw(state, engine); - if state.ghost.charge <= 0.0 { - crate::game_over::draw(state, engine); - } } diff --git a/src/main.rs b/src/main.rs index a5b9b6d..ec4ea4e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -59,10 +59,12 @@ impl State { self.houses.get(&self.get_house_pos()?) } - fn house_mut(&mut self, ctx: &mut EngineContext<'_>) -> &mut HouseState { - self.houses - .entry(self.get_house_pos().unwrap()) - .or_insert_with(|| HouseState::generate_new_house(ctx)) + fn house_mut(&mut self, ctx: &mut EngineContext<'_>) -> Option<&mut HouseState> { + Some( + self.houses + .entry(self.get_house_pos()?) + .or_insert_with(|| HouseState::generate_new_house(ctx)) + ) } } diff --git a/src/ui.rs b/src/ui.rs index 1f31ada..4a22853 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1,41 +1,61 @@ use crate::{game::ZLayer, State}; use comfy::{ draw_rect, draw_rect_outline, egui, screen_height, screen_to_world, screen_width, - EngineContext, Vec2, BLACK, BLUE, RED, WHITE + vec2, Color, EngineContext, Vec2, BLACK, BLUE, PURPLE, RED, WHITE }; use egui::widget_text::RichText; -pub fn draw_batterie(state: &State, _engine: &EngineContext<'_>) { - // seperate fill state into smaller section for better readability - let section_count = 5; - let mut start_positon = screen_to_world(Vec2::new(screen_width(), screen_height())); +// seperate fill state into smaller section for better readability +const BATTERY_SECTION_COUNT: u8 = 5; +const BATTERY_SECTION_WIDTH: f32 = 1.0; +const BATTERY_SECTION_HEIGHT: f32 = 0.5; + +fn draw_battery(mut start_position: Vec2, charge: f32, max_charge: f32, color: Color) { // section size in world codinates - let section_size = Vec2::new(0.5, 0.25); - start_positon.x -= 0.5 * section_size.x + 0.5 * section_size.y; - start_positon.y += 0.5 * section_size.y + 0.5 * section_size.y; + let section_size = vec2(BATTERY_SECTION_WIDTH, BATTERY_SECTION_HEIGHT); + start_position.x -= 0.5 * section_size.x + 0.5 * section_size.y; + start_position.y += 0.5 * section_size.y + 0.5 * section_size.y; // draw fill level { - let ghost = &state.ghost; - let percent = ghost.charge / ghost.max_charge; + let percent = charge / max_charge; let mut size = section_size; - size.y = section_size.y * section_count as f32; - let mut position = start_positon; + size.y = section_size.y * BATTERY_SECTION_COUNT as f32; + let mut position = start_position; position.y += 0.5 * -section_size.y + 0.5 * size.y; draw_rect(position, size, BLACK, ZLayer::UI.into()); size.y *= percent; - let mut position = start_positon; + let mut position = start_position; position.y += 0.5 * -section_size.y + 0.5 * size.y; draw_rect(position, size, BLUE, ZLayer::UI + 1); } // draw sections - for i in 0 .. section_count { - let mut position = start_positon; + for i in 0 .. BATTERY_SECTION_COUNT { + let mut position = start_position; position.y += i as f32 * section_size.y; - draw_rect_outline(position, section_size, 0.1, RED, ZLayer::UI + 2); + draw_rect_outline(position, section_size, 0.1, color, ZLayer::UI + 2); } } -pub fn draw_highscore(state: &State, _engine: &EngineContext<'_>) { +pub fn draw_ghost_battery(state: &State) { + let start_position = screen_to_world(Vec2::new(screen_width(), screen_height())); + draw_battery( + start_position, + state.ghost.charge, + state.ghost.max_charge, + RED + ); +} + +pub fn draw_house_battery(state: &State) { + let Some(house) = state.house() else { + return; + }; + let mut start_position = screen_to_world(Vec2::new(screen_width(), screen_height())); + start_position.x -= 2.0 * BATTERY_SECTION_WIDTH; + draw_battery(start_position, house.charge, house.max_charge, PURPLE) +} + +pub fn draw_highscore(state: &State) { egui::Area::new("score") .anchor(egui::Align2::RIGHT_TOP, egui::vec2(0.0, 0.0)) .show(egui(), |ui| { @@ -49,7 +69,8 @@ pub fn draw_highscore(state: &State, _engine: &EngineContext<'_>) { }); } -pub fn draw(state: &State, engine: &EngineContext<'_>) { - draw_batterie(state, engine); - draw_highscore(state, engine); +pub fn draw(state: &State, _ctx: &EngineContext<'_>) { + draw_ghost_battery(state); + draw_house_battery(state); + draw_highscore(state); }