From c4f2c9cda980a8298800372483e643bcebb5e6e3 Mon Sep 17 00:00:00 2001 From: Axel Meyer Date: Mon, 18 May 2026 23:46:23 +0200 Subject: [PATCH] feat(vagrant): sprint (shift+wasd) + backpack interaction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sprint: holding shift while WASD doubles player_speed (120 → 240) and walk-anim play-speed (0.45 → 0.9). Mid-walk sprint toggle uses puppet v0.4.4 set_play_speed → no cycle restart. Releasing shift or stopping WASD reverts to normal speed in next frame. Interaction: 'interact' bound to E. Proximity trigger registered on the backpack sprite at (350, 400) with range 40px. Pressing E within range fires callback that prints a log message with the actor distance. Uses existing lib-core.interaction (registered at init, polled by interaction.update(player.x, player.y) each frame). New dep: lib-core.interaction ^0.1.0. Module version 0.4.0 → 0.4.4 (syncs with puppet bump). --- init.lua | 73 ++++++++++++++++++++++++++++++++++++++----------- manifest.module | 5 ++-- 2 files changed, 60 insertions(+), 18 deletions(-) diff --git a/init.lua b/init.lua index 96eb82a..aa2fb01 100644 --- a/init.lua +++ b/init.lua @@ -1,20 +1,31 @@ --- sporel-module-vagrant-skeleton v0.4.0 +-- sporel-module-vagrant-skeleton v0.4.4 -- Sprite-mode test-chamber: 13-bone humanoid puppet + sprite-tilemap + -- hardcoded furniture. Subterrain-style puppet control model: --- multi-look-target (aim/soft), slerp body rotation, virtual lower_control bone, --- 4 directional walk animations, HandleAnimationLower port. +-- multi-look-target (aim/soft), slerp body rotation, hip-static legs, +-- foot-body-orientation. Sprint (shift+wasd) + interaction (E near +-- backpack) added v0.4.4. -local input = require("lib-core.input") -local camera = require("lib-core.camera") -local r_lib = require("lib-core.render") -local maps = require("lib-core.maps") -local puppet = require("lib-core.puppet") +local input = require("lib-core.input") +local camera = require("lib-core.camera") +local r_lib = require("lib-core.render") +local maps = require("lib-core.maps") +local puppet = require("lib-core.puppet") +local interaction = require("lib-core.interaction") local M = {} +-- Walk + sprint speed tunings. +local WALK_SPEED_NORMAL = 120 +local WALK_SPEED_SPRINT = 240 -- 2x +local ANIM_SPEED_NORMAL = 0.45 +local ANIM_SPEED_SPRINT = 0.9 -- 2x + +-- Furniture positions (matches M.draw hardcoded sprites). +local BACKPACK_X, BACKPACK_Y = 350, 400 +local INTERACTION_RANGE = 40 -- pixels + local state = { player = nil, - player_speed = 120, map = nil, bed_tex = nil, bench_tex = nil, @@ -24,6 +35,7 @@ local state = { lower_control_rot_deg = 0, move_x = 0, move_y = 0, + sprinting = false, -- shift+wasd = 2x speed + 2x anim } -- CI hook gating (mirrors Phase 1 convention). @@ -113,10 +125,11 @@ local function update_lower_anim(moving, move_x, move_y) end puppet.stop(state.player, "idle_lower") puppet.stop(state.player, "idle") - -- Slow walk to 0.4x substrate speed (user pref: still too fast at 0.5). - puppet.play(state.player, anim_id, { loop = true, speed = 0.45 }) + -- Play with current speed (normal or sprint). + local anim_speed = state.sprinting and ANIM_SPEED_SPRINT or ANIM_SPEED_NORMAL + puppet.play(state.player, anim_id, { loop = true, speed = anim_speed }) if not puppet.is_playing(state.player, "walk_upper") then - puppet.play(state.player, "walk_upper", { loop = true, speed = 0.45 }) + puppet.play(state.player, "walk_upper", { loop = true, speed = anim_speed }) end state.walk_anim_current = anim_id if CI_FRAME_PERF and ci_last_state ~= "walk" then @@ -187,8 +200,18 @@ function M.init(ctx) input.bind("walk_right", { "d" }) input.bind("walk_up", { "w" }) input.bind("walk_down", { "s" }) + input.bind("sprint", { "shift" }) -- held while walking → 2x speed + input.bind("interact", { "e" }) -- fires nearest proximity-trigger input.bind("quit_to_launcher", { "escape" }) + -- Proximity trigger on the backpack sprite (drawn at BACKPACK_X/Y in M.draw). + -- Range 40px; press E while within that radius to fire the callback. + interaction.register(BACKPACK_X, BACKPACK_Y, INTERACTION_RANGE, "interact", function(ctx) + engine.print(string.format( + "vagrant: interact with backpack (distance=%.1f)", + ctx.distance)) + end) + -- CI trace: assets loaded count (puppet+tilemap+furniture textures). if CI_FRAME_PERF and not ci_assets_traced then -- 7 puppet textures + 4 tile textures + 3 furniture textures = 14 @@ -215,6 +238,13 @@ function M.update(ctx, dt) if input.is_action_down("walk_down") then dy = dy + 1 end local moving = (dx ~= 0 or dy ~= 0) + -- Sprint = shift held + actually moving. Updated BEFORE move so the + -- selected speed matches; also feeds update_lower_anim's anim-speed + -- pick at walk-start transitions. + local sprint_held = input.is_action_down("sprint") + state.sprinting = moving and sprint_held + local current_walk_speed = state.sprinting and WALK_SPEED_SPRINT or WALK_SPEED_NORMAL + -- CI_DRIVE: synthetic scripted move (preserve existing P0-S25b semantics). if CI_DRIVE then ci_drive_frame = ci_drive_frame + 1 @@ -223,7 +253,7 @@ function M.update(ctx, dt) moving = true local pos = puppet.position(state.player) puppet.move_to(state.player, - pos.x + dx * state.player_speed * dt, pos.y) + pos.x + dx * WALK_SPEED_NORMAL * dt, pos.y) else moving = false end @@ -236,8 +266,8 @@ function M.update(ctx, dt) state.move_y = dy / len local pos = puppet.position(state.player) puppet.move_to(state.player, - pos.x + state.move_x * state.player_speed * dt, - pos.y + state.move_y * state.player_speed * dt) + pos.x + state.move_x * current_walk_speed * dt, + pos.y + state.move_y * current_walk_speed * dt) elseif not moving then state.move_x = 0 state.move_y = 0 @@ -251,14 +281,25 @@ function M.update(ctx, dt) update_lower_anim(moving, state.move_x, state.move_y) + -- Sprint toggle mid-walk: adjust play-speed of running anims without + -- restarting their cycle (puppet v0.4.4 set_play_speed). Silent no-op + -- if anim not currently playing. + local anim_speed = state.sprinting and ANIM_SPEED_SPRINT or ANIM_SPEED_NORMAL + puppet.set_play_speed(state.player, "walk_fwd_lower", anim_speed) + puppet.set_play_speed(state.player, "walk_upper", anim_speed) + -- Look-targets: head tracks raw mouse (aim), body tracks same for now (soft). local mx, my = engine.input.get_mouse_pos() local wx, wy = camera.screen_to_world(mx, my) puppet.set_look_target(state.player, "aim", wx, wy) puppet.set_look_target(state.player, "soft", wx, wy) - -- Camera follows puppet position each frame. + -- Interaction: dispatches the nearest matching proximity-trigger when + -- 'interact' was pressed this frame. Uses player.position as actor. local pos = puppet.position(state.player) + interaction.update(pos.x, pos.y) + + -- Camera follows puppet position each frame. camera.set_target(pos.x, pos.y) camera.update(dt) diff --git a/manifest.module b/manifest.module index 1cff4ab..220ac5a 100644 --- a/manifest.module +++ b/manifest.module @@ -1,6 +1,6 @@ { "id": "vagrant-skeleton", - "version": "0.4.0", + "version": "0.4.4", "kind": "module", "api": "^0.1", "ci_frames": 60, @@ -15,7 +15,8 @@ {"id": "lib-core.camera", "version": "0.3.0"}, {"id": "lib-core.render", "version": "0.1.0"}, {"id": "lib-core.maps", "version": "0.1.2"}, - {"id": "lib-core.puppet", "version": "0.4.3"}, + {"id": "lib-core.puppet", "version": "0.4.4"}, + {"id": "lib-core.interaction", "version": "0.1.0"}, {"id": "lib-asset.prototype-subterrain", "version": "0.1.1"} ] }