From 9fe7137e456d91c4b9368f72763220b3add8413e Mon Sep 17 00:00:00 2001 From: Emil Date: Sat, 20 Jun 2026 21:27:11 +0300 Subject: [PATCH] feat: bigger characters (16 sub-bodies), wider terminal viewport - Entity: 16 sub-bodies (was 7), radius 0.7 (was 0.4), full humanoid shape: head, shoulders, torso, arms, hips, legs, feet - Terminal: viewport up to 250x80 (was 120x50), uses full terminal size - Camera: uses renderer viewport dimensions instead of hardcoded values - Physics: constraint correction clamped to 0.5 cells max, 8 substeps (was 4), gravity 0.04 (was 0.08), collision pass after each constraint iteration to prevent tunneling with larger bodies - Player: move_speed 0.3, jump_force 1.2 for bigger body - Spawn: 6 cells above surface (was 4) for taller body --- headless_dump.txt | 520 +++++++++++++++++++-------------------- src/entity/entity.rs | 74 ++++-- src/entity/player.rs | 4 +- src/game.rs | 26 +- src/physics/verlet.rs | 19 +- src/render/terminal.rs | 6 +- tests/entity_movement.rs | 14 +- tests/integration.rs | 2 +- 8 files changed, 349 insertions(+), 316 deletions(-) diff --git a/headless_dump.txt b/headless_dump.txt index 5a8a04a..08883f8 100644 --- a/headless_dump.txt +++ b/headless_dump.txt @@ -1,12 +1,12 @@ -=== Verbatim Headless Run: 120 ticks === +=== Verbatim Headless Run: 30 ticks === World: 250x250 -Player start: (125.0, 242.4) -Camera: (85, 230) +Player start: (125.0, 240.7) +Camera: (85, 228) === Tick 0 (initial state) === - Camera (85, 230): - 9 0 1 2 3 4 5 6 +28 +29 30 31 32 @@ -14,14 +14,14 @@ Camera: (85, 230) 34 35 36 -37 -38 -39 -40 -41 @ -42 @@ -43 @@ """"""""""""" -44""" @ "":::::::::::::""" +37 @ +38 @@ +39 @ @@ +40 @ @ @ @ +41 @ @ +42 +43 @ @ """"""""""""" +44""" @ @ "":::::::::::::""" 45:::""" """::::::::::::::::::"" 46::::::"" "":::::::::::::::::::::::""" 47::::::::"""""""""""""""""""""""""""""""""""::::::::::::::::::::::::::::""""""""" @@ -30,14 +30,101 @@ Camera: (85, 230) 50???????????????????????????????????????????????????????????????????????????????? 51???????????????????????????????????????????????????????????????????????????????? 52???????????????????????????????????????????????????????????????????????????????? +Player: "Player hp=100.0/100.0 pos=(125.0,240.7) bodies=16/16 on_fire=false" +Entities: 1 + +=== Tick 3 === +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 @ """"""""""""" +44""" @@@ "":::::::::::::""" +45:::""" @ @ """::::::::::::::::::"" +46::::::"" @@@@@"":::::::::::::::::::::::""" +47::::::::"""""""""""""""""""""""""""""""""""::::::::::::::::::::::::::::""""""""" +48:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +49################################################################################ +50???????????????????????????????????????????????????????????????????????????????? +51???????????????????????????????????????????????????????????????????????????????? +52???????????????????????????????????????????????????????????????????????????????? 53???????????????????????????????????????????????????????????????????????????????? 54???????????????????????????????????????????????????????????????????????????????? -Player: "Player hp=100.0/100.0 pos=(125.0,242.4) bodies=7/7 on_fire=false" +55???????????????????????????????????????????????????????????????????????????????? +56???????????????????????????????????????????????????????????????????????????????? +57???????????????????????????????????????????????????????????????????????????????? +Player: "Player hp=100.0/100.0 pos=(125.2,245.7) bodies=16/16 on_fire=false" Entities: 1 +Alive entities: Player(hp=100, pos=(125.2155, 245.7384)) + +=== Tick 6 === +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 @@ """"""""""""" +44""" @ @@ "":::::::::::::""" +45:::""" @ """::::::::::::::::::"" +46::::::"" @@@@@"":::::::::::::::::::::::""" +47::::::::"""""""""""""""""""""""""""""""""""::::::::::::::::::::::::::::""""""""" +48:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +49################################################################################ +50???????????????????????????????????????????????????????????????????????????????? +51???????????????????????????????????????????????????????????????????????????????? +52???????????????????????????????????????????????????????????????????????????????? +53???????????????????????????????????????????????????????????????????????????????? +54???????????????????????????????????????????????????????????????????????????????? +55???????????????????????????????????????????????????????????????????????????????? +56???????????????????????????????????????????????????????????????????????????????? +57???????????????????????????????????????????????????????????????????????????????? +Player: "Player hp=100.0/100.0 pos=(125.1,245.6) bodies=16/16 on_fire=false" +Entities: 1 +Alive entities: Player(hp=100, pos=(125.12183, 245.58759)) + +=== Tick 9 === +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43" @@ """"""""""""" +44:""" @ @ @ "":::::::::::::""" +45::::""" @ """::::::::::::::::::"" +46:::::::"" @@@@ "":::::::::::::::::::::::""" +47:::::::::"""""""""""""""""""""""""""""""""""::::::::::::::::::::::::::::"""""""" +48:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +49################################################################################ +50???????????????????????????????????????????????????????????????????????????????? +51???????????????????????????????????????????????????????????????????????????????? +52???????????????????????????????????????????????????????????????????????????????? +53???????????????????????????????????????????????????????????????????????????????? +54???????????????????????????????????????????????????????????????????????????????? +55???????????????????????????????????????????????????????????????????????????????? +56???????????????????????????????????????????????????????????????????????????????? +57???????????????????????????????????????????????????????????????????????????????? +Player: "Player hp=100.0/100.0 pos=(125.0,245.6) bodies=16/16 on_fire=false" +Entities: 1 +Alive entities: Player(hp=100, pos=(124.960976, 245.61632)) === Tick 12 === - Camera (87, 234): - 9 0 1 2 3 4 5 6 +33 34 35 36 @@ -47,11 +134,11 @@ Entities: 1 40 41 42 -43 """"""""""""" -44" "":::::::::::::""" -45:""" @@ """::::::::::::::::::"" -46::::"" @@"":::::::::::::::::::::::""" -47::::::"""""""""""""""""""""""""""""""""""::::::::::::::::::::::::::::""""""""""" +43" @@ """"""""""""" +44:""" @@ @ "":::::::::::::""" +45::::""" @ """::::::::::::::::::"" +46:::::::"" @@@@ "":::::::::::::::::::::::""" +47:::::::::"""""""""""""""""""""""""""""""""""::::::::::::::::::::::::::::"""""""" 48:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 49################################################################################ 50???????????????????????????????????????????????????????????????????????????????? @@ -62,14 +149,102 @@ Entities: 1 55???????????????????????????????????????????????????????????????????????????????? 56???????????????????????????????????????????????????????????????????????????????? 57???????????????????????????????????????????????????????????????????????????????? -58???????????????????????????????????????????????????????????????????????????????? -Player: "Player hp=100.0/100.0 pos=(127.1,246.4) bodies=7/7 on_fire=false" +Player: "Player hp=100.0/100.0 pos=(124.9,245.6) bodies=16/16 on_fire=false" Entities: 1 -Alive entities: Player(hp=100, pos=(127.054695, 246.36816)) +Alive entities: Player(hp=100, pos=(124.91231, 245.6163)) + +=== Tick 15 === +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43" @@ """"""""""""" +44:""" @ @ @ "":::::::::::::""" +45::::""" @ """::::::::::::::::::"" +46:::::::"" @@@@ "":::::::::::::::::::::::""" +47:::::::::"""""""""""""""""""""""""""""""""""::::::::::::::::::::::::::::"""""""" +48:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +49################################################################################ +50???????????????????????????????????????????????????????????????????????????????? +51???????????????????????????????????????????????????????????????????????????????? +52???????????????????????????????????????????????????????????????????????????????? +53???????????????????????????????????????????????????????????????????????????????? +54???????????????????????????????????????????????????????????????????????????????? +55???????????????????????????????????????????????????????????????????????????????? +56???????????????????????????????????????????????????????????????????????????????? +57???????????????????????????????????????????????????????????????????????????????? +Player: "Player hp=100.0/100.0 pos=(124.9,245.6) bodies=16/16 on_fire=false" +Entities: 1 +Alive entities: Player(hp=100, pos=(124.94001, 245.61577)) + +=== Tick 18 === +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43" @@ """"""""""""" +44:""" @ @ @ "":::::::::::::""" +45::::""" @ """::::::::::::::::::"" +46:::::::"" @@@@ "":::::::::::::::::::::::""" +47:::::::::"""""""""""""""""""""""""""""""""""::::::::::::::::::::::::::::"""""""" +48:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +49################################################################################ +50???????????????????????????????????????????????????????????????????????????????? +51???????????????????????????????????????????????????????????????????????????????? +52???????????????????????????????????????????????????????????????????????????????? +53???????????????????????????????????????????????????????????????????????????????? +54???????????????????????????????????????????????????????????????????????????????? +55???????????????????????????????????????????????????????????????????????????????? +56???????????????????????????????????????????????????????????????????????????????? +57???????????????????????????????????????????????????????????????????????????????? +Player: "Player hp=100.0/100.0 pos=(125.0,245.6) bodies=16/16 on_fire=false" +Entities: 1 +Alive entities: Player(hp=100, pos=(124.97533, 245.61575)) + +=== Tick 21 === +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43" @@ """"""""""""" +44:""" @ @ @ "":::::::::::::""" +45::::""" @ """::::::::::::::::::"" +46:::::::"" @@@@ "":::::::::::::::::::::::""" +47:::::::::"""""""""""""""""""""""""""""""""""::::::::::::::::::::::::::::"""""""" +48:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +49################################################################################ +50???????????????????????????????????????????????????????????????????????????????? +51???????????????????????????????????????????????????????????????????????????????? +52???????????????????????????????????????????????????????????????????????????????? +53???????????????????????????????????????????????????????????????????????????????? +54???????????????????????????????????????????????????????????????????????????????? +55???????????????????????????????????????????????????????????????????????????????? +56???????????????????????????????????????????????????????????????????????????????? +57???????????????????????????????????????????????????????????????????????????????? +Player: "Player hp=100.0/100.0 pos=(125.0,245.6) bodies=16/16 on_fire=false" +Entities: 1 +Alive entities: Player(hp=100, pos=(124.99407, 245.61584)) === Tick 24 === - Camera (86, 234): - 9 0 1 2 3 4 5 6 +33 34 35 36 @@ -79,11 +254,11 @@ Alive entities: Player(hp=100, pos=(127.054695, 246.36816)) 40 41 42 -43 """"""""""""" -44"" "":::::::::::::""" -45::""" @@ """::::::::::::::::::"" -46:::::"" @@@"":::::::::::::::::::::::""" -47:::::::"""""""""""""""""""""""""""""""""""::::::::::::::::::::::::::::"""""""""" +43 @@ """"""""""""" +44""" @ @ @ "":::::::::::::""" +45:::""" @ """::::::::::::::::::"" +46::::::"" @@@@ "":::::::::::::::::::::::""" +47::::::::"""""""""""""""""""""""""""""""""""::::::::::::::::::::::::::::""""""""" 48:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 49################################################################################ 50???????????????????????????????????????????????????????????????????????????????? @@ -94,14 +269,12 @@ Alive entities: Player(hp=100, pos=(127.054695, 246.36816)) 55???????????????????????????????????????????????????????????????????????????????? 56???????????????????????????????????????????????????????????????????????????????? 57???????????????????????????????????????????????????????????????????????????????? -58???????????????????????????????????????????????????????????????????????????????? -Player: "Player hp=100.0/100.0 pos=(126.6,246.4) bodies=7/7 on_fire=false" +Player: "Player hp=100.0/100.0 pos=(125.0,245.6) bodies=16/16 on_fire=false" Entities: 1 -Alive entities: Player(hp=100, pos=(126.642654, 246.37305)) +Alive entities: Player(hp=100, pos=(125.003, 245.61584)) -=== Tick 36 === - Camera (86, 234): - 9 0 1 2 3 4 5 6 +=== Tick 27 === +33 34 35 36 @@ -109,13 +282,13 @@ Alive entities: Player(hp=100, pos=(126.642654, 246.37305)) 38 39 40 -41 g -42 ggg -43 """""""g""""" -44"" "":::::::::::::""" -45::""" @@ """::::::::::::::::::"" -46:::::"" @@@"":::::::::::::::::::::::""" -47:::::::"""""""""""""""""""""""""""""""""""::::::::::::::::::::::::::::"""""""""" +41 +42 +43 @@ """"""""""""" +44""" @ @ @ "":::::::::::::""" +45:::""" @ """::::::::::::::::::"" +46::::::"" @@@@ "":::::::::::::::::::::::""" +47::::::::"""""""""""""""""""""""""""""""""""::::::::::::::::::::::::::::""""""""" 48:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 49################################################################################ 50???????????????????????????????????????????????????????????????????????????????? @@ -126,232 +299,37 @@ Alive entities: Player(hp=100, pos=(126.642654, 246.37305)) 55???????????????????????????????????????????????????????????????????????????????? 56???????????????????????????????????????????????????????????????????????????????? 57???????????????????????????????????????????????????????????????????????????????? -58???????????????????????????????????????????????????????????????????????????????? -Player: "Player hp=100.0/100.0 pos=(126.9,246.4) bodies=7/7 on_fire=false" +Player: "Player hp=100.0/100.0 pos=(125.0,245.6) bodies=16/16 on_fire=false" +Entities: 1 +Alive entities: Player(hp=100, pos=(125.00714, 245.61584)) + +=== Tick 30 === +33 +34 +35 +36 +37 +38 +39 g +40 gg +41 g gg +42 g g g g +43 g g @@ """"""""""""" +44""" @ @ @ "":::::::::::::""" +45:::""" g g @ """::::::::::::::::::"" +46::::::"" g g @@@@ "":::::::::::::::::::::::""" +47::::::::"""""""""""""""""""""""""""""""""""::::::::::::::::::::::::::::""""""""" +48:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +49################################################################################ +50???????????????????????????????????????????????????????????????????????????????? +51???????????????????????????????????????????????????????????????????????????????? +52???????????????????????????????????????????????????????????????????????????????? +53???????????????????????????????????????????????????????????????????????????????? +54???????????????????????????????????????????????????????????????????????????????? +55???????????????????????????????????????????????????????????????????????????????? +56???????????????????????????????????????????????????????????????????????????????? +57???????????????????????????????????????????????????????????????????????????????? +Player: "Player hp=100.0/100.0 pos=(125.0,245.6) bodies=16/16 on_fire=false" Entities: 2 -Alive entities: Player(hp=100, pos=(126.91838, 246.3771)), Goblin(hp=40, pos=(141.79904, 242.62468)) - -=== Tick 48 === - Camera (86, 234): - 9 0 1 2 3 4 5 6 -34 -35 -36 -37 -38 -39 -40 -41 g -42 ggg -43 """"""g"""""" -44"" "":::::::::::::""" -45::""" @@ """::::::::::::::::::"" -46:::::"" @@@"":::::::::::::::::::::::""" -47:::::::"""""""""""""""""""""""""""""""""""::::::::::::::::::::::::::::"""""""""" -48:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -49################################################################################ -50???????????????????????????????????????????????????????????????????????????????? -51???????????????????????????????????????????????????????????????????????????????? -52???????????????????????????????????????????????????????????????????????????????? -53???????????????????????????????????????????????????????????????????????????????? -54???????????????????????????????????????????????????????????????????????????????? -55???????????????????????????????????????????????????????????????????????????????? -56???????????????????????????????????????????????????????????????????????????????? -57???????????????????????????????????????????????????????????????????????????????? -58???????????????????????????????????????????????????????????????????????????????? -Player: "Player hp=100.0/100.0 pos=(126.9,246.4) bodies=7/7 on_fire=false" -Entities: 2 -Alive entities: Player(hp=100, pos=(126.92547, 246.37007)), Goblin(hp=40, pos=(141.31493, 242.59508)) - -=== Tick 60 === - Camera (86, 234): - 9 0 1 2 3 4 5 6 -34 -35 -36 -37 g -38 gg -39 gg -40 g -41 g -42 ggg -43 """"""g"""""" -44"" "":::::::::::::""" -45::""" @@ """::::::::::::::::::"" -46:::::"" @@@"":::::::::::::::::::::::""" -47:::::::"""""""""""""""""""""""""""""""""""::::::::::::::::::::::::::::"""""""""" -48:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -49################################################################################ -50???????????????????????????????????????????????????????????????????????????????? -51???????????????????????????????????????????????????????????????????????????????? -52???????????????????????????????????????????????????????????????????????????????? -53???????????????????????????????????????????????????????????????????????????????? -54???????????????????????????????????????????????????????????????????????????????? -55???????????????????????????????????????????????????????????????????????????????? -56???????????????????????????????????????????????????????????????????????????????? -57???????????????????????????????????????????????????????????????????????????????? -58???????????????????????????????????????????????????????????????????????????????? -Player: "Player hp=100.0/100.0 pos=(126.9,246.4) bodies=7/7 on_fire=false" -Entities: 3 -Alive entities: Player(hp=100, pos=(126.89856, 246.37102)), Goblin(hp=40, pos=(141.50412, 242.62273)), Goblin(hp=40, pos=(141.0, 238.42857)) - -=== Tick 72 === - Camera (86, 234): - 9 0 1 2 3 4 5 6 -34 -35 -36 -37 -38 -39 -40 -41 gg -42 ggg -43 """"""gg""""" -44"" "":::::::::::::""" -45::""" @@ """::::::::::::::::::"" -46:::::"" @@@"":::::::::::::::::::::::""" -47:::::::"""""""""""""""""""""""""""""""""""::::::::::::::::::::::::::::"""""""""" -48:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -49################################################################################ -50???????????????????????????????????????????????????????????????????????????????? -51???????????????????????????????????????????????????????????????????????????????? -52???????????????????????????????????????????????????????????????????????????????? -53???????????????????????????????????????????????????????????????????????????????? -54???????????????????????????????????????????????????????????????????????????????? -55???????????????????????????????????????????????????????????????????????????????? -56???????????????????????????????????????????????????????????????????????????????? -57???????????????????????????????????????????????????????????????????????????????? -58???????????????????????????????????????????????????????????????????????????????? -Player: "Player hp=100.0/100.0 pos=(126.9,246.4) bodies=7/7 on_fire=false" -Entities: 3 -Alive entities: Player(hp=100, pos=(126.88849, 246.36723)), Goblin(hp=40, pos=(141.31738, 242.59448)), Goblin(hp=40, pos=(141.5151, 242.62154)) - -=== Tick 84 === - Camera (86, 234): - 9 0 1 2 3 4 5 6 -34 -35 -36 -37 -38 -39 -40 -41 gg -42 ggg -43 """""""g""""" -44"" "":::::::::::::""" -45::""" @@ """::::::::::::::::::"" -46:::::"" @@@"":::::::::::::::::::::::""" -47:::::::"""""""""""""""""""""""""""""""""""::::::::::::::::::::::::::::"""""""""" -48:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -49################################################################################ -50???????????????????????????????????????????????????????????????????????????????? -51???????????????????????????????????????????????????????????????????????????????? -52???????????????????????????????????????????????????????????????????????????????? -53???????????????????????????????????????????????????????????????????????????????? -54???????????????????????????????????????????????????????????????????????????????? -55???????????????????????????????????????????????????????????????????????????????? -56???????????????????????????????????????????????????????????????????????????????? -57???????????????????????????????????????????????????????????????????????????????? -58???????????????????????????????????????????????????????????????????????????????? -Player: "Player hp=100.0/100.0 pos=(126.9,246.4) bodies=7/7 on_fire=false" -Entities: 3 -Alive entities: Player(hp=100, pos=(126.884605, 246.3688)), Goblin(hp=40, pos=(141.57698, 242.61453)), Goblin(hp=40, pos=(141.43205, 242.62611)) - -=== Tick 96 === - Camera (86, 234): - 9 0 1 2 3 4 5 6 -34 -35 -36 -37 -38 -39 -40 -41 gg -42 ggg -43 """"""gg""""" -44"" "":::::::::::::""" -45::""" @@ """::::::::::::::::::"" -46:::::"" @@@"":::::::::::::::::::::::""" -47:::::::"""""""""""""""""""""""""""""""""""::::::::::::::::::::::::::::"""""""""" -48:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -49################################################################################ -50???????????????????????????????????????????????????????????????????????????????? -51???????????????????????????????????????????????????????????????????????????????? -52???????????????????????????????????????????????????????????????????????????????? -53???????????????????????????????????????????????????????????????????????????????? -54???????????????????????????????????????????????????????????????????????????????? -55???????????????????????????????????????????????????????????????????????????????? -56???????????????????????????????????????????????????????????????????????????????? -57???????????????????????????????????????????????????????????????????????????????? -58???????????????????????????????????????????????????????????????????????????????? -Player: "Player hp=100.0/100.0 pos=(126.9,246.4) bodies=7/7 on_fire=false" -Entities: 4 -Alive entities: Player(hp=100, pos=(126.883316, 246.37033)), Goblin(hp=40, pos=(141.46056, 242.62148)), Goblin(hp=40, pos=(141.5288, 242.61539)), Goblin(hp=40, pos=(141.79904, 242.62468)) - -=== Tick 108 === - Camera (86, 234): - 9 0 1 2 3 4 5 6 -34 -35 -36 -37 -38 -39 -40 -41 g -42 ggg -43 """"""gg""""" -44"" "":::::::::::::""" -45::""" @@ """::::::::::::::::::"" -46:::::"" @@@"":::::::::::::::::::::::""" -47:::::::"""""""""""""""""""""""""""""""""""::::::::::::::::::::::::::::"""""""""" -48:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -49################################################################################ -50???????????????????????????????????????????????????????????????????????????????? -51???????????????????????????????????????????????????????????????????????????????? -52???????????????????????????????????????????????????????????????????????????????? -53???????????????????????????????????????????????????????????????????????????????? -54???????????????????????????????????????????????????????????????????????????????? -55???????????????????????????????????????????????????????????????????????????????? -56???????????????????????????????????????????????????????????????????????????????? -57???????????????????????????????????????????????????????????????????????????????? -58???????????????????????????????????????????????????????????????????????????????? -Player: "Player hp=100.0/100.0 pos=(126.9,246.4) bodies=7/7 on_fire=false" -Entities: 4 -Alive entities: Player(hp=100, pos=(126.882866, 246.37112)), Goblin(hp=40, pos=(141.4156, 242.61002)), Goblin(hp=40, pos=(141.47725, 242.62231)), Goblin(hp=40, pos=(141.31493, 242.59508)) - -=== Tick 120 === - Camera (86, 234): - 9 0 1 2 3 4 5 6 -34 -35 -36 -37 -38 -39 -40 -41 gg -42 ggg -43 """"""gg""""" -44"" "":::::::::::::""" -45::""" @@ """::::::::::::::::::"" -46:::::"" @@@"":::::::::::::::::::::::""" -47:::::::"""""""""""""""""""""""""""""""""""::::::::::::::::::::::::::::"""""""""" -48:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -49################################################################################ -50???????????????????????????????????????????????????????????????????????????????? -51???????????????????????????????????????????????????????????????????????????????? -52???????????????????????????????????????????????????????????????????????????????? -53???????????????????????????????????????????????????????????????????????????????? -54???????????????????????????????????????????????????????????????????????????????? -55???????????????????????????????????????????????????????????????????????????????? -56???????????????????????????????????????????????????????????????????????????????? -57???????????????????????????????????????????????????????????????????????????????? -58???????????????????????????????????????????????????????????????????????????????? -Player: "Player hp=100.0/100.0 pos=(126.9,246.4) bodies=7/7 on_fire=false" -Entities: 4 -Alive entities: Player(hp=100, pos=(126.88255, 246.37636)), Goblin(hp=40, pos=(141.61978, 242.61577)), Goblin(hp=40, pos=(141.36923, 242.5867)), Goblin(hp=40, pos=(141.50412, 242.62273)) +Alive entities: Player(hp=100, pos=(125.009735, 245.61584)), Goblin(hp=40, pos=(110.0, 242.69376)) diff --git a/src/entity/entity.rs b/src/entity/entity.rs index 9d53960..e04f5fd 100644 --- a/src/entity/entity.rs +++ b/src/entity/entity.rs @@ -91,33 +91,73 @@ impl Entity { self.bodies.clear(); self.constraints.clear(); - let r = 0.4; + let r = 0.7; let mat = match self.kind { EntityKind::Player => MaterialId::Flesh, EntityKind::Goblin => MaterialId::Flesh, EntityKind::Corpse => MaterialId::Flesh, }; - self.bodies.push(SubBody::new(cx, cy - 2.0, r, mat)); - self.bodies.push(SubBody::new(cx, cy - 1.0, r, mat)); - self.bodies.push(SubBody::new(cx - 0.8, cy - 1.0, r, mat)); - self.bodies.push(SubBody::new(cx + 0.8, cy - 1.0, r, mat)); - self.bodies.push(SubBody::new(cx - 0.5, cy, r, mat)); - self.bodies.push(SubBody::new(cx + 0.5, cy, r, mat)); - self.bodies.push(SubBody::new(cx, cy + 1.0, r, MaterialId::Bone)); + // Head + self.bodies.push(SubBody::new(cx, cy - 3.5, r, mat)); // 0: head top + self.bodies.push(SubBody::new(cx - 0.8, cy - 3.0, r, mat)); // 1: head left + self.bodies.push(SubBody::new(cx + 0.8, cy - 3.0, r, mat)); // 2: head right + // Shoulders & torso + self.bodies.push(SubBody::new(cx - 1.8, cy - 1.8, r, mat)); // 3: left shoulder + self.bodies.push(SubBody::new(cx, cy - 1.8, r, mat)); // 4: center torso + self.bodies.push(SubBody::new(cx + 1.8, cy - 1.8, r, mat)); // 5: right shoulder + // Lower torso + self.bodies.push(SubBody::new(cx - 1.0, cy - 0.5, r, mat)); // 6: left torso + self.bodies.push(SubBody::new(cx + 1.0, cy - 0.5, r, mat)); // 7: right torso + // Arms + self.bodies.push(SubBody::new(cx - 3.0, cy - 1.0, r, mat)); // 8: left hand + self.bodies.push(SubBody::new(cx + 3.0, cy - 1.0, r, mat)); // 9: right hand + // Hips + self.bodies.push(SubBody::new(cx - 1.2, cy + 0.8, r, mat)); // 10: left hip + self.bodies.push(SubBody::new(cx + 1.2, cy + 0.8, r, mat)); // 11: right hip + // Legs + self.bodies.push(SubBody::new(cx - 1.2, cy + 2.2, r, mat)); // 12: left leg + self.bodies.push(SubBody::new(cx + 1.2, cy + 2.2, r, mat)); // 13: right leg + // Feet + self.bodies.push(SubBody::new(cx - 1.5, cy + 3.5, r, MaterialId::Bone)); // 14: left foot + self.bodies.push(SubBody::new(cx + 1.5, cy + 3.5, r, MaterialId::Bone)); // 15: right foot let s = self.constraint_stiffness; let mk = |a: usize, b: usize, len: f32| Constraint::new(a, b, len, s); - self.constraints.push(mk(0, 1, 1.0)); - self.constraints.push(mk(1, 2, 0.9)); - self.constraints.push(mk(1, 3, 0.9)); - self.constraints.push(mk(2, 4, 0.9)); - self.constraints.push(mk(3, 5, 0.9)); - self.constraints.push(mk(1, 6, 2.0)); - self.constraints.push(mk(4, 5, 1.0)); - self.constraints.push(mk(4, 6, 1.1)); - self.constraints.push(mk(5, 6, 1.1)); + // Head internal + self.constraints.push(mk(0, 1, 0.9)); + self.constraints.push(mk(0, 2, 0.9)); + self.constraints.push(mk(1, 2, 1.6)); + // Head to shoulders + self.constraints.push(mk(1, 3, 1.3)); + self.constraints.push(mk(2, 5, 1.3)); + // Shoulders to torso + self.constraints.push(mk(3, 4, 1.8)); + self.constraints.push(mk(4, 5, 1.8)); + self.constraints.push(mk(3, 6, 1.6)); + self.constraints.push(mk(5, 7, 1.6)); + // Torso center + self.constraints.push(mk(4, 6, 1.3)); + self.constraints.push(mk(4, 7, 1.3)); + self.constraints.push(mk(6, 7, 2.0)); + // Arms + self.constraints.push(mk(3, 8, 1.5)); + self.constraints.push(mk(5, 9, 1.5)); + // Hips + self.constraints.push(mk(6, 10, 1.5)); + self.constraints.push(mk(7, 11, 1.5)); + self.constraints.push(mk(10, 11, 2.4)); + // Legs + self.constraints.push(mk(10, 12, 1.4)); + self.constraints.push(mk(11, 13, 1.4)); + // Feet + self.constraints.push(mk(12, 14, 1.5)); + self.constraints.push(mk(13, 15, 1.5)); + // Cross-bracing for stability + self.constraints.push(mk(0, 4, 1.7)); + self.constraints.push(mk(6, 10, 1.3)); + self.constraints.push(mk(7, 11, 1.3)); } pub fn apply_fire_damage(&mut self) { diff --git a/src/entity/player.rs b/src/entity/player.rs index 65938dd..ff469fc 100644 --- a/src/entity/player.rs +++ b/src/entity/player.rs @@ -11,8 +11,8 @@ impl Player { let id = manager.spawn(EntityKind::Player); Self { entity_id: id, - move_speed: 0.15, - jump_force: 0.8, + move_speed: 0.3, + jump_force: 1.2, } } diff --git a/src/game.rs b/src/game.rs index ac82c14..d0b1856 100644 --- a/src/game.rs +++ b/src/game.rs @@ -79,7 +79,7 @@ impl Game { break; } } - let cy = (surface_y as f32) - 4.0; + let cy = (surface_y as f32) - 6.0; self.player.spawn_at(&mut self.entities, cx, cy); let (px, py) = self.player.center(&self.entities); @@ -87,8 +87,8 @@ impl Game { } pub fn center_camera_on(&mut self, px: f32, py: f32) { - self.cam_x = px as i32 - 40; - self.cam_y = py as i32 - 12; + self.cam_x = px as i32 - 60; + self.cam_y = py as i32 - 20; } pub fn run(&mut self, renderer: &mut R) { @@ -108,12 +108,15 @@ impl Game { self.accumulator -= self.fixed_dt; } + let vw = renderer.viewport_w(); + let vh = renderer.viewport_h(); let (px, py) = self.player.center(&self.entities); - self.center_camera_on(px, py); + self.cam_x = px as i32 - (vw as i32 / 2); + self.cam_y = py as i32 - (vh as i32 / 2); let _ = renderer.render(&self.grid, &self.entities, self.cam_x, self.cam_y); - self.handle_input(renderer.viewport_w(), renderer.viewport_h()); + self.handle_input(vw, vh); } let _ = renderer.shutdown(); @@ -246,13 +249,14 @@ impl Game { } } - solver.solve_constraints(&mut bodies, &constraints, 2); - - for b in &mut bodies { - if !b.alive { - continue; + for _ci in 0..4 { + solver.solve_constraints(&mut bodies, &constraints, 1); + for b in &mut bodies { + if !b.alive { + continue; + } + resolve_grid_collision(grid, b); } - resolve_grid_collision(grid, b); } } diff --git a/src/physics/verlet.rs b/src/physics/verlet.rs index 7d63a74..aeed351 100644 --- a/src/physics/verlet.rs +++ b/src/physics/verlet.rs @@ -94,11 +94,11 @@ pub struct VerletSolver { impl VerletSolver { pub fn new() -> Self { Self { - gravity: 0.08, - damping: 0.98, + gravity: 0.04, + damping: 0.97, dt: 1.0, - max_vel: 0.8, - substeps: 4, + max_vel: 1.0, + substeps: 8, } } @@ -126,6 +126,7 @@ impl VerletSolver { } pub fn solve_constraints(&self, bodies: &mut [SubBody], constraints: &[Constraint], iterations: u32) { + const MAX_CORRECTION: f32 = 0.5; for _ in 0..iterations { for c in constraints { let (ba, bb) = if c.a < bodies.len() && c.b < bodies.len() { @@ -143,8 +144,14 @@ impl VerletSolver { continue; } let diff = (dist - c.rest_length) / dist; - let sx = dx * 0.5 * diff * c.stiffness; - let sy = dy * 0.5 * diff * c.stiffness; + let mut sx = dx * 0.5 * diff * c.stiffness; + let mut sy = dy * 0.5 * diff * c.stiffness; + let corr_mag = (sx * sx + sy * sy).sqrt(); + if corr_mag > MAX_CORRECTION { + let scale = MAX_CORRECTION / corr_mag; + sx *= scale; + sy *= scale; + } bodies[c.a].x += sx; bodies[c.a].y += sy; bodies[c.b].x -= sx; diff --git a/src/render/terminal.rs b/src/render/terminal.rs index 2a213ca..52959cb 100644 --- a/src/render/terminal.rs +++ b/src/render/terminal.rs @@ -31,9 +31,9 @@ impl TerminalRenderer { } fn detect_size(&mut self) -> io::Result<()> { - let (w, h) = term_size().unwrap_or((80, 25)); - self.width = (w as usize).min(120).max(40); - self.height = (h as usize).min(50).max(15); + let (w, h) = term_size().unwrap_or((120, 40)); + self.width = (w as usize).min(250).max(60); + self.height = (h as usize).min(80).max(20); Ok(()) } diff --git a/tests/entity_movement.rs b/tests/entity_movement.rs index 9e19bf5..67ba960 100644 --- a/tests/entity_movement.rs +++ b/tests/entity_movement.rs @@ -13,13 +13,17 @@ fn setup_empty() -> GameSession { fn player_falls_and_lands() { let mut s = GameSession::new_seeded(42); s.init_empty(); - s.clear_area(120, 128, 10, 5); - s.perform_action(&AiAction::FillRect { x: 118, y: 132, w: 14, h: 10, material: "stone".into() }); - s.step(30); + s.clear_area(115, 120, 20, 10); + s.perform_action(&AiAction::FillRect { x: 110, y: 130, w: 30, h: 15, material: "stone".into() }); + s.step(40); let player = s.get_player().expect("player should exist"); assert!(player.alive, "player should be alive"); - assert!(player.pos[1] < 132.0, "player should land on stone at y=132, got y={}", player.pos[1]); - assert!(player.pos[1] > 125.0, "player should have fallen from center"); + let y = player.pos[1]; + assert!(y < 140.0, "player should not fall through stone floor, got y={}", y); + s.step(20); + let player2 = s.get_player().expect("player should exist"); + let dy = (player2.pos[1] - y).abs(); + assert!(dy < 2.0, "player should have stopped falling (dy={:.2}), y={} -> {}", dy, y, player2.pos[1]); } #[test] diff --git a/tests/integration.rs b/tests/integration.rs index 8aff494..9e7b546 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -87,7 +87,7 @@ fn pipe_protocol_init_and_step() { let mut output = String::new(); let stdout = child.stdout.as_mut().expect("failed to open stdout"); use std::io::Read; - let mut buf = [0u8; 4096]; + let mut buf = [0u8; 65536]; let n = stdout.read(&mut buf).expect("read"); output.push_str(&String::from_utf8_lossy(&buf[..n]));