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/src/game/player.c raw
#include "game/player.h"
#define WALK_SPEED 2.2f /* brisk walk */
#define JOG_SPEED 3.6f /* Shift held */
#define TAP_TIME 0.6f /* Shift pressed again within this: faster */
#define TAP_BOOST 0.45f /* ... by this much of the way to a sprint */
#define BOOST_DECAY 0.8f /* per second with Shift up */
#define ACCELERATION 3.5f /* m/s per second speeding up */
#define DECELERATION 7.0f
#define RUN_JUMP_BONUS 0.25f /* a jump at full speed goes this much higher (take-off speed) */
#define CAREFUL_SPEED 4.4f /* carrying a chainsaw: no faster than this */
#define SIDEWAYS_FACTOR 0.65f /* side steps are slower than walking forward */
#define DRUNK_VEER 0.55f /* radians the walk direction wanders when very drunk */
#define DRUNK_SLOWDOWN 0.25f
/* Drunk people don't walk quite where they want to. */
static Vec3 veer(const Object *player, Vec3 move) {
float d = player->drunk;
if (d <= 0.0f) return move;
float t = player->body.clock;
float angle = (sinf(t * 0.7f) + 0.6f * sinf(t * 1.9f + 1.3f)) * DRUNK_VEER * d;
float c = cosf(angle), s = sinf(angle);
return vec3(move.x * c - move.z * s, move.y, move.x * s + move.z * c);
}
/* Speed the player wants: walking, jogging (Shift held) or sprinting (Shift
tapped again and again); eased so it never jumps from walk to sprint. */
static float runSpeed(Object *player, const Input *input, bool can_run, bool moving, float dt) {
player->tap_timer += dt;
if (input->sprint_tap) {
if (player->tap_timer < TAP_TIME) player->sprint_boost = fminf(1.0f, player->sprint_boost + TAP_BOOST);
player->tap_timer = 0.0f;
}
bool running = input->sprint && can_run && moving;
if (!running) player->sprint_boost = fmaxf(0.0f, player->sprint_boost - BOOST_DECAY * dt);
float top = fmaxf(Object_topSpeed(player), JOG_SPEED);
if (Hands_carries(player, OBJ_CHAINSAW)) top = fminf(top, CAREFUL_SPEED); /* careful with that */
float goal = running ? lerpf(JOG_SPEED, top, player->sprint_boost) : WALK_SPEED;
float speed = player->run_speed;
speed = goal > speed ? fminf(goal, speed + ACCELERATION * dt) : fmaxf(goal, speed - DECELERATION * dt);
player->run_speed = fmaxf(speed, WALK_SPEED * 0.5f);
return player->run_speed;
}
void Player_update(Object *player, const Input *input, const Camera *camera, float dt) {
/* The head follows where you look */
player->body.look_dir = camera->front;
player->body.look_weight = 1.0f;
player->body.urge = clampf(input->move_forward, 0.0f, 1.0f); /* W gets you up sooner after a fall */
if (Body_isBusy(&player->body) || player->on_ladder || player->riding) { /* (climbing: see the game; in the car) */
player->movement = vec3_zero();
player->move_local = vec3_zero();
return;
}
/* Move on the XZ plane. While grabbing, directions follow the grab heading
(forward pushes, backward pulls) instead of the camera. */
bool grabbing = Hands_isGrabbing(player);
Vec3 forward = grabbing ? player->hands.grab_heading
: vec3_normalize(vec3(camera->front.x, 0.0f, camera->front.z));
Vec3 right = vec3_normalize(vec3_cross(forward, vec3(0, 1, 0)));
Vec3 move = vec3_add(vec3_scale(forward, input->move_forward),
vec3_scale(right, input->move_right * SIDEWAYS_FACTOR));
/* Pushing, pulling or carrying with both hands slows you down */
bool busy = grabbing || Hands_moveFactor(player) < 1.0f;
/* too exhausted to run: until you got your breath back a bit (no on-off-on) */
static bool spent = false;
if (player->needs.stamina < 0.1f) spent = true;
else if (player->needs.stamina > 0.3f) spent = false;
bool can_run = !busy && !spent;
bool moving = input->move_forward != 0.0f || input->move_right != 0.0f;
float speed = runSpeed(player, input, can_run, moving, dt) * Hands_moveFactor(player) * Object_vigor(player);
speed *= 1.0f - DRUNK_SLOWDOWN * fminf(player->drunk, 1.0f);
float amount = fminf(vec3_length(move), 1.0f); /* sideways input stays slower */
if (!grabbing) move = veer(player, move);
player->movement = vec3_scale(vec3_normalize(move), speed * amount);
player->move_local = vec3(input->move_right, 0.0f, input->move_forward);
if (input->jump && player->is_grounded && !grabbing) {
/* Everybody jumps their own height; a run-up adds a little */
float run_up = clampf((player->run_speed - WALK_SPEED) / (CAREFUL_SPEED - WALK_SPEED), 0.0f, 1.0f);
player->velocity.y = Object_jumpSpeed(player) * (1.0f + RUN_JUMP_BONUS * run_up * amount);
player->is_grounded = false;
}
if (!player->sitting) /* sitting, the body stays put while you look around */
player->rotation.y = atan2f(forward.z, forward.x) + PI_F / 2.0f;
}