Entropie git · main
Entropie festival game; first steps
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.gzentropie 1.62.0: smooth pull-ups (no joint jumps climbing up)
- The climb ends exactly where you then stand (no hop at the end), each foot lands on what's under it, the feet stay put instead of replanting - Feet come over the edge more slowly; the foot kept back from the face lets go gradually; knees ease out of the pull-up pose - An elbow swinging up over an edge and a hand taking hold blend in smoothly (they flipped at half way) - Audit walk (walks into a wall and climbs it): joint jumps 161 -> 58, the worst 22 -> 10 cm Includes 1.61.0 (if not committed separately): - A step ladder in the tool room: stands on its own, at a wall with its back to it; climb onto the wall from its top Includes 1.60.0 (if not committed separately): - A folding ladder (two 2.5 m halves on a hinge, 5 m open) beside the telescopic one; one click at a wall unfolds it and leans it there Includes 1.59.0 (if not committed separately): - Stepping up onto blocks above knee high; set moves and jumps only for things standing on the ground in front of you Includes 1.58.0 (if not committed separately): - Walking over knee-high things is one smooth set move that always finishes; at a run: jump up onto blocks, catch climbable edges
entropie/Makefile | 2 +- entropie/STATE.md | 6 +++--- entropie/commit_message.txt | 19 +++++++++++++------ entropie/src/game/game_actions.c | 34 +++++++++++++++++++++++++++------- entropie/src/people/body.h | 6 ++++-- entropie/src/people/body_pose.c | 34 +++++++++++++++++++++++----------- 6 files changed, 71 insertions(+), 30 deletions(-) diff --git a/entropie/Makefile b/entropie/Makefile index 81a5ea7..2c5dc21 100644 --- a/entropie/Makefile +++ b/entropie/Makefile @@ -1,5 +1,5 @@ APP := entropie -VERSION := 1.61.0 +VERSION := 1.62.0 PREFIX ?= /usr BINDIR ?= $(PREFIX)/bin diff --git a/entropie/STATE.md b/entropie/STATE.md index 0737850..275e788 100644 --- a/entropie/STATE.md +++ b/entropie/STATE.md @@ -84,7 +84,7 @@ Talk topics: offer, ask, suggest, where (new woodpile spot), ask for a hand, ask - **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) - **Sure-footedness**: one factor (`world.c`, unsure: ~0.2 sporty and careful .. ~1 average .. ~2.7 clumsy and unfit) scales every trip, slip, scrape and run-into, and how bad it gets; clumsy and unfit, you also stumble over your own feet jogging or running -- **Climbing**: hand on it (up to 1.35 m), hang and pull up (higher, both hands free), jump for the edge; ladder up and down, over the edge at the top. Walking up to something 0.7–2 m high, the hands go onto its edge first; pulling up, the feet push against the face below the edge, then the right knee and foot come over onto it, then the left (scripted in `game_actions.c`, climbFeet); knees bend up. A foot below the edge goes back until its (forward bent) knee is 8 cm clear of the face (`game_actions.c`, kneeClear); onto something low (under 1 m) the body rises quickly first, so the knee comes up above the edge. Walking up to anything higher than 0.5 m, the feet stay 0.35 m back from it (room for the knee; `body.c`, footSpot). Climb test: 0.8-1.5 m, walking or jumping, legs at most 5 cm into it (was 19 cm at 0.8 m). High pull-ups: pulled up till the arms press down (hips near the edge), then the knee comes up and you rise; the hands go on ahead onto the top and stay there, the back bends over the edge as far as it takes to keep them on it (body_pose.c, reach_bend). Jumping: holding Space (or W) grabs an edge the hands reach (about 2.4 m); up to 0.35 m higher, the fingertips touch it ("Just out of reach"); hands go up wide, then onto the edge +- **Climbing**: hand on it (up to 1.35 m), hang and pull up (higher, both hands free), jump for the edge; ladder up and down, over the edge at the top. Walking up to something 0.7–2 m high, the hands go onto its edge first; pulling up, the feet push against the face below the edge, then the right knee and foot come over onto it, then the left (scripted in `game_actions.c`, climbFeet); knees bend up. A foot below the edge goes back until its (forward bent) knee is 8 cm clear of the face (`game_actions.c`, kneeClear); onto something low (under 1 m) the body rises quickly first, so the knee comes up above the edge. Walking up to anything higher than 0.5 m, the feet stay 0.35 m back from it (room for the knee; `body.c`, footSpot). Climb test: 0.8-1.5 m, walking or jumping, legs at most 5 cm into it (was 19 cm at 0.8 m). High pull-ups: pulled up till the arms press down (hips near the edge), then the knee comes up and you rise; the hands go on ahead onto the top and stay there, the back bends over the edge as far as it takes to keep them on it (body_pose.c, reach_bend). Jumping: holding Space (or W) grabs an edge the hands reach (about 2.4 m); up to 0.35 m higher, the fingertips touch it ("Just out of reach"); hands go up wide, then onto the edge. Smooth pull-ups (audit walk: joint jumps 161 -> 58, the worst 22 -> 10 cm): the climb ends at the highest point under the body's footprint (where the physics stands you: no hop), each foot lands on what's under it, no replanting at the end (the feet are there already; body velocity zeroed: no stride ahead); feet over the edge over longer windows (lead 0.56-0.86, trail 0.74-1.0 of a high climb); kneeClear eases the foot back in 1 cm steps and lets go gradually as the knee comes over the top; the knee pole for pulling up eases in and out (`pull_knees`); an elbow swinging up over an edge blends between the two solves (no flip at half way); a hand taking hold eases out of the arm's "move out" (`arm_hold`) - **Drink and the rest**: sips, burps, sways, veers, sick, passes out, sleeps it off; pees (stream lands on the real ground, soaks in or puddles) - **Throwing**: underhand lob, overhand when wound up long enough - **Carrying one-handed**: hangs at the side by its top (a bag by its neck), wide things with the arm a little out; only long things (ladder, logs, axe) stop you at walls, bags and bottles squeeze by @@ -135,7 +135,7 @@ A cell grid of the site (2 m cells, `src/world/grid.c`, built once a frame) answ Most important first. **Bugs** -- Arms brushing past things while walking ease out of them at 2 m/s: a few more small joint jumps in the audit (walk 116 -> 161, the worst 21 cm; walking into a wall and climbing it is part of that run) +- Joint jumps left in the audit: jog+stop 191, sprint 373 (worst 28 cm), ladder 163 (27 cm) - running into things and the ladder climb; walk is down to 58 (10 cm) **Body and moving** - Obstacle approach, still to do: prefer a step in between on top of something stable (or unstable, if clumsy) over a long stride; NPCs: pull up or jump onto things on their own (the player does when running at them) @@ -160,4 +160,4 @@ Most important first. - The walking map rebuild takes ~9 ms when fixed things change (a felled tree) --- -State of `entropie 1.61.0 (build e870d0c)` +State of `entropie 1.62.0 (build 4e94661)` diff --git a/entropie/commit_message.txt b/entropie/commit_message.txt index 5ca9a15..b421ebf 100644 --- a/entropie/commit_message.txt +++ b/entropie/commit_message.txt @@ -1,10 +1,17 @@ -entropie 1.61.0: step ladder +entropie 1.62.0: smooth pull-ups (no joint jumps climbing up) -- A step ladder lies in the tool room, in front of the other two -- A click opens it and stands it in front of you; with a wall just ahead - it stands with its back to it, and from its top you climb onto the wall -- Climb it like the others (feet on the treads, hands on the top); - E / Q folds it up again +- The climb ends exactly where you then stand (no hop at the end), each + foot lands on what's under it, the feet stay put instead of replanting +- Feet come over the edge more slowly; the foot kept back from the face + lets go gradually; knees ease out of the pull-up pose +- An elbow swinging up over an edge and a hand taking hold blend in + smoothly (they flipped at half way) +- Audit walk (walks into a wall and climbs it): joint jumps 161 -> 58, + the worst 22 -> 10 cm + +Includes 1.61.0 (if not committed separately): +- A step ladder in the tool room: stands on its own, at a wall with its + back to it; climb onto the wall from its top Includes 1.60.0 (if not committed separately): - A folding ladder (two 2.5 m halves on a hinge, 5 m open) beside the diff --git a/entropie/src/game/game_actions.c b/entropie/src/game/game_actions.c index 96d75a6..22c398e 100644 --- a/entropie/src/game/game_actions.c +++ b/entropie/src/game/game_actions.c @@ -86,6 +86,17 @@ static bool startClimb(Game *game, float top, Vec3 probe) { Vec3 to = vec3(probe.x + f.x * 0.25f * s, top, probe.z + f.z * 0.25f * s); to.y = World_groundHeight(&game->world, to.x, to.z, top + 0.6f * s); /* (a sloping roof goes on up) */ if (to.y < top - 0.3f || to.y > top + 0.4f * s) to.y = top; + { /* (where the body will stand up there: the highest point under its footprint - no hop once up) */ + const Collider *pc = &p->colliders[0]; + float under = to.y; + for (int cx = -1; cx <= 1; cx += 2) + for (int cz = -1; cz <= 1; cz += 2) { + Vec3 q = vec3_add(to, vec3_add(vec3_scale(pc->axes[0], (float)cx * pc->half_extents.x), vec3_scale(pc->axes[2], (float)cz * pc->half_extents.z))); + float g = World_groundHeight(&game->world, q.x, q.z, to.y + 0.4f * s); + if (g > under && g < to.y + 0.3f * s) under = g; + } + to.y = under; + } game->climb_from = p->position; game->climb_to = to; @@ -127,16 +138,19 @@ static bool startClimb(Game *game, float top, Vec3 probe) { until the knee is clear of it. */ static float kneeClear(float along, float y, float root_along, float root_y, float face, float top, float s) { const float leg = KNEE_LEG * s, hip_a = root_along + 0.04f * s, hip_y = root_y + KNEE_HIP * s; - for (int k = 0; k < 14; k++, along -= 0.03f * s) { - float dx = along - hip_a, dy = y - hip_y, d = sqrtf(dx * dx + dy * dy); + float pushed = along, knee_y = top; + for (int k = 0; k < 42; k++, pushed -= 0.01f * s) { + float dx = pushed - hip_a, dy = y - hip_y, d = sqrtf(dx * dx + dy * dy); if (d < 1e-3f) continue; float h = d < 2.0f * leg ? sqrtf(leg * leg - 0.25f * d * d) : 0.0f; float px = dy / d, py = -dx / d; /* (perpendicular, the forward one) */ if (px < 0.0f) { px = -px; py = -py; } float ka = hip_a + 0.5f * dx + px * h, ky = hip_y + 0.5f * dy + py * h; - if (ka < face - KNEE_GAP * s || ky > top + 0.04f * s) break; + if (k == 0) knee_y = ky; + if (ka < face - KNEE_GAP * s) break; } - return along; + /* (the knee up over the top already: no need to keep the foot back - eased off, no jump) */ + return lerpf(pushed, along, smoothstepf(top - 0.08f * s, top + 0.06f * s, knee_y)); } static void climbFeet(Game *game, Object *p, float t, bool high, float s) { @@ -150,7 +164,7 @@ static void climbFeet(Game *game, Object *p, float t, bool high, float s) { for (int i = 0; i < 2; i++) { float sign = i == 0 ? -1.0f : 1.0f; bool lead = i == 1; /* (the right knee comes up first) */ - float u = high ? (lead ? smoothstepf(0.7f, 0.86f, t) : smoothstepf(0.84f, 0.98f, t)) /* (once the hips are up near the edge) */ + float u = high ? (lead ? smoothstepf(0.56f, 0.86f, t) : smoothstepf(0.74f, 1.0f, t)) /* (once the hips are up near the edge) */ : (lead ? smoothstepf(0.12f, 0.4f, t) : smoothstepf(0.5f, 0.85f, t)); /* below: under you, but in front of the face, no higher than just under the edge */ float along_below = fminf(root_along - 0.06f * s, face - (!high && top - ground < 1.0f * s && !lead ? LOW_BACK : 0.25f) * s); /* (the knees bend forward: room for them; low, the push-off foot further back) */ @@ -158,8 +172,13 @@ static void climbFeet(Game *game, Object *p, float t, bool high, float s) { /* on top: a little over the edge, or under you once you're up there */ float along_top = fmaxf(face + 0.2f * s, root_along); float y_top = top + 0.08f * s; + { /* (on what's right under that foot up there - the top isn't always level) */ + Vec3 q = vec3_add(a, vec3_add(vec3_scale(f, along_top), vec3_scale(side, sign * 0.11f * s))); + float g = World_groundHeight(&game->world, q.x, q.z, top + 0.3f * s); + if (g > top - 0.25f * s && g < top + 0.05f * s) y_top = g + 0.08f * s; + } /* up first (clear of the edge), then over */ - float up = smoothstepf(0.0f, 0.55f, u), across = smoothstepf(0.45f, 1.0f, u); + float up = smoothstepf(0.0f, 0.6f, u), across = smoothstepf(0.35f, 1.0f, u); if (top - ground < 1.0f * s) { /* low: up and over in one swing (the knee comes over the edge) */ up = smoothstepf(0.0f, 0.3f, u); across = smoothstepf(0.25f, 0.85f, u); @@ -254,7 +273,8 @@ void game_climb(Game *game, const Input *in, float dt) { if (t >= 1.0f) { p->climbing = false; p->is_grounded = true; - p->body.replant = true; /* up there: the feet stand on it (not left down below, through it) */ + /* (the feet are on it already - climbFeet - and stay put: no replanting, no jump) */ + p->body.velocity = vec3_zero(); /* (standing there, not a stride ahead) */ } return; } diff --git a/entropie/src/people/body.h b/entropie/src/people/body.h index 18dff96..83bf9f3 100644 --- a/entropie/src/people/body.h +++ b/entropie/src/people/body.h @@ -131,9 +131,10 @@ typedef struct { PushOutQuery push_out; /* ... and solid things (arms keep out of them) */ const void *clutter_ctx; float sulk; /* 0..1: annoyed (shows in the face; set by the world) */ - float lifted[JOINT_COUNT]; + float lifted[JOINT_COUNT]; /* down or sitting: how far each joint is lifted onto what it lies on (see Body_solve) */ Vec3 arm_out[2]; /* standing: how far each arm is moved out of what it would be in (figure space, eases) ... */ - float elbow_up[2]; /* ... and how far its elbow swings back over an edge its hand holds (0..1, eases) */ /* down or sitting: how far each joint is lifted onto what it lies on (see Body_solve) */ + float elbow_up[2]; /* ... how far its elbow swings back over an edge its hand holds (0..1, eases) ... */ + float arm_hold[2]; /* ... and whether its hand holds on there (0..1, eases: the hand isn't moved out with the arm) */ Vec3 at; /* where the body stands (last frame, world) ... */ float at_scale; /* ... and its size (height / reference height) */ bool limb_pole_ok[4]; @@ -164,6 +165,7 @@ typedef struct { bool asleep; bool replant; /* plant the feet again next update */ bool pulling_up; /* climbing up over an edge (on_ladder too): the legs still keep clear of it */ + float pull_knees; /* ... its knees up and out, eased (0..1) */ float reach_bend, reach_bend_v; /* ... and the back bends over as far as it takes to keep the hands on it */ float fitness; /* how sporty (0..1): runs smoother, steps over things surer */ float bob, bob_v; /* running: the body's rise and fall with each stride (sprung, -1..1) */ diff --git a/entropie/src/people/body_pose.c b/entropie/src/people/body_pose.c index b776a88..43611d8 100644 --- a/entropie/src/people/body_pose.c +++ b/entropie/src/people/body_pose.c @@ -518,6 +518,8 @@ static void solveStanding(Body *b, Vec3 position, Vec3 facing, float s, float dt vec3_scale(out->head_forward, 0.015f))); /* ----- Legs: IK from the hips to the planted / stepping feet ----- */ + /* (pulling up: knees up and out - eased in and out, so they don't swing over when it ends) */ + b->pull_knees += clampf((b->pulling_up ? 1.0f : 0.0f) - b->pull_knees, -3.0f * dt, 3.0f * dt); for (int side = 0; side < 2; side++) { float sign = side == 0 ? -1.0f : 1.0f; int hip = side == 0 ? JOINT_HIP_L : JOINT_HIP_R; @@ -542,7 +544,8 @@ static void solveStanding(Body *b, Vec3 position, Vec3 facing, float s, float dt Vec3 fd = vec3(tip.x - target.x, 0.0f, tip.z - target.z); fd = vec3_length(fd) > 0.02f ? vec3_normalize(fd) : vec3(0.0f, 0.0f, 1.0f); Vec3 pole = vec3_add(fd, vec3(sign * (0.06f - 0.3f * shy), 0.0f, 0.15f)); - if (b->pulling_up) { pole.y += 0.8f; pole.x += sign * 0.35f; } /* (getting up onto something: the knee comes up, not into it - and not into the other) */ + pole.y += 0.8f * b->pull_knees; + pole.x += sign * 0.35f * b->pull_knees; /* (getting up onto something: the knee comes up, not into it - and not into the other) */ twoBone(j[hip], target, THIGH, SHIN, pole, &j[hip + 1], &j[hip + 2]); j[hip + 3] = vec3_add(j[hip + 2], vec3_sub(tip, target)); /* foot keeps its shape if the leg can't reach */ } @@ -1282,7 +1285,7 @@ static void keepBodyOut(Body *b, Vec3 position, Vec3 facing, float s, float dt, static void keepArmsOut(Body *b, Vec3 position, Vec3 facing, float s, float dt, Skeleton *out) { if (b->pose != POSE_UP || !b->push_out) { - for (int k = 0; k < 2; k++) { b->arm_out[k] = vec3_zero(); b->elbow_up[k] = 0.0f; } + for (int k = 0; k < 2; k++) { b->arm_out[k] = vec3_zero(); b->elbow_up[k] = b->arm_hold[k] = 0.0f; } return; } Vec3 *j = out->joints; @@ -1304,6 +1307,7 @@ static void keepArmsOut(Body *b, Vec3 position, Vec3 facing, float s, float dt, } /* holding: the elbow swings back, up and out (the forearm over the edge); else the arm moves out */ float up_goal = holding && most > 0.0f ? 1.0f : 0.0f; + b->arm_hold[side] += clampf((holding ? 1.0f : 0.0f) - b->arm_hold[side], -6.0f * dt, 6.0f * dt); b->elbow_up[side] += clampf(up_goal - b->elbow_up[side], -4.0f * dt, 4.0f * dt); Vec3 goal = vec3_zero(); if (!holding && most > 0.0f) { @@ -1314,19 +1318,27 @@ static void keepArmsOut(Body *b, Vec3 position, Vec3 facing, float s, float dt, float dl = vec3_length(d); b->arm_out[side] = dl > step ? vec3_add(b->arm_out[side], vec3_scale(d, step / dl)) : goal; if (vec3_length(b->arm_out[side]) < 1e-4f && b->elbow_up[side] < 1e-3f) continue; - if (!holding) for (int k = 1; k <= 3; k++) j[sh + k] = vec3_add(j[sh + k], b->arm_out[side]); - else j[sh + 1] = vec3_add(j[sh + 1], b->arm_out[side]); /* (just taken hold: the hand stays, the elbow eases back in - no jump) */ + /* (taking hold: the hand goes to where it holds, the elbow eases back in - both eased, no jump) */ + Vec3 hand_out = vec3_scale(b->arm_out[side], 1.0f - b->arm_hold[side]); + j[sh + 1] = vec3_add(j[sh + 1], b->arm_out[side]); + j[sh + 2] = vec3_add(j[sh + 2], hand_out); + j[sh + 3] = vec3_add(j[sh + 3], hand_out); float l1 = UPPER_ARM * s, l2 = FOREARM * s; Vec3 tail = vec3_sub(j[sh + 3], j[sh + 2]); Vec3 pole = vec3_lerp(vec3_normalize(vec3_sub(j[sh + 1], j[sh])), vec3_normalize(vec3(sign * 0.45f, 0.6f, -0.65f)), b->elbow_up[side]); - Vec3 end; - if (b->elbow_up[side] > 0.5f) { /* (elbow up and back: its own way, folded or not) */ - Vec3 mid; - twoBone(j[sh], j[sh + 2], l1, l2, pole, &mid, &end); + /* elbow up and back: its own way, folded or not - blended in from the usual fit (no flip half way) */ + const float own = smoothstepf(0.3f, 0.7f, b->elbow_up[side]); + Vec3 own_mid = j[sh + 1], own_end = j[sh + 2], end = j[sh + 2]; + if (own > 0.0f) twoBone(j[sh], j[sh + 2], l1, l2, pole, &own_mid, &own_end); + if (own < 1.0f) end = refitLimb(j, sh, l1, l2, pole); + if (own > 0.0f) { + Vec3 mid = vec3_lerp(j[sh + 1], own_mid, own), e = vec3_lerp(end, own_end, own); + Vec3 u = vec3_sub(mid, j[sh]); + if (vec3_length(u) > 1e-4f) mid = vec3_add(j[sh], vec3_scale(u, l1 / vec3_length(u))); /* (bones keep their length) */ + Vec3 v = vec3_sub(e, mid); + if (vec3_length(v) > 1e-4f) e = vec3_add(mid, vec3_scale(v, l2 / vec3_length(v))); j[sh + 1] = mid; - j[sh + 2] = end; - } else { - end = refitLimb(j, sh, l1, l2, pole); + j[sh + 2] = end = e; } float tl = vec3_length(tail); if (tl > 1e-4f) j[sh + 3] = vec3_add(end, vec3_scale(tail, HAND * s / tl));