feat(0.3.0): Player als Actor-Entity (Phase A.6)

Refactor spine-prototype für player_control v0.2.0 + actor:
- composition.define_template{id="player", properties={position,
  movement_speed, sprite_color, sprite_w, sprite_h}, tags={"renderable"}}
- actor.create instanziiert Player bei map-center
- player_control.update(player, dt) ersetzt player.update(dt)
- camera.set_target / interaction.update lesen via actor.position(player)
  (Lua-multi-return)
- Manueller draw_rect für Player raus — Player wird via
  render.draw_entities{tag="renderable"} zusammen mit Sign gezeichnet
- Draw-order: stones zuerst, dann Entities (Sign + Player). Stones-vs-
  Player-Overlay-Issue in der Praxis nicht relevant (Positionen kollidieren
  nicht)

PLAYER_R/G/B Konstanten entfernt (Color jetzt im Template).

Bumps: 0.2.0 → 0.3.0; +actor v0.1.0; player_control 0.1.0 → 0.2.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Axel Meyer
2026-06-09 14:13:17 +00:00
parent fcf8f80b1e
commit 0227aad47d
2 changed files with 49 additions and 34 deletions

View File

@@ -1,12 +1,13 @@
local maps = require("lib-core.maps")
local r_lib = require("lib-core.render")
local camera = require("lib-core.camera")
local input = require("lib-core.input")
local player = require("lib-core.player_control")
local interaction = require("lib-core.interaction")
local selection = require("lib-core.selection")
local command = require("lib-core.command")
local composition = require("lib-core.composition")
local maps = require("lib-core.maps")
local r_lib = require("lib-core.render")
local camera = require("lib-core.camera")
local input = require("lib-core.input")
local player_control = require("lib-core.player_control")
local interaction = require("lib-core.interaction")
local selection = require("lib-core.selection")
local command = require("lib-core.command")
local composition = require("lib-core.composition")
local actor = require("lib-core.actor")
local demo_map = maps.load("maps/demo.map.json")
maps.set_current(demo_map)
@@ -57,12 +58,29 @@ camera.enable_pan_edge()
-- unsichtbar in follow-mode wegen set_target-override jeden Frame).
camera.set_pan_enabled("keys", false)
-- Configure player: defaults are 24x24 + 200 px/sec; place at map-center
local p_size = player.size()
player.set_position(map_center_x - p_size.w / 2, map_center_y - p_size.h / 2)
player.bind_movement("move_left", "move_right", "move_up", "move_down")
-- Player-Template (Phase A.5/A.6 — Actor + composition).
-- position is the visual CENTER per render.draw_entities convention.
composition.define_template{
id = "player",
properties = {
position = {x = 0, y = 0},
movement_speed = 200,
sprite_color = engine.render.rgb(200, 60, 80),
sprite_w = 24,
sprite_h = 24,
},
tags = {"renderable"},
}
local PLAYER_R, PLAYER_G, PLAYER_B = 200, 60, 80
-- Spawn the player at map-center; bind WASD movement.
local player = actor.create{
template = "player",
properties = {
position = {x = map_center_x, y = map_center_y},
movement_speed = 200,
},
}
player_control.bind_movement("move_left", "move_right", "move_up", "move_down")
-- Sign-Template (Phase A.1 — composition + Inactive-Entity-Pattern).
-- Position-Property is the visual CENTER per render.draw_entities convention.
@@ -116,10 +134,11 @@ function init(ctx)
local t = camera.target()
engine.print(string.format("camera: target=(%d,%d) zoom=%.2f", t.x, t.y, camera.zoom()))
engine.print(string.format("input: %d actions bound", input.action_count()))
local p = player.position()
local s = player.size()
local px, py = actor.position(player)
local sw = player:get_property("sprite_w")
local sh = player:get_property("sprite_h")
engine.print(string.format("player: pos=(%d,%d) size=%dx%d speed=%d",
p.x, p.y, s.w, s.h, player.speed()))
px, py, sw, sh, actor.movement_speed(player)))
-- Position + text are read once at registration; the sign is stationary
-- in v0.1 so a snapshot is correct. If it ever moves, the interaction-
@@ -154,18 +173,17 @@ function render(ctx)
engine.render.clear_color(engine.render.rgb(20, 20, 30))
camera.begin()
maps.draw_map_pre_entities()
-- draw all renderable entities (Phase A.2: tag-based render)
r_lib.draw_entities{ tag = "renderable" }
-- P.3.6: draw stones
-- P.3.6: draw stones (still Lua-tables; future-slice makes them
-- entities too)
for _, s in ipairs(stones) do
engine.render.draw_rect(s.x, s.y, s.w, s.h,
engine.render.rgb(s.color[1], s.color[2], s.color[3]))
end
-- draw player on top of map/stones
local p = player.position()
local sz = player.size()
engine.render.draw_rect(p.x, p.y, sz.w, sz.h,
engine.render.rgb(PLAYER_R, PLAYER_G, PLAYER_B))
-- Draw all renderable entities (Sign + Player). Drawn AFTER
-- stones so the Player visually overlays stone-occlusions —
-- in practice positions don't collide, but the layering
-- intent is preserved.
r_lib.draw_entities{ tag = "renderable" }
-- P.3.6: highlights over selected entities (world-space)
selection.render_highlights()
maps.draw_map_post_entities()
@@ -189,10 +207,8 @@ function update(ctx, dt)
-- Player + interaction nur in follow-mode (in free-cam ist player pausiert).
if not free_cam_mode then
player.update(dt)
local p = player.position()
local s = player.size()
interaction.update(p.x + s.w / 2, p.y + s.h / 2)
player_control.update(player, dt)
interaction.update(actor.position(player))
end
-- Pan-Summation jeden Frame (keys nur wenn enabled; drag + edge always-on).
@@ -202,9 +218,7 @@ function update(ctx, dt)
if not free_cam_mode then
-- Follow-cam: set_target jeden Frame -> drag/edge "drift" wird unsichtbar.
local p = player.position()
local s = player.size()
camera.set_target(p.x + s.w / 2, p.y + s.h / 2)
camera.set_target(actor.position(player))
end
-- CI-conditional self-exit (unverändert aus P.0):