Builder Manual Play
Builder Manual / Player Module

PLAYER / Player Module

Player Module

Input, physics, animation, collisions, and player lifecycle in player.c.

Player Module


The player module is split across focused files under src/player/. player.h is the public API; player_internal.h holds private sprite/hitbox constants shared by implementation files.

FileRole
player.hPlayer struct, AnimState, public function declarations
player.cHigh-level player_update orchestration
player_lifecycle.cinit, render, hitbox, reset, cleanup, default physics
player_input.ckeyboard/gamepad intent, run state, climb input
player_motion.cacceleration, friction, counter-accel, air control
player_jump.cjump buffer, coyote time, jump cut
player_climb.cvine/ladder/rope grab detection and climbing helpers
player_surfaces.cfloor/platform/float-platform/bridge/bouncepad surface collision helpers
player_animation.canimation state selection and source frame updates

Lifecycle at a Glance

player_init
  ├── IMG_LoadTexture("assets/sprites/player/player.png")
  ├── 48x48 frame setup from 192x288 sheet (4 cols x 6 rows)
  ├── default spawn (overridden by LevelDef)
  └── player_apply_default_physics

per frame
  ├── player_handle_input        -> move_dir, run, jump/climb intent
  ├── player_update              -> jump buffer, motion, gravity, collisions, animation
  ├── player_render              -> draw current frame with camera offset
  └── player_get_hitbox          -> inset AABB for damage/collision checks

player_reset                     -> restore spawn/state; keep texture + tunable physics
player_cleanup                   -> SDL_DestroyTexture

Public API

int player_init(Player *player, SDL_Renderer *renderer);
void player_apply_default_physics(Player *player);
void player_handle_input(Player *player, Mix_Chunk *snd_jump,
                         SDL_GameController *ctrl,
                         const VineDecor *vines, int vine_count,
                         const LadderDecor *ladders, int ladder_count,
                         const RopeDecor *ropes, int rope_count);
void player_update(Player *player, float dt, Mix_Chunk *snd_jump,
                   const Platform *platforms, int platform_count,
                   const FloatPlatform *float_platforms, int float_platform_count,
                   const Bouncepad *bouncepads, int bouncepad_count,
                   const VineDecor *vines, int vine_count,
                   const LadderDecor *ladders, int ladder_count,
                   const RopeDecor *ropes, int rope_count,
                   const Bridge *bridges, int bridge_count,
                   const SpikePlatform *spike_platforms, int spike_platform_count,
                   const int *floor_gaps, int floor_gap_count,
                   int *out_bounce_idx,
                   int *out_fp_landed_idx,
                   int prev_fp_landed_idx,
                   int world_w);
void player_render(Player *player, SDL_Renderer *renderer, int cam_x);
SDL_Rect player_get_hitbox(const Player *player);
void player_reset(Player *player);
void player_cleanup(Player *player);

Initialization

ActionCurrent code
Textureassets/sprites/player/player.png
Sheet192×288 px, 4 columns × 6 rows
Frame48×48 px (PLAYER_FRAME_W/H)
Default spawnspawn_x = 80, spawn_y = FLOOR_Y - 2*TILE_SIZE + 16
Runtime spawnlevel_load may override from LevelDef.player_start_x/y
Physics defaultsplayer_apply_default_physics, then optional LevelDef overrides

player_init returns 0 after loading the required player texture and -1 if the texture cannot be loaded, allowing game_init to clean up the partially initialized runtime.

Default display size is 48×48 logical pixels. PLAYER_FLOOR_SINK = 16 sinks the frame into the floor to compensate for transparent sprite padding.


Movement Physics

Current movement uses acceleration and friction, not instant velocity reset.

Field / constantDefaultMeaning
walk_max_speed100.0 px/swalking cap
run_max_speed250.0 px/srunning cap
walk_ground_accel750.0 px/s²ground walk acceleration
run_ground_accel600.0 px/s²ground run acceleration
ground_friction550.0 px/s²braking with no input on ground
ground_counter_accel100.0 px/s²extra brake when reversing direction
air_accel_walk350.0 px/s²air control for walk jumps
air_accel_run180.0 px/s²reduced air control for run jumps
air_friction80.0 px/s²passive air drag with no input

LevelDef.physics can override these values; -1.0 keeps engine defaults and 0.0 is a valid override.


Jumping

ConstantValueMeaning
JUMP_VY−325.0 px/sjump impulse
JUMP_BUFFER_TIME0.10 spre-landing jump buffer
PLAYER_COYOTE_TIME0.10 spost-edge jump grace
JUMP_CUT_FACTOR0.45shorten jump when button released early

player_update receives snd_jump so buffered/coyote jumps can play the same guarded jump sound as direct jumps.


Climbables

The same climb state supports vines, ladders, and ropes.

ConstantValueMeaning
CLIMB_SPEED80.0 px/svertical climb speed
CLIMB_H_SPEED80.0 px/shorizontal drift while climbing
PLAYER_CLIMB_GRAB_PAD4 pxextra grab width around climbable art

Player.climb_source identifies the active climbable type: 0 = vine, 1 = ladder, 2 = rope.


Animation

player_animation.c selects an AnimState, then maps it to a linear frame index on the 4-column sheet.

StateFramesms/frameFirst frameSheet row
ANIM_IDLE415000
ANIM_WALK410041
ANIM_JUMP215082
ANIM_FALL1200123
ANIM_CLIMB2100164

Walk animation starts only when horizontal velocity exceeds WALK_ANIM_MIN_VX = 8.0f; this avoids foot-shuffling during tiny acceleration/friction speeds.


Hitbox

ConstantValueEffect
PLAYER_PHYS_PAD_X15 pxleft/right inset; physics width = 18 px
PLAYER_PHYS_PAD_TOP18 pxtop inset
PLAYER_FLOOR_SINK16 pxbottom inset/sink; physics height = 14 px
r.x = (int)player->x + PLAYER_PHYS_PAD_X;
r.y = (int)player->y + PLAYER_PHYS_PAD_TOP;
r.w = player->w - 2 * PLAYER_PHYS_PAD_X;
r.h = player->h - PLAYER_PHYS_PAD_TOP - PLAYER_FLOOR_SINK;

Sprite analysis confirms the art envelope fits this inset: visible art is roughly 18×16 px inside the 48×48 frame.