Nimbin[12]?Games / Entropie / commits / 2d01926

Entropie git · main

Entropie festival game; first steps

sdl c game entropie cmake · first commit 2026-10-10 · last commit 2026-11-02 (17 hours ago) · synced 8 hours ago

C 88.5% Markdown 9.1% GLSL 2.3%
git clone https://git.christianimmanuel.de/games/Entropie.gitwget https://git.christianimmanuel.de/games/Entropie/archive/Entropie.tar.gz

entropie 1.57.0: timed jumps over low things; no more collapsed sleepers

Christian Immanuel · 2026-10-14 20:39 · 2d019266dd2336cbcf9592b9a602effbd7f966c7

- Jogging or faster, low things are jumped on their own: no slowing down
  before them, the take-off timed so the top of the jump is over them, as
  high as it takes (and long enough to land past them)
- People lying down or passing out before ever facing anywhere no longer
  collapse into a heap above the floor (no fall direction: on the back)
 entropie/Makefile               |  2 +-
 entropie/README.md              |  5 ++-
 entropie/STATE.md               |  6 ++--
 entropie/commit_message.txt     | 15 ++++-----
 entropie/src/people/body.c      |  3 ++
 entropie/src/people/body_pose.c |  4 ++-
 entropie/src/world/physics.c    | 74 ++++++++++++++++++++++++++++-------------
 7 files changed, 71 insertions(+), 38 deletions(-)

diff --git a/entropie/Makefile b/entropie/Makefile
index 49be6ab..15bfbba 100644
--- a/entropie/Makefile
+++ b/entropie/Makefile
@@ -1,5 +1,5 @@
 APP       := entropie
-VERSION   := 1.56.0
+VERSION   := 1.57.0
 
 PREFIX    ?= /usr
 BINDIR    ?= $(PREFIX)/bin
diff --git a/entropie/README.md b/entropie/README.md
index 54ecc99..55d5858 100644
--- a/entropie/README.md
+++ b/entropie/README.md
@@ -144,7 +144,10 @@ and satellite pictures (about 340 x 340 m).
 - Stepping over, you lean into it and the leg swings round a little, out to
   the side and back in to land, while the momentum carries you on
 - The sporty fit their steps to what's coming, so a foot lands at a good
-  take-off spot; sprinting fit and fresh, they leap low things in their stride
+  take-off spot
+- Jogging or faster, low things (up to about the knee) are jumped on their
+  own: no slowing down before them, the take-off timed so the top of the
+  jump is over them, as high as it takes
 - Running into something sober: low, you trip or go headlong over it; high,
   you stagger back or go down to the side you came in from. How badly
   depends on speed, fitness, energy and clumsiness
diff --git a/entropie/STATE.md b/entropie/STATE.md
index 0579678..79a937b 100644
--- a/entropie/STATE.md
+++ b/entropie/STATE.md
@@ -64,7 +64,7 @@ Talk topics: offer, ask, suggest, where (new woodpile spot), ask for a hand, ask
 
 ## Body
 
-- **Poses**: up, falling, lying down to sleep, down, getting up; sitting on a seat or cross-legged on the ground
+- **Poses**: up, falling, lying down to sleep, down, getting up; sitting on a seat or cross-legged on the ground. Lying down (or falling) before ever having faced anywhere (asleep or passed out right where they stood): back, as usual (it collapsed into a heap "sitting over the floor")
 - **Fidgets** (standing about): shake a leg, rock on the toes, stretch, roll shoulders, stretch the neck, fold arms, tap a foot
 - **Gestures**: hand on the hip, at the head, at the chin, in a pocket
 - **Face**: mouth, eyelids, brows, smile, gaze; drunk, tired, shy, proud show in it
@@ -76,7 +76,7 @@ Talk topics: offer, ask, suggest, where (new woodpile spot), ask for a hand, ask
 - **Arms out of things**: standing, an arm that would be in something solid (fixed or 40 kg and more; not ladders) moves back and out (eases at 2 m/s) and is fitted again; a hand holding an edge stays, the elbow swings back over the edge
 - **Speed limit**: no joint moves faster than it can (hands 14, feet 12, knees and elbows 9, trunk 5 m/s); bones keep their length; a limb folded right up (foot by the hip, cross-legged) keeps its bend instead of being fitted again (that flipped the knee); between folded and stretched (30-42 % of its reach) the two blend, so an arm folding up on an edge no longer jumps (elbows popped 31 cm); an elbow swung up over an edge stays solved that way
 - **Any frame rate**: springs are solved exactly per frame, people pushing each other ease apart gently, helpers stay put once there (or blocked close by): no flicker at low, high or uneven frame rates
