Procedural workbench redraws + 3-season tree variety

Workbenches: replace atlas sprites (which read as chest-of-drawers,
candle base, kitchen stove, cushion stack) with procedural _draw_ methods
following CremationPyre._draw_pyre's pattern. Carpenter shows a wood bench
with saw + log slabs; Smelter a stone furnace with smoking chimney; Hearth
a tall h=2 stone fireplace with arched opening + log fire; Millstone a
wood frame supporting a round grindstone wheel.

Trees: add Summer + Fall atlases alongside Spring (12 visual variants
from 4 silhouettes × 3 seasons). Selection hash mixes season independently
so neighbouring tiles don't all share the same palette.
This commit is contained in:
megaproxy 2026-05-15 20:22:55 +01:00
parent 840db55b44
commit c97ada80d7
6 changed files with 278 additions and 113 deletions

View file

@ -34,14 +34,23 @@ var chop_designated: bool = false
# Preloaded scene for spawned wood items.
const ITEM_SCENE: PackedScene = preload("res://scenes/entities/item.tscn")
## ElvGames Grasslands tree pack — 4 variants laid out left-to-right.
## Each variant is 64×80 px; trunk base sits in the bottom ~10 rows. We anchor
## the sprite center 32 px above tile origin so the trunk bottom lands at the
## tile's bottom edge and the canopy rises into the cells above.
const _TREE_TEX: Texture2D = preload("res://art/sprites/FG_Tree_Spring.png")
## ElvGames Grasslands tree pack — 4 silhouettes laid out left-to-right (64×80
## each). Trunk base sits in the bottom ~10 rows; we anchor the sprite centre
## 32 px above tile origin so the trunk bottom lands at the tile's bottom edge
## and the canopy rises into the cells above.
##
## Three season palettes (Spring / Summer / Fall) give 12 visual variants from
## the same silhouette set. Winter is omitted — snowy trees look out of place
## in the current biome. When a season-cycle system lands later, swap the
## active texture by season globally instead of per-tree.
const _TREE_TEXES: Array[Texture2D] = [
preload("res://art/sprites/FG_Tree_Spring.png"),
preload("res://art/sprites/FG_Tree_Summer.png"),
preload("res://art/sprites/FG_Tree_Fall.png"),
]
const _TREE_VARIANT_W: int = 64
const _TREE_VARIANT_H: int = 80
const _TREE_VARIANT_COUNT: int = 4
const _TREE_SILHOUETTES: int = 4 # silhouettes per atlas (columns)
# ── lifecycle ─────────────────────────────────────────────────────────────────
@ -55,16 +64,20 @@ func _ready() -> void:
World.register_tree(self)
## Adds a Sprite2D child painted with one of the 4 ElvGames tree variants.
## Variant chosen deterministically from the tile coord so the same tile always
## gets the same tree silhouette across boots and load/save.
## Adds a Sprite2D child painted with one of the 12 ElvGames tree variants
## (4 silhouettes × 3 season palettes). Variant chosen deterministically
## from the tile coord so the same tile always gets the same tree silhouette
## across boots and load/save.
func _build_sprite() -> void:
var sprite := Sprite2D.new()
sprite.name = "Sprite"
sprite.texture = _TREE_TEX
var hash_seed: int = tile.x * 31 + tile.y * 17
var silhouette: int = hash_seed % _TREE_SILHOUETTES
# Independent hash mix for season so neighbouring tiles don't all match.
var season: int = ((hash_seed / _TREE_SILHOUETTES) + tile.x * 7 + tile.y * 11) % _TREE_TEXES.size()
sprite.texture = _TREE_TEXES[season]
sprite.region_enabled = true
var variant: int = (tile.x * 31 + tile.y * 17) % _TREE_VARIANT_COUNT
sprite.region_rect = Rect2(variant * _TREE_VARIANT_W, 0, _TREE_VARIANT_W, _TREE_VARIANT_H)
sprite.region_rect = Rect2(silhouette * _TREE_VARIANT_W, 0, _TREE_VARIANT_W, _TREE_VARIANT_H)
sprite.centered = true
# Lift the sprite up so its bottom edge sits at the tile's bottom row.
# Sprite center is at offset.y; sprite half-height is _TREE_VARIANT_H/2 = 40.