feat(vagrant): sprint (shift+wasd) + backpack interaction
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).
This commit is contained in:
73
init.lua
73
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 +
|
-- Sprite-mode test-chamber: 13-bone humanoid puppet + sprite-tilemap +
|
||||||
-- hardcoded furniture. Subterrain-style puppet control model:
|
-- hardcoded furniture. Subterrain-style puppet control model:
|
||||||
-- multi-look-target (aim/soft), slerp body rotation, virtual lower_control bone,
|
-- multi-look-target (aim/soft), slerp body rotation, hip-static legs,
|
||||||
-- 4 directional walk animations, HandleAnimationLower port.
|
-- foot-body-orientation. Sprint (shift+wasd) + interaction (E near
|
||||||
|
-- backpack) added v0.4.4.
|
||||||
|
|
||||||
local input = require("lib-core.input")
|
local input = require("lib-core.input")
|
||||||
local camera = require("lib-core.camera")
|
local camera = require("lib-core.camera")
|
||||||
local r_lib = require("lib-core.render")
|
local r_lib = require("lib-core.render")
|
||||||
local maps = require("lib-core.maps")
|
local maps = require("lib-core.maps")
|
||||||
local puppet = require("lib-core.puppet")
|
local puppet = require("lib-core.puppet")
|
||||||
|
local interaction = require("lib-core.interaction")
|
||||||
|
|
||||||
local M = {}
|
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 = {
|
local state = {
|
||||||
player = nil,
|
player = nil,
|
||||||
player_speed = 120,
|
|
||||||
map = nil,
|
map = nil,
|
||||||
bed_tex = nil,
|
bed_tex = nil,
|
||||||
bench_tex = nil,
|
bench_tex = nil,
|
||||||
@@ -24,6 +35,7 @@ local state = {
|
|||||||
lower_control_rot_deg = 0,
|
lower_control_rot_deg = 0,
|
||||||
move_x = 0,
|
move_x = 0,
|
||||||
move_y = 0,
|
move_y = 0,
|
||||||
|
sprinting = false, -- shift+wasd = 2x speed + 2x anim
|
||||||
}
|
}
|
||||||
|
|
||||||
-- CI hook gating (mirrors Phase 1 convention).
|
-- CI hook gating (mirrors Phase 1 convention).
|
||||||
@@ -113,10 +125,11 @@ local function update_lower_anim(moving, move_x, move_y)
|
|||||||
end
|
end
|
||||||
puppet.stop(state.player, "idle_lower")
|
puppet.stop(state.player, "idle_lower")
|
||||||
puppet.stop(state.player, "idle")
|
puppet.stop(state.player, "idle")
|
||||||
-- Slow walk to 0.4x substrate speed (user pref: still too fast at 0.5).
|
-- Play with current speed (normal or sprint).
|
||||||
puppet.play(state.player, anim_id, { loop = true, speed = 0.45 })
|
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
|
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
|
end
|
||||||
state.walk_anim_current = anim_id
|
state.walk_anim_current = anim_id
|
||||||
if CI_FRAME_PERF and ci_last_state ~= "walk" then
|
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_right", { "d" })
|
||||||
input.bind("walk_up", { "w" })
|
input.bind("walk_up", { "w" })
|
||||||
input.bind("walk_down", { "s" })
|
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" })
|
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).
|
-- CI trace: assets loaded count (puppet+tilemap+furniture textures).
|
||||||
if CI_FRAME_PERF and not ci_assets_traced then
|
if CI_FRAME_PERF and not ci_assets_traced then
|
||||||
-- 7 puppet textures + 4 tile textures + 3 furniture textures = 14
|
-- 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
|
if input.is_action_down("walk_down") then dy = dy + 1 end
|
||||||
local moving = (dx ~= 0 or dy ~= 0)
|
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).
|
-- CI_DRIVE: synthetic scripted move (preserve existing P0-S25b semantics).
|
||||||
if CI_DRIVE then
|
if CI_DRIVE then
|
||||||
ci_drive_frame = ci_drive_frame + 1
|
ci_drive_frame = ci_drive_frame + 1
|
||||||
@@ -223,7 +253,7 @@ function M.update(ctx, dt)
|
|||||||
moving = true
|
moving = true
|
||||||
local pos = puppet.position(state.player)
|
local pos = puppet.position(state.player)
|
||||||
puppet.move_to(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
|
else
|
||||||
moving = false
|
moving = false
|
||||||
end
|
end
|
||||||
@@ -236,8 +266,8 @@ function M.update(ctx, dt)
|
|||||||
state.move_y = dy / len
|
state.move_y = dy / len
|
||||||
local pos = puppet.position(state.player)
|
local pos = puppet.position(state.player)
|
||||||
puppet.move_to(state.player,
|
puppet.move_to(state.player,
|
||||||
pos.x + state.move_x * state.player_speed * dt,
|
pos.x + state.move_x * current_walk_speed * dt,
|
||||||
pos.y + state.move_y * state.player_speed * dt)
|
pos.y + state.move_y * current_walk_speed * dt)
|
||||||
elseif not moving then
|
elseif not moving then
|
||||||
state.move_x = 0
|
state.move_x = 0
|
||||||
state.move_y = 0
|
state.move_y = 0
|
||||||
@@ -251,14 +281,25 @@ function M.update(ctx, dt)
|
|||||||
|
|
||||||
update_lower_anim(moving, state.move_x, state.move_y)
|
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).
|
-- Look-targets: head tracks raw mouse (aim), body tracks same for now (soft).
|
||||||
local mx, my = engine.input.get_mouse_pos()
|
local mx, my = engine.input.get_mouse_pos()
|
||||||
local wx, wy = camera.screen_to_world(mx, my)
|
local wx, wy = camera.screen_to_world(mx, my)
|
||||||
puppet.set_look_target(state.player, "aim", wx, wy)
|
puppet.set_look_target(state.player, "aim", wx, wy)
|
||||||
puppet.set_look_target(state.player, "soft", 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)
|
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.set_target(pos.x, pos.y)
|
||||||
camera.update(dt)
|
camera.update(dt)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"id": "vagrant-skeleton",
|
"id": "vagrant-skeleton",
|
||||||
"version": "0.4.0",
|
"version": "0.4.4",
|
||||||
"kind": "module",
|
"kind": "module",
|
||||||
"api": "^0.1",
|
"api": "^0.1",
|
||||||
"ci_frames": 60,
|
"ci_frames": 60,
|
||||||
@@ -15,7 +15,8 @@
|
|||||||
{"id": "lib-core.camera", "version": "0.3.0"},
|
{"id": "lib-core.camera", "version": "0.3.0"},
|
||||||
{"id": "lib-core.render", "version": "0.1.0"},
|
{"id": "lib-core.render", "version": "0.1.0"},
|
||||||
{"id": "lib-core.maps", "version": "0.1.2"},
|
{"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"}
|
{"id": "lib-asset.prototype-subterrain", "version": "0.1.1"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user