Let a texture frame set where a sprite stands for Y sorting (#228)
A sprite sorted by Y stood on the bottom of its box. With a shadow or empty rows under the feet that is too low, so a figure slipped in front of a tree it should stand behind. The line belongs to the frame, not the texture, because one texture can hold several sprite sheets. - New field `sortLine` on a frame: whole image pixels up from the frame's bottom edge, 0 to the frame height. 0 is stored as nothing, so old projects stay the same. Shrinking a frame keeps the line inside it. - `feetOf` in drawOrder.ts lifts a sprite by the same share of its box. Scene view, game view, play and picking all use it. In an animation the line of the frame shown right now counts. - The texture tab draws the selected frame's line dashed in yellow with a knob left of the frame. At 0 the line shares the bottom edge with the nine-slice border and a resize handle, so the knob is tested first. A line inside the frame can be dragged directly, tested after the nine-slice lines. - The inspector has a new "Sorting" section with a "Sort line" field. Dragging or typing is one undo step each. Limit: frames of one walk cycle need the same value, set by hand. Otherwise the figure changes its place in the order while walking. Tests: - ./check.sh: 160 files, 2356 tests, CHECK EXIT 0 (before 2350). - 6 new unit tests in tests/viewport/sort-by-y.test.ts. - e2e 37 and 39-43: ALL PASSED, 162 checks. New check 37b-ii drags the knob up 6 px and undoes it, plus the inspector row. - Counter checks: if feetOf ignores the line, exactly the 3 order tests fail. If the knob cannot be grabbed, 37b-ii fails. - The e2e sum in the README is 1380, counted, not yet seen in CI. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
50854389bb
commit
89048413f1
11 files changed
+334
-11
No files matched your search
@@ -49,9 +49,9 @@ interface Candidate extends DrawSlot {
|
||||
* piece. Symbols are left out, they are drawn above everything.
|
||||
*
|
||||
* Where a layer sorted by Y sits on a `z`, everything on that `z` is sorted by where it stands
|
||||
* (#228): an object by the bottom of its box, a row of the layer by the bottom of the row. Ties
|
||||
* keep the order above. A layer drawn as one piece and the map's own node stay behind them, in
|
||||
* that order, since neither has a single place to stand.
|
||||
* (#228): an object by the bottom of its box or by its frame's sort line, a row of the layer by the
|
||||
* bottom of the row. Ties keep the order above. A layer drawn as one piece and the map's own node
|
||||
* stay behind them, in that order, since neither has a single place to stand.
|
||||
*/
|
||||
export function drawSlots(items: readonly DrawItem[]): DrawSlot[] {
|
||||
const slots: Candidate[] = [];
|
||||
@@ -91,9 +91,17 @@ function standsOnY(slot: Candidate): boolean {
|
||||
return slot.row !== null || (slot.layerId === '' && slot.item.type !== 'tilemap');
|
||||
}
|
||||
|
||||
/** Where a slot stands, in world Y: the bottom of an object's box, or of a map's row. */
|
||||
/**
|
||||
* Where a slot stands, in world Y: the bottom of an object's box, or of a map's row. A sprite whose
|
||||
* frame has a sort line stands that share of its box higher up.
|
||||
*/
|
||||
function feetOf({ item, row }: Candidate): number {
|
||||
if (row === null) return footprintExtent(item.type, item.props, item.m, item.frame).bottom;
|
||||
if (row === null) {
|
||||
const box = footprintExtent(item.type, item.props, item.m, item.frame);
|
||||
const line = item.type === 'sprite' ? (item.texture?.sortLine ?? 0) : 0;
|
||||
const frameH = item.texture?.rect?.h ?? 0;
|
||||
return line > 0 && frameH > 0 ? box.bottom - (line / frameH) * (box.bottom - box.top) : box.bottom;
|
||||
}
|
||||
const bottom = cellOrigin(item.props, 0, row).y + tilemapTileSize(item.props);
|
||||
return item.m.ty + bottom * item.m.d;
|
||||
}
|
||||
Reference in new issue
Block a user