feat: modeled market stalls, mega wall ads, traffic lights, awnings
Final detail pass — no gameplay object remains a plain box: - Markets: box stalls replaced with modeled kit stalls (4 styles seeded), hidden box colliders keep the wood acoustics; hand carts at the market mouths; standing lanterns between stalls - Shrines: hanging lanterns on the stone pillars, wooden fences flanking the torii approach - Towers: giant mid-height wall ads on the street faces (the anime-city mega-ad look), on top of crown boards and corner columns - Storefront awnings (kit detail piece) on ~40% of buildings - Traffic signals at every central-avenue crossing, diagonal from the streetlights - Fantasy Town Kit (CC0) installed at assets/props/town Verified via street capture (wall-scale glyph ads, pharmacy signs, banner ads, stalls, carts); movement 11/11, smoke 0, acoustics PASSED. Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
co-authored by
Claude Fable 5
parent
648872a16d
commit
c8a85586bd
@@ -0,0 +1,28 @@
|
||||
|
||||
|
||||
Fantasy Town Kit (2.0)
|
||||
|
||||
Created/distributed by Kenney (www.kenney.nl)
|
||||
Creation date: 03-08-2025 13:56
|
||||
|
||||
------------------------------
|
||||
|
||||
License: (Creative Commons Zero, CC0)
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
You can use this content for personal, educational, and commercial purposes.
|
||||
|
||||
Support by crediting 'Kenney' or 'www.kenney.nl' (this is not a requirement)
|
||||
|
||||
------------------------------
|
||||
|
||||
• Website : www.kenney.nl
|
||||
• Donate : www.kenney.nl/donate
|
||||
|
||||
• Patreon : patreon.com/kenney
|
||||
|
||||
Follow on social media for updates:
|
||||
|
||||
• Twitter: twitter.com/KenneyNL
|
||||
• BlueSky: kenney.bsky.social
|
||||
• Instagram: instagram.com/kenney_nl
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -177,6 +177,10 @@ func _kit_fill_side(front_x: float, dir: int, z0: float, z1: float, seed_id: Str
|
||||
var h: float = KIT_BUILDINGS[key].y * KIT_SCALE
|
||||
_kit_building(key, Vector3(front_x, 0, zc), yaw, "K%s_%d" % [seed_id, idx])
|
||||
var face_yaw := -90.0 if dir > 0 else 90.0 # ad quads face the street
|
||||
# Storefront awning on some buildings (kit detail piece)
|
||||
if _rng.randi() % 5 < 2:
|
||||
_kit_prop_path(KIT_DIR + "detail-awning-wide.glb",
|
||||
Vector3(front_x, 3.1, zc), face_yaw, minf(w * 0.9, 11.0))
|
||||
# Street-level posters plastered on the facade (graphic density)
|
||||
var posters := 1 + _rng.randi() % 3
|
||||
for p in posters:
|
||||
@@ -467,6 +471,10 @@ func _tower_block(c: Vector3, bx: int, bz: int) -> void:
|
||||
_box_static(c + Vector3(0, h + 2.4, 0), Vector3(0.6, 4.0, tw - 4.0), METAL, n + "_Crown", "metal")
|
||||
_ad_quad(c + Vector3(0.42, h + 2.4, 0), Vector2(tw - 4.6, 3.3), 90.0, _board_tex())
|
||||
_ad_quad(c + Vector3(-0.42, h + 2.4, 0), Vector2(tw - 4.6, 3.3), -90.0, _board_tex())
|
||||
# Giant mid-height wall ad on the tower's street faces (ZZZ-style)
|
||||
var wall_off := dims.z * s * 0.5 + 0.15
|
||||
_ad_quad(c + Vector3(0, FLOOR_H + dims.y * s * 0.45, -wall_off).rotated(Vector3.UP, deg_to_rad(yaw)),
|
||||
Vector2(tw * 0.55, tw * 0.8), yaw + 180.0, _poster_tex())
|
||||
_spawn_points.append(c + Vector3(0, FLOOR_H + 1.5, (BLOCK - 4.0) * 0.4))
|
||||
|
||||
|
||||
@@ -492,14 +500,18 @@ func _shrine_block(c: Vector3, bx: int, bz: int) -> void:
|
||||
# Hall with slide roof
|
||||
_box_static(c + Vector3(0, 2.0, -10.0), Vector3(12.0, 4.0, 8.0), WOOD.darkened(0.2), n + "_Hall", "wood")
|
||||
_ramp_static(c + Vector3(0, 4.9, -8.2), Vector3(13.0, 0.3, 5.6), Vector3(-24, 0, 0), VERMILION.darkened(0.35), n + "_Roof", "wood")
|
||||
# Stone lanterns + real modeled trees (trunk collider under each)
|
||||
# Stone + hanging lanterns, wooden gate fence, real modeled trees
|
||||
for i in 2:
|
||||
var lx := -8.0 + 16.0 * float(i)
|
||||
_box_static(c + Vector3(lx, 1.0, 8.0), Vector3(1.0, 2.0, 1.0), Color(0.55, 0.55, 0.52), n + "_Lant%d" % i, "brick")
|
||||
_kit_prop_path("res://assets/props/town/lantern.glb", c + Vector3(lx, 2.0, 8.0), 0.0, 2.6)
|
||||
_box_static(c + Vector3(lx, 1.6, -2.0), Vector3(0.8, 3.2, 0.8), TRUNK, n + "_Trunk%d" % i, "wood")
|
||||
_kit_prop_path("res://assets/props/nature/" + ["tree_detailed.glb", "tree_default.glb"][i % 2],
|
||||
c + Vector3(lx, 0, -2.0), _rng.randf_range(0.0, 360.0), 7.0)
|
||||
_kit_prop_path("res://assets/props/nature/tree_oak.glb", c + Vector3(0, 0, 2.0), _rng.randf_range(0.0, 360.0), 6.0)
|
||||
# Fence gate flanking the torii approach
|
||||
_kit_prop_path("res://assets/props/town/fence.glb", c + Vector3(-8.0, 0.15, tz - 0.2), 0.0, 3.0)
|
||||
_kit_prop_path("res://assets/props/town/fence.glb", c + Vector3(8.0, 0.15, tz - 0.2), 0.0, 3.0)
|
||||
_spawn_points.append(c + Vector3(0, 1.5, 12))
|
||||
|
||||
|
||||
@@ -513,17 +525,26 @@ func _market_block(c: Vector3, bx: int, bz: int) -> void:
|
||||
for pi in 3:
|
||||
var pp := c + Vector3(_rng.randf_range(-9.0, 9.0), 0.1, _rng.randf_range(-12.0, 12.0))
|
||||
_kit_prop(["detail-parasol-a", "detail-parasol-b"][pi % 2], pp, _rng.randf_range(0.0, 360.0), 6.0)
|
||||
# Stall rows down the middle
|
||||
# Modeled stall rows down the middle (kit stalls + carts, box colliders)
|
||||
var stall_keys := ["stall", "stall-green", "stall-red", "stall-bench"]
|
||||
for r in 2:
|
||||
var x := c.x + (-5.0 if r == 0 else 5.0)
|
||||
for s in 4:
|
||||
var z := c.z - 15.0 + float(s) * 10.0
|
||||
_box_static(Vector3(x, 1.0, z), Vector3(3.2, 2.0, 2.2), WOOD, "%s_S%d_%d" % [n, r, s], "wood")
|
||||
_box_static(Vector3(x, 2.35, z), Vector3(4.0, 0.16, 3.0),
|
||||
SIGN_COLORS[(r + s) % SIGN_COLORS.size()].darkened(0.5), "%s_C%d_%d" % [n, r, s], "wood")
|
||||
var body := _box_static(Vector3(x, 1.3, z), Vector3(3.4, 2.6, 3.0), WOOD, "%s_S%d_%d" % [n, r, s], "wood")
|
||||
for mi in body.find_children("*", "MeshInstance3D", false, false):
|
||||
mi.visible = false # collider only; the kit stall is the visual
|
||||
_kit_prop_path("res://assets/props/town/%s.glb" % stall_keys[(r * 4 + s + bx) % stall_keys.size()],
|
||||
Vector3(x, 0.02, z), 90.0 if r == 0 else -90.0, 3.2)
|
||||
if s % 2 == 0:
|
||||
_kit_prop_path("res://assets/props/town/lantern.glb",
|
||||
Vector3(x + 2.2, 0.02, z + 1.8), 0.0, 3.0)
|
||||
# Lantern string over each row
|
||||
for l in 6:
|
||||
_deco_box(Vector3(x, 3.6, c.z - 17.5 + float(l) * 7.0), Vector3(0.32, 0.45, 0.32), Color(1.0, 0.62, 0.25), true)
|
||||
# Hand carts at the market mouths
|
||||
_kit_prop_path("res://assets/props/town/cart.glb", c + Vector3(0, 0.02, 19.0), _rng.randf_range(-30, 30), 3.0)
|
||||
_kit_prop_path("res://assets/props/town/cart-high.glb", c + Vector3(2.0, 0.02, -19.0), _rng.randf_range(150, 210), 3.0)
|
||||
# Vending pair at the north entry
|
||||
for v in 2:
|
||||
_box_static(c + Vector3(-1.5 + 3.0 * float(v), 1.0, -BLOCK * 0.5 + 3.0), Vector3(1.1, 2.0, 0.9),
|
||||
@@ -700,6 +721,9 @@ func _build_avenues() -> void:
|
||||
_box_static(Vector3(x, 3.4, z), Vector3(0.26, 6.8, 0.26), METAL, "LampP_%d_%d" % [int(z), int(side)], "metal")
|
||||
_kit_prop_path("res://assets/props/roads/light-curved.glb",
|
||||
Vector3(x, 0, z), 90.0 if side > 0 else -90.0, lamp_scale)
|
||||
# Traffic signal on the opposite diagonal corner of each crossing
|
||||
_kit_prop_path("res://assets/props/roads/light-square-cross.glb",
|
||||
Vector3(x, 0, z - side * (ROAD_W * 0.5 + 0.8)), 90.0 if side > 0 else -90.0, lamp_scale * 0.8)
|
||||
for x in lines:
|
||||
if absf(x) < 1.0:
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user