-- **Approaching obstacles**: the sporty fit their steps to a good take-off spot; sprinting fit and fresh, they leap low narrow things; running into something: trip or headlong over it if low, stagger back or fall to the side if high (speed, fitness, energy, clumsiness)
+- **Approaching obstacles**: the sporty fit their steps to a good take-off spot; jogging or faster (2.9 m/s+, some energy, not very drunk) low things (15 cm up to about knee high, up to 0.7 m deep) are jumped on their own (`physics.c` hurdle / jumpOver): no slowing down before them (the run-up counts), off when the top of the jump comes over its middle, as high as it takes to clear it by 14 cm (feet tucked 18 cm) and long enough to land 25 cm past it, at most a full jump (else stepped over, slower); course test (jog / sprint): legs in obstacles about a third of before, joint jumps -30 %; running into something: trip or headlong over it if low, stagger back or fall to the side if high (speed, fitness, energy, clumsiness)
 - **Over obstacles**: lean into it, the leg swings out a little and back in; lift the foot first, then over; the body waits for the back leg; knee turns out, or the foot comes up; sprinting, leaps; careless people just step on small things; trips and scrapes by speed, height, condition
 - **Bushes**: trying to get over one ends in it, twigs snap
 - **Half way over something**: from when a foot is well into a step over something (lifted 12 cm+, 15 % into the step) until the body is over there (6 cm behind where that foot came down, at most 20 cm past it), you're crossing (`body.c` crossOver): stopping (or slower than 0.3 m/s) the body carries on over it at 0.6 m/s (`physics.c` carryOver); the foot over there stays down, the other comes after. Walking back takes you back. Standing still half over costs energy (2.5 %/s, a leg held up 6 %/s; less sporty, more); worn out, held longer than 1-6 s (fitness, energy) or legs over 0.95 m apart: you're made to go over; still stuck 1.5 s later: you fall (`world.c` halfOver)
@@ -154,4 +154,4 @@ Most important first.
 - The walking map rebuild takes ~9 ms when fixed things change (a felled tree)
 
 ---
-State of `entropie 1.56.0 (build efaf3bb)`
+State of `entropie 1.57.0 (build 3d7cb1a)`
diff --git a/entropie/commit_message.txt b/entropie/commit_message.txt
index e66251c..ae7addb 100644
--- a/entropie/commit_message.txt
+++ b/entropie/commit_message.txt
@@ -1,10 +1,7 @@
-entropie 1.56.0: careful people put tools back, practised ones cut even
+entropie 1.57.0: timed jumps over low things; no more collapsed sleepers
 
