Fix black wall tops, pillar art, player anchor, and whole-sheet bullets
ci / verify (push) Successful in 46s
ci / verify (push) Successful in 46s
Bullets rendered as the entire sprite sheet, which was the clue that named the cause: a MultiMeshInstance2D cannot show a sub-region of a texture. Its mesh UVs run 0..1 across whatever texture it is handed, and an AtlasTexture does not help -- the draw resolves to the underlying atlas and the region is discarded. Frames are now pre-sliced into 32 standalone 16x16 textures at startup, so each frame is one texture assignment per kind and no region is involved. My previous two attempts fixed the atlas contents while the renderer was structurally incapable of showing one cell of it. Black voids above walls: wall_top_mid has 12 of its 16 rows transparent. It is a cap meant to be laid over a wall, not a tile, and drawn alone it was three quarters nothing. Floor is now drawn beneath every tile so transparency shows ground rather than clear colour, the wall face is drawn from the opaque wall_mid, and the cap is overlaid only where open floor lies above. Pillars used a wall segment and read as stray blocks; they now use the column tile, which looks like something you walk around. The player hitbox appeared at the head because it was: the knight occupies rows 8..27 of a 28-row cell, so anchoring on the cell centre put the draw origin about 4px above the body's centre. Added a per-sprite anchor offset that cancels it, with a test that recomputes the offset from the art so a re-cut sheet fails rather than silently misplacing the character. Tests pin the two tileset facts that caused this: the cap is mostly transparent (so it may never be drawn alone) and the wall face is fully opaque (so it may). 166 tests. check.sh, test.sh and smoke.sh pass.
This commit is contained in:
1 parent
801f328093
commit
ff5e527ad4
4 files changed
+117
-22
No files matched your search
+30
-10
@@ -20,6 +20,8 @@ const _FALLBACK_COLOURS: Array[Color] = [
|
||||
]
|
||||
|
||||
var _layers: Array[MultiMeshInstance2D] = []
|
||||
## [kind][frame] -> standalone texture. See _slice_frames().
|
||||
var _frames: Array[Array] = []
|
||||
## Advances the bullets' own animation, independent of the simulation.
|
||||
var _anim_time: float = 0.0
|
||||
## True when the licence-restricted bullet sheet is absent and we are drawing
|
||||
@@ -32,6 +34,9 @@ func _ready() -> void:
|
||||
_fallback = sheet == null
|
||||
var art: Texture2D = sheet if sheet != null else _make_dot_texture()
|
||||
var kinds := SimConfig.KIND_HEAVY + 1
|
||||
if not _fallback:
|
||||
_slice_frames(sheet, kinds)
|
||||
art = _frames[0][0]
|
||||
if _fallback:
|
||||
GameLog.info("view", "bullet sheet absent, drawing generated dots")
|
||||
var quad := QuadMesh.new()
|
||||
@@ -72,18 +77,33 @@ func _make_dot_texture() -> ImageTexture:
|
||||
return ImageTexture.create_from_image(img)
|
||||
|
||||
|
||||
## Point each layer's texture at this frame's row/column in the atlas. Every
|
||||
## bullet in a layer shares the frame, so this is one region assignment per kind
|
||||
## rather than any per-instance work.
|
||||
## Slice the atlas into one standalone texture per (kind, frame).
|
||||
##
|
||||
## A MultiMeshInstance2D cannot show a sub-region of a texture. Its mesh UVs run
|
||||
## 0..1 across whatever texture it is given, and handing it an AtlasTexture does
|
||||
## not help -- the draw resolves to the underlying atlas and the region is
|
||||
## ignored, so every bullet rendered as the entire sheet. Pre-slicing costs 32
|
||||
## tiny textures once at startup and makes each frame a single assignment.
|
||||
func _slice_frames(sheet: Texture2D, kinds: int) -> void:
|
||||
var img := sheet.get_image()
|
||||
for kind in kinds:
|
||||
var per_kind: Array[Texture2D] = []
|
||||
for f in Art.BULLET_FRAMES:
|
||||
var r := Art.bullet_region(kind, f)
|
||||
var cell := Image.create(int(r.size.x), int(r.size.y), false, img.get_format())
|
||||
cell.blit_rect(img, Rect2i(r), Vector2i.ZERO)
|
||||
per_kind.append(ImageTexture.create_from_image(cell))
|
||||
_frames.append(per_kind)
|
||||
|
||||
|
||||
## Swap each layer to this frame's texture. One assignment per kind per frame;
|
||||
## every bullet in a layer shares it, so there is no per-instance work.
|
||||
func _apply_frame() -> void:
|
||||
var frame_index := int(_anim_time / Art.BULLET_FRAME_SECONDS)
|
||||
if _frames.is_empty():
|
||||
return
|
||||
var f := int(_anim_time / Art.BULLET_FRAME_SECONDS) % Art.BULLET_FRAMES
|
||||
for kind in _layers.size():
|
||||
var atlas := _layers[kind].texture as AtlasTexture
|
||||
if atlas == null:
|
||||
atlas = AtlasTexture.new()
|
||||
atlas.atlas = Art.bullets_texture()
|
||||
_layers[kind].texture = atlas
|
||||
atlas.region = Art.bullet_region(kind, frame_index)
|
||||
_layers[kind].texture = _frames[kind][f]
|
||||
|
||||
|
||||
func render_pool(pool: BulletPool) -> void:
|
||||
|
||||
Reference in new issue
Block a user