lib-core.player_control

P.0 player movement lib. Single player with top-left position + size + speed. Reads input direction via lib-core.input, applies 4-corner-AABB collision against lib-core.maps.is_walkable, all-or-nothing block (no wall-sliding).

  • Lib-ID: lib-core.player_control
  • Version: 0.1.0
  • Spec: meta/docs/superpowers/specs/2026-05-09-p0-lib-player_control-design.md

Forward-compat stubs (DEPRECATED-MVP) for wall-sliding, actor-integration, sprite-rendering, click-to-move, drag-select, animation, velocity/momentum, walls-collision, multi-player.

API

  • player.set_position(x, y) — top-left, pixel-coords
  • player.position() → {x, y} — top-left
  • player.set_size(w, h) — bounding box (default 24x24)
  • player.size() → {w, h}
  • player.set_speed(px_per_sec) — default 200
  • player.speed() → number
  • player.bind_movement(left_action, right_action, up_action, down_action)
  • player.update(dt) — reads bound actions, predicts next pos, AABB-collision-check, mutates position

Conventions

  • Position is top-left corner of player AABB (matches engine.render.draw_rect).
  • Center calculation lives in caller: cx = position.x + size.w/2.
  • All-or-nothing block on collision (no wall-sliding in P.0).
  • Module owns rendering (lib has no draw fn). Module composes camera-follow.
  • Silent no-op for update() before bind_movement (debug-friendly).
  • Lua error(...) for setter misuse (caller-bug fast-fail).

Consumer pattern

local player = require("lib-core.player_control")
local input  = require("lib-core.input")

input.bind("move_left",  { engine.input.KEY_A, engine.input.KEY_LEFT })
input.bind("move_right", { engine.input.KEY_D, engine.input.KEY_RIGHT })
input.bind("move_up",    { engine.input.KEY_W, engine.input.KEY_UP })
input.bind("move_down",  { engine.input.KEY_S, engine.input.KEY_DOWN })

player.set_position(244, 244)
player.bind_movement("move_left", "move_right", "move_up", "move_down")

function update(ctx, dt)
    player.update(dt)
    local p = player.position()
    local s = player.size()
    camera.set_target(p.x + s.w/2, p.y + s.h/2)  -- camera follows player center
end

function render(ctx)
    -- draw map first, then player on top
    local p = player.position()
    local s = player.size()
    engine.render.draw_rect(p.x, p.y, s.w, s.h, engine.render.rgb(200, 60, 80))
end
Description
P.0.lib.player_control � player movement + AABB-wall-collision
Readme 43 KiB
Languages
Lua 89.5%
Shell 10.5%