feat: Verbatim MVP - terminal renderer, cellular automaton, Verlet physics

- World: 250x250 grid with 14 materials (sand, water, lava, stone, wood, etc.)
- Physics: cellular automaton for materials + Verlet solver for entities
- Entity: multi-cell humanoid (7 sub-bodies with distance constraints)
- Render: terminal renderer with ANSI colors and diff-based updates
- Game loop: fixed 60Hz timestep with accumulator pattern
- Input: WASD movement, number keys for material painting
This commit is contained in:
Emil
2026-06-20 18:21:26 +03:00
commit 68f6292c4d
19 changed files with 2218 additions and 0 deletions
+64
View File
@@ -0,0 +1,64 @@
use crate::entity::entity::{Entity, EntityKind, EntityManager, EntityId};
pub struct Player {
pub entity_id: EntityId,
pub move_speed: f32,
pub jump_force: f32,
}
impl Player {
pub fn new(manager: &mut EntityManager) -> Self {
let id = manager.spawn(EntityKind::Player);
Self {
entity_id: id,
move_speed: 0.15,
jump_force: 0.8,
}
}
pub fn spawn_at(&self, manager: &mut EntityManager, cx: f32, cy: f32) {
if let Some(e) = manager.get_mut(self.entity_id) {
e.build_humanoid(cx, cy);
}
}
pub fn move_left(&self, manager: &mut EntityManager) {
if let Some(e) = manager.get_mut(self.entity_id) {
if let Some(head) = e.head_mut() {
head.add_vel(-self.move_speed, 0.0);
}
}
}
pub fn move_right(&self, manager: &mut EntityManager) {
if let Some(e) = manager.get_mut(self.entity_id) {
if let Some(head) = e.head_mut() {
head.add_vel(self.move_speed, 0.0);
}
}
}
pub fn jump(&self, manager: &mut EntityManager, on_ground: bool) {
if on_ground {
if let Some(e) = manager.get_mut(self.entity_id) {
for b in &mut e.bodies {
if b.alive {
b.add_vel(0.0, -self.jump_force);
}
}
}
}
}
pub fn entity<'a>(&self, manager: &'a EntityManager) -> Option<&'a Entity> {
manager.get(self.entity_id)
}
pub fn entity_mut<'a>(&self, manager: &'a mut EntityManager) -> Option<&'a mut Entity> {
manager.get_mut(self.entity_id)
}
pub fn center(&self, manager: &EntityManager) -> (f32, f32) {
manager.get(self.entity_id).map(|e| e.center()).unwrap_or((0.0, 0.0))
}
}