feat(vagrant): backpack as inventory container — end-to-end pickup/drop demo
- Add container={kind="list"} to the backpack template so inventory.add
accepts it as a valid list-container
- Remove old backpack proximity-trigger (print-only callback, pre-B.5);
the rock's register_pickup is now the sole interaction trigger
- Emit unconditional inventory inspection trace after every add/remove:
backpack count + item reg-ids for user-facing demo feedback
- Add CI-gated tree-check traces: tree_check_after_pickup=ok and
tree_check_after_drop=ok verify composition-tree child placement
- Bump version 0.7.3 -> 0.8.0 across init.lua header, manifest.module,
and README
- README: rewrite Controls section into full demo walkthrough; add Demo
Walkthrough section; update Demonstrates + Interactions sections;
add v0.8.0 CHANGELOG entry
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
81
init.lua
81
init.lua
@@ -1,9 +1,9 @@
|
||||
-- sporel-module-vagrant-skeleton v0.7.3
|
||||
-- sporel-module-vagrant-skeleton v0.8.0
|
||||
-- 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, hip-static legs,
|
||||
-- foot-body-orientation. Sprint (shift+wasd) + interaction (E near
|
||||
-- backpack) added v0.4.4.
|
||||
-- pickup-item) added v0.4.4.
|
||||
--
|
||||
-- v0.6.0 (Phase A.4): Backpack promoted to composition-Entity (Atlas-UV
|
||||
-- render-path via render.draw_entities{tag="renderable"}). Bed + Bench
|
||||
@@ -15,6 +15,13 @@
|
||||
-- via puppet.move_to. Movement-Logic moves the actor; puppet renders.
|
||||
-- Untagged actor — render.draw_entities doesn't see it; puppet handles
|
||||
-- the render via puppet.render(state.player) unchanged.
|
||||
--
|
||||
-- v0.8.0: Backpack template gains container={kind="list"}.
|
||||
-- End-to-end pickup/drop loop: E on rock → inventory.add(backpack, rock)
|
||||
-- → rock disappears from draw_entities; Q → rock reappears at player
|
||||
-- position. engine.print shows inventory count + item-IDs after each
|
||||
-- add/remove. Tree-check (CI-gated) verifies child placement in
|
||||
-- composition tree.
|
||||
|
||||
local input = require("lib-core.input")
|
||||
local camera = require("lib-core.camera")
|
||||
@@ -37,11 +44,13 @@ local ANIM_SPEED_SPRINT = 0.9 -- 2x
|
||||
-- Furniture positions (Bed/Bench remain hardcoded for v0.1; Backpack
|
||||
-- promoted to Inactive-Entity via composition. Bed/Bench have no
|
||||
-- interaction-trigger and no demo-pflicht to be entities — they stay
|
||||
-- atlas-furniture until Phase B (container-on-bed) or similar triggers).
|
||||
-- atlas-furniture until a container-on-bed feature or similar triggers).
|
||||
local BACKPACK_X, BACKPACK_Y = 350, 400
|
||||
local INTERACTION_RANGE = 40 -- pixels
|
||||
|
||||
-- Backpack-Template (Phase A.4 — Atlas-UV render-path).
|
||||
-- v0.8.0: container={kind="list"} declared so the backpack receives
|
||||
-- items via inventory.add (capability-by-declaration).
|
||||
-- Real sprite_atlas + sprite_uv values are filled in M.init after the
|
||||
-- atlas-JSON is parsed; defaults here are placeholders so the inert-
|
||||
-- declaration types are correct (string + numbers).
|
||||
@@ -53,6 +62,7 @@ composition.define_template{
|
||||
position = {x = 0, y = 0},
|
||||
},
|
||||
tags = {"renderable"},
|
||||
container = { kind = "list" }, -- receives items via inventory.add
|
||||
}
|
||||
|
||||
-- Rock-Template: an item sitting in the world that the player can pick up.
|
||||
@@ -85,7 +95,7 @@ composition.define_template{
|
||||
tags = {}, -- intentionally untagged: not renderable
|
||||
}
|
||||
|
||||
-- Item-Template-Convention (Phase B):
|
||||
-- Item-Template-Convention:
|
||||
-- An "item" is a composition-template with:
|
||||
-- - properties.stack_mode = "individual" (required by inventory-list)
|
||||
-- - properties.sprite_atlas + sprite_uv (Atlas-UV render path)
|
||||
@@ -101,8 +111,8 @@ composition.define_template{
|
||||
-- re-parents it to the world at the player position, and re-registers a
|
||||
-- pickup-trigger at the new location.
|
||||
--
|
||||
-- Rock template (B.4) and container block on backpack (B.5) activate this
|
||||
-- convention end-to-end. B.3 establishes the glue only.
|
||||
-- Rock template (v0.7.3) and container block on backpack (v0.8.0) activate this
|
||||
-- convention end-to-end. The pickup/drop glue (v0.7.2) sets up the wiring.
|
||||
|
||||
local state = {
|
||||
player = nil, -- puppet handle (state-bearing for animation)
|
||||
@@ -138,7 +148,7 @@ local WALK_ANIMS = {"walk_fwd_lower", "walk_back_lower", "walk_left_lower", "wal
|
||||
-- When the player presses E within INTERACTION_RANGE, the item is moved
|
||||
-- into state.backpack via inventory.add (renderable-tag flips off) and
|
||||
-- the trigger is unregistered so the item no longer shows as interactable.
|
||||
-- Called by B.4 after placing the rock, and by drop-glue after relocation.
|
||||
-- Called after placing the rock, and by drop-glue after relocation.
|
||||
local function register_pickup(item)
|
||||
local x = item:get_property("position.x")
|
||||
local y = item:get_property("position.y")
|
||||
@@ -148,6 +158,27 @@ local function register_pickup(item)
|
||||
inventory.add(state.backpack, item)
|
||||
interaction.unregister(trigger_id)
|
||||
if CI_FRAME_PERF then engine.print("vagrant: event=pickup") end
|
||||
|
||||
-- Inventory inspection trace (unconditional — user-facing demo output).
|
||||
local count = inventory.count(state.backpack)
|
||||
local items = inventory.contents(state.backpack)
|
||||
local ids = {}
|
||||
for _, it in ipairs(items) do
|
||||
table.insert(ids, tostring(it:get_property("composition.reg_id")))
|
||||
end
|
||||
engine.print(string.format("vagrant: backpack count=%d items=[%s]",
|
||||
count, table.concat(ids, ",")))
|
||||
|
||||
-- Tree-check (CI-gated): verify the item was actually placed as a
|
||||
-- child of the backpack entity in the composition tree.
|
||||
if CI_FRAME_PERF then
|
||||
local found = false
|
||||
for slot_name, _ in pairs(state.backpack:get_children()) do
|
||||
if slot_name:match("^item%.%d+$") then found = true; break end
|
||||
end
|
||||
engine.print(string.format("vagrant: tree_check_after_pickup=%s",
|
||||
found and "ok" or "MISSING"))
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -368,18 +399,9 @@ function M.init(ctx)
|
||||
input.bind("drop", { "q" }) -- drop most-recent item from backpack
|
||||
input.bind("quit_to_launcher", { "escape" })
|
||||
|
||||
-- Proximity trigger on the backpack-Entity. Anchor read from the
|
||||
-- entity's position-Properties; sign is stationary so a snapshot is
|
||||
-- correct (interaction-API takes raw numbers, not closures, in v0.1).
|
||||
interaction.register(
|
||||
state.backpack:get_property("position.x"),
|
||||
state.backpack:get_property("position.y"),
|
||||
INTERACTION_RANGE, "interact",
|
||||
function(ctx)
|
||||
engine.print(string.format(
|
||||
"vagrant: interact with backpack (distance=%.1f)",
|
||||
ctx.distance))
|
||||
end)
|
||||
-- Note: no backpack proximity-trigger registered here. The backpack is now
|
||||
-- a container; interaction is driven by the rock's register_pickup
|
||||
-- trigger. The old backpack-print callback has been removed.
|
||||
|
||||
-- CI trace: assets loaded count (4 atlas textures: player + tiles + world + stone).
|
||||
if CI_FRAME_PERF and not ci_assets_traced then
|
||||
@@ -411,6 +433,27 @@ function M.update(ctx, dt)
|
||||
item:set_property("position.y", py)
|
||||
register_pickup(item)
|
||||
if CI_FRAME_PERF then engine.print("vagrant: event=drop") end
|
||||
|
||||
-- Inventory inspection trace (unconditional — user-facing demo output).
|
||||
local count = inventory.count(state.backpack)
|
||||
local items = inventory.contents(state.backpack)
|
||||
local ids = {}
|
||||
for _, it in ipairs(items) do
|
||||
table.insert(ids, tostring(it:get_property("composition.reg_id")))
|
||||
end
|
||||
engine.print(string.format("vagrant: backpack count=%d items=[%s]",
|
||||
count, table.concat(ids, ",")))
|
||||
|
||||
-- Tree-check (CI-gated): verify the backpack has no item.* children
|
||||
-- after drop (item was re-parented to world).
|
||||
if CI_FRAME_PERF then
|
||||
local found = false
|
||||
for slot_name, _ in pairs(state.backpack:get_children()) do
|
||||
if slot_name:match("^item%.%d+$") then found = true; break end
|
||||
end
|
||||
engine.print(string.format("vagrant: tree_check_after_drop=%s",
|
||||
found and "MISSING" or "ok"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user