-- Done with a tool, careful people take it back to where it belongs (the
-  tool room); careless ones leave it lying where they stopped
-- The practised cut even pieces; the unpractised by eye (up to 0.2 m off)
-
-Includes 1.55.0 (if not committed separately):
-- Tools people shouldn't use (chainsaw unpractised, axe or saw drunk):
-  used anyway with close calls; "Leave the chainsaw alone" in talk; proud,
-  unwilling or drunk people may not listen
+- Jogging or faster, low things are jumped on their own: no slowing down
+  before them, the take-off timed so the top of the jump is over them, as
+  high as it takes (and long enough to land past them)
+- People lying down or passing out before ever facing anywhere no longer
+  collapse into a heap above the floor (no fall direction: on the back)
diff --git a/entropie/src/people/body.c b/entropie/src/people/body.c
index 3a75568..fd810c1 100644
--- a/entropie/src/people/body.c
+++ b/entropie/src/people/body.c
@@ -217,6 +217,8 @@ void Body_fall(Body *b, Vec3 dir) {
     b->fall_style = b->unsteadiness > 0.3f && r < 0.5f ? FALL_CRUMPLE : (r < 0.35f ? FALL_PLANK : (r < 0.7f ? FALL_TWIST : FALL_CRUMPLE));
     b->fall_twist = b->fall_style == FALL_TWIST ? (random01(b) - 0.5f) * 1.8f : (random01(b) - 0.5f) * 0.4f;
     b->fall_time  = FALL_TIME * (0.8f + 0.5f * random01(b)) * (b->fall_style == FALL_CRUMPLE ? 1.3f : 1.0f);
+    dir = flat(dir);
+    if (vec3_length(dir) < 1e-3f) dir = vec3_length(b->last_facing) > 1e-3f ? b->last_facing : vec3(0.0f, 0.0f, 1.0f); /* (no way given: forward) */
     dir = turnRight(vec3_normalize(dir), (random01(b) - 0.5f) * 0.6f);
     b->fall_delay = 0.0f;
     b->pose       = POSE_FALLING;
@@ -303,6 +305,7 @@ void Body_lieDown(Body *b) {
     b->pose       = POSE_LYING_DOWN;
     b->pose_time  = 0.0f;
     b->fall_dir   = vec3_scale(b->last_facing, -1.0f); /* sits down, then lies back */
+    if (vec3_length(b->fall_dir) < 1e-3f) b->fall_dir = vec3(0.0f, 0.0f, -1.0f); /* (never faced anywhere yet) */
     b->lie_offset = 0.0f;
     b->face_down  = false;
 }
diff --git a/entropie/src/people/body_pose.c b/entropie/src/people/body_pose.c
index 0b28cbe..b776a88 100644
--- a/entropie/src/people/body_pose.c
+++ b/entropie/src/people/body_pose.c
@@ -1338,7 +1338,9 @@ void Body_solve(Body *b, Vec3 position, Vec3 facing, float height, float dt, Ske
     solveStanding(b, position, facing, s, dt, out);
 
     if (b->pose != POSE_UP) {
-        Vec3 d = vec3_normalize(flat(Figure_toLocal(vec3_zero(), facing, b->fall_dir)));
+        Vec3 dl = flat(Figure_toLocal(vec3_zero(), facing, b->fall_dir));
+        /* (no way to fall known - down before ever facing anywhere: back, as when lying down) */
+        Vec3 d = vec3_length(dl) > 1e-3f && isfinite(dl.x) && isfinite(dl.z) ? vec3_normalize(dl) : vec3(0.0f, 0.0f, -1.0f);
         Skeleton lying = *out, kneeling = *out;
         solveLying(b, d, s, &lying);
         solveKneeling(&kneeling);
diff --git a/entropie/src/world/physics.c b/entropie/src/world/physics.c
index 757f24b..59223be 100644
--- a/entropie/src/world/physics.c
+++ b/entropie/src/world/physics.c
@@ -32,14 +32,18 @@
 #define STEP_OVER_LOOK      1.2f   /* how far ahead people look for it */
 #define LEG_WAIT            0.0f   /* m a standing leg may reach into something ... */
 #define LEG_WAIT_SPEED      0.05f  /* ... before the body waits (m/s) */
-#define HURDLE_SPEED        4.2f   /* m/s: sprinting ... */
-#define HURDLE_FIT          0.55f  /* ... and this sporty, ... */
-#define HURDLE_FROM         0.45f  /* ... something this far ahead (scaled) ... */
-#define HURDLE_TO           1.0f
-#define HURDLE_LOWEST       0.15f  /* ... at least this high ... */
-#define HURDLE_HIGHEST      0.5f   /* ... at most this high ... */
+#define JUMP_OVER_SPEED     2.9f   /* m/s: jogging or faster, something low ahead ... */
+#define HURDLE_LOWEST       0.15f  /* ... at least this high (scaled; lower: run over) ... */
 #define HURDLE_DEPTH        0.7f   /* ... and no deeper than this: jumped */
-#define HURDLE_POWER        0.7f   /* of a full jump */
+#define JUMP_LOOK           2.5f   /* (looked for this far ahead: no slowing down for it) */
+#define JUMP_CLEAR          0.14f  /* the feet this much over it ... */
+#define JUMP_TUCK           0.18f  /* ... tucked up this much in the air */
+#define JUMP_PAST           0.25f  /* landing this far past it */
+#define JUMP_MOST           1.05f  /* of a full jump at most */
+#define JUMP_EARLY          0.04f  /* m: take-off a touch early rather than late */
+
+static bool jumpOver(const Object *obj, const Object *o, Vec3 dir, float speed, float *v_up, float *center);
+static bool canJumpOver(const Object *obj, float speed);
 #define PERSON_EASE         0.008f /* m per step people standing into each other move apart at most */
 #define LAND_ON_MOST        0.12f  /* characters get onto loose things only from about this close above */
 
@@ -479,9 +483,12 @@ static Vec3 steppingOver(const Object *obj, Vec3 m, Object *const *objects, int
     const float s = obj->look.height / 1.75f;
     float most = 1e9f;
     bool near = false;
+    const bool jumper = canJumpOver(obj, speed);
     for (int i = 0; i < count; i++) {
         const Object *o = objects[i];
         if (!Physics_stepsOver(obj, o)) continue;
+        float jv, jc;
+        if (jumper && jumpOver(obj, o, dir, speed, &jv, &jc)) continue; /* (going to jump it: no slowing down, the run-up counts) */
         const Collider *c = &o->colliders[0];
         Vec3 rel = vec3_sub(Object_colliderCenter(o, 0), obj->position);
         rel.y = 0.0f;
@@ -518,26 +525,47 @@ static Vec3 steppingOver(const Object *obj, Vec3 m, Object *const *objects, int
     return vec3(m.x * most / speed, m.y, m.z * most / speed);
 }
 
-/* Sprinting, fit and fresh, at something low and narrow: in the flow, over
-   it in a leap (take-off a stride before it) instead of a high step. */
+/* Jogging or faster at something low and narrow: over it in a jump, timed
+   so the top of the jump is over it and as high as it takes (the feet tuck
+   up a little), the speed kept. Too high or too deep for that jump: no jump
+   (stepped over, slower). */
+static bool jumpOver(const Object *obj, const Object *o, Vec3 dir, float speed, float *v_up, float *center) {
+    /* (low for its own sake - uphill it may be a bit higher above your feet: the jump is higher) */
+    if (!obj->is_character || (o->weight < STEP_OVER_LIGHT && !o->is_static) || Physics_lowObstacle(o) <= 0.0f) return false;
+    const float s = obj->look.height / 1.75f;
+    const Collider *c = &o->colliders[0];
+    Vec3 rel = vec3_sub(Object_colliderCenter(o, 0), obj->position);
+    rel.y = 0.0f;
+    float reach = projectRadius(c, dir), side = projectRadius(c, vec3(-dir.z, 0.0f, dir.x));
+    float ahead = vec3_dot(rel, dir), beside = fabsf(rel.x * -dir.z + rel.z * dir.x);
+    float height = Object_colliderCenter(o, 0).y + projectRadius(c, WORLD_UP) - obj->position.y;
+    if (beside > side + 0.2f || ahead - reach < 0.05f * s || ahead - reach > JUMP_LOOK * s) return false;
+    if (height < HURDLE_LOWEST * s || 2.0f * reach > HURDLE_DEPTH * s) return false;
+    /* high enough to clear it, long enough to land past it */
+    float lift = fmaxf(height + (JUMP_CLEAR - JUMP_TUCK) * s, 0.1f * s);
+    float v = fmaxf(sqrtf(2.0f * GRAVITY * lift), GRAVITY * (reach + JUMP_PAST * s) / fmaxf(speed, 0.1f));
+    if (v > Object_jumpSpeed(obj) * JUMP_MOST) return false; /* (that jump isn't in them) */
+    *v_up = v;
+    *center = ahead;
+    return true;
+}
+
+static bool canJumpOver(const Object *obj, float speed) {
+    return speed >= JUMP_OVER_SPEED && obj->needs.stamina >= 0.15f && obj->drunk <= 0.6f &&
+           obj->hands.state[HAND_LEFT] != HAND_GRABBING && obj->hands.state[HAND_RIGHT] != HAND_GRABBING &&
+           !obj->body.airborne && obj->body.pose == POSE_UP && !obj->sitting && !obj->climbing && !obj->on_ladder;
+}
+
 static void hurdle(Object *obj, Object *const *objects, int count) {
     float speed = sqrtf(obj->movement.x * obj->movement.x + obj->movement.z * obj->movement.z);
-    if (speed < HURDLE_SPEED || obj->fitness < HURDLE_FIT || obj->needs.stamina < 0.35f || obj->drunk > 0.3f ||
-        obj->hands.state[HAND_LEFT] == HAND_GRABBING || obj->body.airborne) return;
+    if (!canJumpOver(obj, speed)) return;
     Vec3 dir = vec3(obj->movement.x / speed, 0.0f, obj->movement.z / speed);
-    const float s = obj->look.height / 1.75f;
     for (int i = 0; i < count; i++) {
-        const Object *o = objects[i];
-        if (!Physics_stepsOver(obj, o)) continue;
-        const Collider *c = &o->colliders[0];
-        Vec3 rel = vec3_sub(Object_colliderCenter(o, 0), obj->position);
-        rel.y = 0.0f;
-        float reach = projectRadius(c, dir), side = projectRadius(c, vec3(-dir.z, 0.0f, dir.x));
-        float ahead = vec3_dot(rel, dir), beside = fabsf(rel.x * -dir.z + rel.z * dir.x);
-        float edge = ahead - reach, height = 2.0f * projectRadius(c, WORLD_UP);
-        if (beside > side + 0.2f || edge < HURDLE_FROM * s || edge > HURDLE_TO * s) continue;
-        if (height < HURDLE_LOWEST * s || height > HURDLE_HIGHEST * s || 2.0f * reach > HURDLE_DEPTH * s) continue;
-        obj->velocity.y = Object_jumpSpeed(obj) * HURDLE_POWER;
+        float v, center;
+        if (!jumpOver(obj, objects[i], dir, speed, &v, &center)) continue;
+        /* off now: the top of the jump comes over its middle */
+        if (center > speed * v / GRAVITY + JUMP_EARLY) continue;
+        obj->velocity.y = v;
         obj->is_grounded = false;
         return;
     }