From 723c2fe0982f80438b75098fa79d1933efc13d0a Mon Sep 17 00:00:00 2001 From: salmonik Date: Sat, 11 Jul 2026 15:30:04 +0200 Subject: add enemy AI: chase, patrol, attack, and movement animation --- src/renderer.rs | 117 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 69 insertions(+), 48 deletions(-) (limited to 'src/renderer.rs') diff --git a/src/renderer.rs b/src/renderer.rs index aa87b54..885e5de 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -74,6 +74,18 @@ pub struct Renderer { floor_dist_lut: Vec, } +// ---- entity sprites --------------------------------------------------- + +/// Screen-space info for an entity sprite to render. +struct Sprite { + sx: isize, + sy: isize, + scale: f64, + ch: char, + color: u32, + cam_z: f64, +} + impl Renderer { pub fn new(screen_w: usize, screen_h: usize) -> Self { let half_h = screen_h as f64 / 2.0; @@ -306,19 +318,9 @@ impl Renderer { ) { let mw = game.maze.width(); let mh = game.maze.height(); - - // Collect visible entities with their screen info. - struct Sprite { - sx: isize, - sy: isize, - scale: f64, - ch: char, - color: u32, - cam_z: f64, - } - let mut sprites: Vec = Vec::new(); + // Static entities on the grid. for y in 0..mh { for x in 0..mw { let entity = match game.maze.entity_at(x, y) { @@ -329,46 +331,15 @@ impl Renderer { let ex = x as f64 + 0.5; let ey = y as f64 + 0.5; - let dx = ex - game.player.x; - let dy = ey - game.player.y; - - let fx = game.player.angle.cos(); - let fy = game.player.angle.sin(); - let rx = -fy; - let ry = fx; - - let cam_z = dx * fx + dy * fy; - if cam_z <= 0.1 { - continue; - } - - let cam_x = dx * rx + dy * ry; - - let half_fov_tan = (fov / 2.0).tan(); - let screen_x_norm = cam_x / (cam_z * half_fov_tan); - if screen_x_norm < -1.0 || screen_x_norm > 1.0 { - continue; - } - - let sx = ((screen_x_norm + 1.0) * 0.5 * self.screen_w as f64) as isize; - - let entity_h = (self.screen_h as f64 / cam_z * 0.4) as isize; - let sy = (half_h - entity_h as f64 * 0.3) as isize; - - let scale = (entity_h.max(6) as f64 / LETTER_H as f64).max(0.5); - let (ch, color) = entity_char_and_color(entity); - - sprites.push(Sprite { - sx, - sy, - scale, - ch, - color, - cam_z, - }); + self.push_entity_sprite(game, ex, ey, entity, fov, half_h, &mut sprites); } } + // Animating enemies (mid-move, not on the grid). + for (wx, wy, entity) in game.enemy_render_entities() { + self.push_entity_sprite(game, wx, wy, &entity, fov, half_h, &mut sprites); + } + // Sort farthest first so nearby entities draw on top. sprites.sort_by(|a, b| b.cam_z.partial_cmp(&a.cam_z).unwrap()); @@ -387,6 +358,56 @@ impl Renderer { } } + /// Project a world-space entity position and push a Sprite if on screen. + fn push_entity_sprite( + &self, + game: &Game, + ex: f64, + ey: f64, + entity: &Entity, + fov: f64, + half_h: f64, + sprites: &mut Vec, + ) { + let dx = ex - game.player.x; + let dy = ey - game.player.y; + + let fx = game.player.angle.cos(); + let fy = game.player.angle.sin(); + let rx = -fy; + let ry = fx; + + let cam_z = dx * fx + dy * fy; + if cam_z <= 0.1 { + return; + } + + let cam_x = dx * rx + dy * ry; + + let half_fov_tan = (fov / 2.0).tan(); + let screen_x_norm = cam_x / (cam_z * half_fov_tan); + if screen_x_norm < -1.0 || screen_x_norm > 1.0 { + return; + } + + let sx = ((screen_x_norm + 1.0) * 0.5 * self.screen_w as f64) as isize; + + let entity_h = (self.screen_h as f64 / cam_z * 0.4) as isize; + let sy = (half_h - entity_h as f64 * 0.3) as isize; + + let scale = (entity_h.max(6) as f64 / LETTER_H as f64).max(0.5); + let (ch, color) = entity_char_and_color(entity); + + sprites.push(Sprite { + sx, + sy, + scale, + ch, + color, + cam_z, + }); + } + fn draw_char_scaled( &self, buffer: &mut [u32], -- cgit v1.2.3