feat(vagrant): spawn rock entity with pickup trigger

- Rock template (stack_mode=individual, tags=renderable+item) defined
  alongside backpack and vagrant_player templates.
- state.rock entity created in M.init using slot_00_isolated UV from
  the blob_rect_stone atlas (lib-asset.prototype-blob-geom); position
  (270, 400) — 80px left of the backpack.
- register_pickup(state.rock) wires an interaction trigger; existing
  render.draw_entities{tag="renderable"} draws the rock with no
  special-case render code.
- CI trace: engine.print("vagrant: rock_spawned") emitted once on init.
- Version bump 0.7.2 -> 0.7.3.
This commit is contained in:
Axel Meyer
2026-06-13 18:27:25 +02:00
parent f1e27d8183
commit f874813498
3 changed files with 68 additions and 7 deletions

View File

@@ -7,7 +7,7 @@ puppet control model: leg orientation decoupled from body via procedural
callback, foot-body-orientation ("tactical twist"), scale-deformation walk
cycle, and inheritance-decoupled foot sprites.
**Version:** 0.7.2
**Version:** 0.7.3
**Module-ID:** vagrant-skeleton
**Requires:** lib-core.input >=0.4.0, lib-core.camera >=0.3.0, lib-core.render >=0.1.0, lib-core.maps >=0.1.2, lib-core.puppet >=0.4.4, lib-core.interaction >=0.1.0, lib-asset.prototype-subterrain >=0.1.0
**Tags:** test-chamber, puppet, walking-sim, interaction
@@ -26,8 +26,11 @@ cycle, and inheritance-decoupled foot sprites.
- **Q** — drop most-recent item from backpack at player position + re-register pickup trigger
- **ESC** — return to launcher
> **Note:** Q (drop) and E (item pickup) are groundwork for B.4 (rock on ground) and
> B.5 (backpack-as-container) — not yet exercisable end-to-end until those slices land.
> **Note:** The world now contains a rock (near the backpack, 80px to its left). Walk up
> and press E to pick it up into the backpack; press Q to drop it back at your feet.
> Picking up the rock currently throws a loud error because the backpack is not yet a
> container — this confirms the pickup wiring is alive. Full pickup-into-backpack works
> once the backpack becomes a container (next slice).
## Demonstrates
@@ -79,6 +82,16 @@ cycle, and inheritance-decoupled foot sprites.
## CHANGELOG
### v0.7.3
- **Rock entity**: `composition.define_template{id="rock"}` added (stack_mode=individual,
tags=renderable+item). One rock entity spawned at (270, 400) — 80px left of the backpack.
Uses `slot_00_isolated` UV from the `blob_rect_stone` atlas (lib-asset.prototype-blob-geom).
`register_pickup(state.rock)` wires an interaction trigger so pressing E near the rock
fires the pickup callback. The callback calls `inventory.add(state.backpack, …)` which
errors until the backpack becomes a container (next slice) — the error confirms the wiring
is alive. `render.draw_entities{tag="renderable"}` (existing Phase A render path) draws
the rock without any special-case render code.
### v0.4.4
- **Sprint** (Shift+WASD): doubles `WALK_SPEED` (120 → 240) and walk-anim
`speed` (0.45 → 0.9). Mid-walk sprint toggle uses `puppet.set_play_speed`

View File

@@ -1,4 +1,4 @@
-- sporel-module-vagrant-skeleton v0.7.2
-- sporel-module-vagrant-skeleton v0.7.3
-- 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,
@@ -55,6 +55,22 @@ composition.define_template{
tags = {"renderable"},
}
-- Rock-Template: an item sitting in the world that the player can pick up.
-- sprite_atlas + sprite_uv are filled in M.init after the blob_rect_stone atlas
-- is loaded; placeholder defaults here keep the inert-declaration types correct.
-- slot_00_isolated is a standalone isolated stone tile — visually reads as a
-- single rock on the ground.
composition.define_template{
id = "rock",
properties = {
stack_mode = "individual", -- required by inventory-list
sprite_atlas = "",
sprite_uv = {x = 0, y = 0, w = 1, h = 1},
position = {x = 0, y = 0},
},
tags = {"renderable", "item"},
}
-- Player-Actor-Template (Phase A.6). Vagrant's player is an actor whose
-- position drives the puppet (sync each frame). NOT tagged renderable —
-- the puppet handles rendering, render.draw_entities doesn't see this
@@ -95,6 +111,7 @@ local state = {
world_tex = nil, -- subterrain_world atlas diffuse handle (used for bed/bench)
furniture_uvs = nil, -- name -> { x, y, w, h } from atlas JSON
backpack = nil, -- composition-entity, created in M.init after atlas load
rock = nil, -- composition-entity (item), created in M.init after blob_rect_stone load
-- Subterrain-style controller state:
walk_anim_current = nil, -- "walk_fwd_lower" / "walk_back_lower" / etc. (nil = idle_lower)
lower_control_rot_deg = 0,
@@ -310,6 +327,37 @@ function M.init(ctx)
},
}
-- Blob-rect-stone atlas: load JSON + diffuse texture for the rock sprite.
-- blob_rect_stone alias resolves to lib-asset.prototype-blob-geom. The
-- "slot_00_isolated" tile is the standalone isolated stone shape — reads as
-- a single rock on the ground. Separate atlas/texture from world atlas
-- (lib-core.render's atlas-cache de-duplicates on path, no wasted load).
local stone_lib = aliases.blob_rect_stone
local stone_base = stone_lib .. "/assets/atlases/blob_rect_stone"
local stone_atlas_png = stone_base .. "/tiles.diffuse.atlas.png"
local stone_meta = engine.asset.load_json(stone_base .. "/tiles.atlas.json")
local stone_uvs = {}
for _, t in ipairs(stone_meta.tiles) do
stone_uvs[t.name] = { x = t.uv[1], y = t.uv[2], w = t.uv[3], h = t.uv[4] }
end
-- Spawn Rock-Entity 80px to the left of the backpack so it sits in a
-- distinct position: visible to the player on first load, not overlapping
-- the backpack, reachable by walking left from spawn.
local ROCK_X, ROCK_Y = BACKPACK_X - 80, BACKPACK_Y
local rock_uv = stone_uvs["slot_00_isolated"]
state.rock = composition.create{
template = "rock",
properties = {
sprite_atlas = stone_atlas_png,
sprite_uv = {x = rock_uv.x, y = rock_uv.y,
w = rock_uv.w, h = rock_uv.h},
position = {x = ROCK_X, y = ROCK_Y},
},
}
register_pickup(state.rock)
if CI_FRAME_PERF then engine.print("vagrant: rock_spawned") end
-- Input bindings.
input.bind("walk_left", { "a" })
input.bind("walk_right", { "d" })
@@ -333,9 +381,9 @@ function M.init(ctx)
ctx.distance))
end)
-- CI trace: assets loaded count (3 atlas textures: player + tiles + world).
-- CI trace: assets loaded count (4 atlas textures: player + tiles + world + stone).
if CI_FRAME_PERF and not ci_assets_traced then
engine.print("vagrant: assets_loaded=3")
engine.print("vagrant: assets_loaded=4")
ci_assets_traced = true
end

View File

@@ -1,6 +1,6 @@
{
"id": "vagrant-skeleton",
"version": "0.7.2",
"version": "0.7.3",
"kind": "module",
"api": "^0.1",
"ci_frames": 60,