trolley — abandoned shopping trolley (53 props)

Wire basket via translucent panels, galv frame, casters. Grinds: handle
bar + front rim. As found in every Brisbane park.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
type-two 2026-08-03 21:32:26 +10:00
parent 0c551843a7
commit 9fb0ca833b
3 changed files with 89 additions and 1 deletions

View File

@ -1865,6 +1865,52 @@
"collider": {
"type": "none"
}
},
{
"id": "trolley",
"src": "props/trolley.glb",
"category": "furniture",
"desc": "abandoned shopping trolley \u2014 gap bait",
"size": [
0.936,
1.022,
0.552
],
"tris": 384,
"grinds": [
{
"a": [
-0.52,
-0.25
],
"b": [
-0.52,
0.25
],
"ya": 1.0,
"yb": 1.0,
"kind": "rail"
},
{
"a": [
0.38,
-0.26
],
"b": [
0.38,
0.26
],
"ya": 0.95,
"yb": 0.95,
"kind": "rail"
}
],
"collider": {
"type": "box",
"hw": 0.52,
"hd": 0.3,
"h": 1.0
}
}
]
}

BIN
props/trolley.glb Normal file

Binary file not shown.

View File

@ -750,6 +750,48 @@ def bleachers():
p.collider = {'type': 'box', 'hw': L / 2, 'hd': 0.75, 'h': 0.92}
return p
def trolley():
"""Shopping trolley. Lives in every Brisbane park whether the park likes it
or not. Wire basket faked with translucent panels; handle bar grinds."""
p = Prop('trolley', 'furniture', 'abandoned shopping trolley — gap bait')
WIRE = Mat('trolley_wire', tint=(0.72, 0.75, 0.78, 0.45), rough=0.4,
metal=0.8, double=True)
# basket: tapered shell, small base -> wide mouth
b = {'x0': -0.28, 'x1': 0.30, 'z': 0.20, 'y': 0.50}
t = {'x0': -0.44, 'x1': 0.38, 'z': 0.26, 'y': 0.95}
q = lambda a, bb, c, d: quad(a, bb, c, d)
p.add(WIRE, q((b['x0'], b['y'], -b['z']), (b['x1'], b['y'], -b['z']),
(t['x1'], t['y'], -t['z']), (t['x0'], t['y'], -t['z'])))
p.add(WIRE, q((b['x1'], b['y'], b['z']), (b['x0'], b['y'], b['z']),
(t['x0'], t['y'], t['z']), (t['x1'], t['y'], t['z'])))
p.add(WIRE, q((b['x1'], b['y'], -b['z']), (b['x1'], b['y'], b['z']),
(t['x1'], t['y'], t['z']), (t['x1'], t['y'], -t['z'])))
p.add(WIRE, q((b['x0'], b['y'], b['z']), (b['x0'], b['y'], -b['z']),
(t['x0'], t['y'], -t['z']), (t['x0'], t['y'], t['z'])))
p.add(WIRE, box(( b['x0'] + b['x1']) / 2, b['y'], 0,
b['x1'] - b['x0'], 0.015, 2 * b['z']))
# top rim + handle + frame
rim = [(t['x0'], t['y'], -t['z']), (t['x1'], t['y'], -t['z']),
(t['x1'], t['y'], t['z']), (t['x0'], t['y'], t['z']),
(t['x0'], t['y'], -t['z'])]
p.add(GALV, tube(rim, 0.016, seg=6))
p.add(GALV, tube([(-0.52, 1.0, -0.25), (-0.52, 1.0, 0.25)], 0.022, seg=8))
for sz in (-1, 1):
p.add(GALV, tube([(-0.42, 0.05, sz * 0.22), (-0.52, 0.98, sz * 0.25)],
0.016, seg=6))
p.add(GALV, tube([(0.34, 0.05, sz * 0.22), (t['x1'], t['y'] - 0.02, sz * t['z'])],
0.016, seg=6))
p.add(GALV, tube([(-0.42, 0.08, sz * 0.22), (0.34, 0.08, sz * 0.22)],
0.014, seg=6))
for wx in (-0.42, 0.34): # casters
for sz in (-1, 1):
p.add(STEEL, tube([(wx, 0.045, sz * 0.22 - 0.015), (wx, 0.045, sz * 0.22 + 0.015)],
0.045, seg=8))
p.grind(-0.52, -0.25, -0.52, 0.25, 1.0, 1.0, 'rail') # handle bar
p.grind(t['x1'], -t['z'], t['x1'], t['z'], t['y'], t['y'], 'rail') # front rim
p.collider = {'type': 'box', 'hw': 0.52, 'hd': 0.3, 'h': 1.0}
return p
def drain_grate():
p = Prop('drain_grate', 'dressing', 'flush drainage grate')
p.add(Mat('grate', tex='steel_grate', uv=0.9, rough=0.5, metal=0.6),
@ -793,7 +835,7 @@ BUILDERS = [
'inclined manual pad', graf=True),
pyramid, euro_gap, volcano, roller,
jersey_barrier, parking_block, hydrant, pool_edge,
fence_chain, floodlight, bleachers, drain_grate,
fence_chain, floodlight, bleachers, drain_grate, trolley,
]
def main():