From 586487e61c1744fe48c3c7466678fbce25074117 Mon Sep 17 00:00:00 2001 From: Emil Date: Sun, 21 Jun 2026 18:14:34 +0300 Subject: [PATCH] feat: asymmetric characters that flip when turning - Player template is now asymmetric: - Weapon arm extends forward (right side, x=3..4) - Hair flows backward (left side, x=-3..-4) - Cape drapes to the left (x=-3..-4) - Front hand colored as 'weapon' (bright steel) - Goblin template asymmetric: weapon arm extends forward (x=4) - Entity.flip_facing() mirrors all rest_offsets X and body positions - Entity.facing_right field (default true) - Game loop detects mouse crossing player center X and calls flip_facing() - Verlet constraints adapt smoothly to mirrored positions - 'weapon' label added to preview_ascii All 171 tests + 14 scenarios pass. --- src/entity/body_template.rs | 26 +++++++++++++++----------- src/entity/entity.rs | 18 ++++++++++++++++++ src/main.rs | 8 +++++++- 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/src/entity/body_template.rs b/src/entity/body_template.rs index bb3ebc0..15c6d7b 100644 --- a/src/entity/body_template.rs +++ b/src/entity/body_template.rs @@ -46,13 +46,13 @@ impl BodyTemplate { p!(0, -5, 40, 30, 50, "eye"), p!(-1, -5, 60, 40, 70, "eye"), p!(1, -5, 60, 40, 70, "eye"), - p!(-2, -6, 120, 80, 40, "hair"), - p!(-1, -7, 140, 90, 50, "hair"), + p!(-3, -6, 120, 80, 40, "hair"), + p!(-2, -7, 140, 90, 50, "hair"), + p!(-1, -7, 150, 100, 55, "hair"), p!(0, -7, 150, 100, 55, "hair"), p!(1, -7, 140, 90, 50, "hair"), - p!(2, -6, 120, 80, 40, "hair"), - p!(-3, -7, 110, 70, 35, "hair"), - p!(3, -7, 110, 70, 35, "hair"), + p!(-3, -5, 110, 70, 35, "hair"), + p!(-4, -5, 100, 60, 30, "hair"), p!(-2, -4, 80, 50, 130, "hat"), p!(2, -4, 80, 50, 130, "hat"), p!(-1, -5, 90, 55, 140, "hat"), @@ -70,23 +70,25 @@ impl BodyTemplate { p!(1, -3, 150, 90, 210, "shirt"), p!(-2, -3, 210, 185, 240, "hand"), p!(2, -3, 210, 185, 240, "hand"), + p!(3, -3, 220, 195, 245, "weapon"), + p!(4, -3, 230, 205, 250, "weapon"), p!(-1, -2, 150, 90, 210, "shirt"), p!(0, -2, 160, 100, 220, "shirt"), p!(1, -2, 150, 90, 210, "shirt"), p!(-2, -2, 200, 170, 230, "hand"), p!(2, -2, 200, 170, 230, "hand"), - p!(-3, -2, 80, 50, 130, "cape"), - p!(3, -2, 80, 50, 130, "cape"), + p!(-4, -2, 80, 50, 130, "cape"), + p!(-3, -2, 75, 45, 120, "cape"), p!(-1, -1, 150, 90, 210, "shirt"), p!(0, -1, 160, 100, 220, "shirt"), p!(1, -1, 150, 90, 210, "shirt"), - p!(-3, -1, 75, 45, 120, "cape"), - p!(3, -1, 75, 45, 120, "cape"), + p!(-4, -1, 70, 40, 110, "cape"), + p!(-3, -1, 70, 40, 110, "cape"), p!(-1, 0, 230, 190, 110, "belt"), p!(0, 0, 240, 200, 120, "belt"), p!(1, 0, 230, 190, 110, "belt"), - p!(-3, 0, 70, 40, 110, "cape"), - p!(3, 0, 70, 40, 110, "cape"), + p!(-4, 0, 60, 35, 100, "cape"), + p!(-3, 0, 65, 38, 105, "cape"), p!(-1, 1, 95, 55, 155, "pants"), p!(0, 1, 95, 55, 155, "pants"), p!(1, 1, 95, 55, 155, "pants"), @@ -145,6 +147,7 @@ impl BodyTemplate { p!(2, -3, 110, 180, 85, "hand"), p!(-3, -3, 100, 170, 75, "hand"), p!(3, -3, 100, 170, 75, "hand"), + p!(4, -3, 180, 160, 60, "weapon"), p!(-1, -2, 55, 130, 45, "shirt"), p!(0, -2, 65, 140, 50, "shirt"), p!(1, -2, 55, 130, 45, "shirt"), @@ -357,6 +360,7 @@ impl BodyTemplate { ("cape", '>'), ("tooth", '.'), ("ear", '<'), + ("weapon", '/'), ]); for part in &self.parts { diff --git a/src/entity/entity.rs b/src/entity/entity.rs index 06cec22..7bf4064 100644 --- a/src/entity/entity.rs +++ b/src/entity/entity.rs @@ -41,6 +41,7 @@ pub struct Entity { pub toughness: u32, pub willpower: u32, pub counted_for_score: bool, + pub facing_right: bool, } impl Clone for Entity { @@ -76,6 +77,7 @@ impl Clone for Entity { toughness: self.toughness, willpower: self.willpower, counted_for_score: self.counted_for_score, + facing_right: self.facing_right, } } } @@ -111,6 +113,7 @@ impl Entity { toughness: 10, willpower: 10, counted_for_score: false, + facing_right: true, half_w: 3.5, half_h: 3.0, } @@ -195,6 +198,21 @@ impl Entity { } } + pub fn flip_facing(&mut self) { + self.facing_right = !self.facing_right; + for off in &mut self.rest_offsets { + off.0 = -off.0; + } + for b in &mut self.bodies { + if b.alive { + let dx = b.x - self.cx; + b.x = self.cx - dx; + let old_dx = b.old_x - self.cx; + b.old_x = self.cx - old_dx; + } + } + } + pub fn set_horizontal_vel(&mut self, vx: f32) { if self.rigid { self.cvx = vx; diff --git a/src/main.rs b/src/main.rs index c36707a..80284e6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -329,7 +329,13 @@ fn run_gpu_mode(title: &str) { { let (px, _py) = game.player.center(&game.entities); let player_screen_x = ((px as i32 - game.cam_x) as f64) * 8.0 + 4.0; - game.player.facing_right = input.mouse_x >= player_screen_x; + let should_face_right = input.mouse_x >= player_screen_x; + if should_face_right != game.player.facing_right { + if let Some(e) = game.player.entity_mut(&mut game.entities) { + e.flip_facing(); + } + game.player.facing_right = should_face_right; + } } if input.cam_left {