Units face eight directions and animate their actions

- five sprite views per kind and gear tier (front, front three-quarter, profile, back three-quarter, back), mirrored for the other three directions; chosen from the unit's facing and the camera
- units face where they walk, dig, repair or fight
- animations: imps stomp while claiming (squash on landing), swing while digging, hammer while repairing; lunges in combat, punches in training, nodding while eating, swaying while reading or praying, breathing when idle, leaning back with loads, lying in bed, chained creatures pulling at their chains, flyers flapping

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard ZinkandClaude Opus 5.5 committed 2026-11-03 15:41:09 +01:00
1 parent 1016ee5d6c
commit d06ce2edb5
3 files changed
+234 -21

No files matched your search

+33
View File
@@ -210,6 +210,8 @@ pub struct Ent {
pub anim: f32,
pub flash: f32,
pub face: f32,
#[serde(default)]
pub dir: f32, // facing direction on the map (radians, 0 = +x), for the eight sprite views
pub moving: bool,
pub working: bool,
#[serde(default)]
@@ -282,6 +284,7 @@ impl Ent {
anim: 0.0,
flash: 0.0,
face: 1.0,
dir: std::f32::consts::FRAC_PI_2,
moving: false,
working: false,
slow: 0.0,
@@ -1016,7 +1019,9 @@ impl Game {
continue;
}
let mut e = std::mem::replace(&mut self.ents[i], Ent::dummy());
let (x0, y0) = (e.x, e.y);
self.update_ent(&mut e, dt);
self.turn(&mut e, x0, y0);
self.ents[i] = e;
}
self.ents.retain(|e| e.alive);
@@ -1621,6 +1626,34 @@ impl Game {
}
}
// the direction a unit faces: where it walks, otherwise what it works on or fights
fn turn(&self, e: &mut Ent, x0: f32, y0: f32) {
let (dx, dy) = (e.x - x0, e.y - y0);
if dx * dx + dy * dy > 1e-8 {
e.dir = dy.atan2(dx);
return;
}
if !e.working {
return;
}
let tile = |t: usize| {
let (x, y) = xy(t);
Some((x as f32 + 0.5, y as f32 + 0.5))
};
let target = match e.job {
Job::Dig(t) | Job::Reinforce(t) | Job::Help(t) | Job::TearBridge(t) => tile(t),
Job::Attack(id) | Job::Torment(id) | Job::Carry(id) => self.find(id).map(|j| (self.ents[j].x, self.ents[j].y)),
Job::Repair(id) | Job::AttackTower(id) => self.towers.iter().find(|t| t.id == id).map(|t| t.pos()),
_ => None,
};
if let Some((tx, ty)) = target {
let (dx, dy) = (tx - e.x, ty - e.y);
if dx * dx + dy * dy > 0.01 {
e.dir = dy.atan2(dx);
}
}
}
// moves a unit along its path; true = still moving
pub(crate) fn step_path(&mut self, e: &mut Ent, dt: f32) -> bool {
if e.path.is_empty() {