Merge pull request #1020 from ArmstrongThomas/agent/variable-size-overworld-sprites

Support variable-size anchored overworld sprites
This commit is contained in:
bryanthaboi
2026-08-10 14:09:13 -04:00
committed by GitHub
7 changed files with 250 additions and 42 deletions
+47
View File
@@ -428,16 +428,42 @@ local spriteReg = Registry.new("sprites", Schemas.REGISTRIES.sprites)
spriteReg:register("SPRITE_TITLE_LOGO",
{ image = "mods/logo/logo.png", frames = 1,
trueColor = true }, "logo_mod")
spriteReg:register("SPRITE_LARGE_ACTOR",
{ image = "mods/actor/actor.png", frames = 6,
walker = true, frameWidth = 32, frameHeight = 24,
anchorX = 16, anchorY = 24, trueColor = true },
"actor_mod")
local logoDef = spriteReg:get("SPRITE_TITLE_LOGO")
check(Schemas.check(Schemas.REGISTRIES.sprites, "sprites", "SPRITE_TITLE_LOGO",
logoDef, "register"),
"a trueColor sprites record validates against the catalog schema")
check(logoDef.trueColor == true, "and keeps the flag through the merge")
local largeDef = spriteReg:get("SPRITE_LARGE_ACTOR")
check(Schemas.check(Schemas.REGISTRIES.sprites, "sprites", "SPRITE_LARGE_ACTOR",
largeDef, "register"),
"a variable-size sprites record validates against the catalog schema")
Renderer:init()
local plainSprite = SpriteRenderer.new(
{ image = "assets/generated/sprites/red.png", frames = 1 })
local litSprite = SpriteRenderer.new(logoDef)
local largeSprite = SpriteRenderer.new(largeDef)
check(plainSprite.frameWidth == 16 and plainSprite.frameHeight == 16
and plainSprite.anchorX == 8 and plainSprite.anchorY == 16,
"legacy sprite definitions keep the vanilla frame geometry")
local frameGeometry = largeSprite:getFrameGeometry(5)
check(frameGeometry.frame == 5 and frameGeometry.x == 0
and frameGeometry.y == 120 and frameGeometry.width == 32
and frameGeometry.height == 24 and frameGeometry.anchorX == 16
and frameGeometry.anchorY == 24,
"frame geometry exposes a larger sheet rectangle and anchor")
local poseGeometry = largeSprite:getPoseGeometry("right", 1, true)
check(poseGeometry.frame == 5 and poseGeometry.mirror == true
and poseGeometry.quad == largeSprite.frames[5],
"pose geometry follows walker frame selection and right mirroring")
local originX, originY = largeSprite:getScreenOrigin(32, 32, 0, 0)
check(originX == 24 and originY == 20,
"a custom anchor keeps a larger sprite grounded at its cell")
Renderer:beginFrame(true)
check(#PaletteFX.trueColorRects("ui") == 0
@@ -471,6 +497,27 @@ check(#worldDrawn == 2, "the reported zone joins the world list endFrame blits")
check(worldDrawn[1].shader and worldDrawn[2].shader == false,
"the colorized pass runs first, then the sprite's rect with no shader")
-- Larger true-color frames claim their actual extent, and fishing's top-half
-- path reserves only the bottom 8-pixel tile for the overlay.
Renderer:beginFrame(true)
Renderer:beginWorldPass()
largeSprite:draw(32, 32, 0, 0, "down", 0, false)
local largeRects = PaletteFX.trueColorRects("world")
check(#largeRects == 1 and largeRects[1].x == 24 and largeRects[1].y == 20
and largeRects[1].w == 32 and largeRects[1].h == 24,
"a larger trueColor sprite reports its full anchored extent")
Renderer:endWorldPass()
Renderer:beginFrame(true)
Renderer:beginWorldPass()
largeSprite:draw(32, 32, 0, 0, "down", 0, false, true)
local topRects = PaletteFX.trueColorRects("world")
check(#topRects == 1 and topRects[1].h == 16
and largeSprite.halfFrames[0].y == 0
and largeSprite.halfFrames[0].h == 16,
"the fishing overlay keeps a larger frame's bottom tile clear")
Renderer:endWorldPass()
-- the same path on the UI canvas, which is where a full-color title logo
-- or menu portrait lands
Renderer:beginFrame(false)