Ballpark Building

In short

Every park is built from its BallparkDefinition by BallparkBuilder.Build, all in code. Only the props around the field (barns, rocks) can come from a prefab; the field, wall, targets and stands always stay in code because the ball physics and scoring read the same numbers.

How it works

Build order

BallparkBuilder.Build(park) returns at once if park is already built. Otherwise it destroys the old park root and builds, under a new root named after the park:

  1. Ground by GroundStyle: Mowed (striped grass, dirt diamond, infield grass, mound, plate, then a warning track), Sandlot (patchy grass, one big dirt infield with bases, no warning track), Lunar (cratered dust, a dark regolith field, landing pad at the plate, then a warning track).
  2. Foul lines.
  3. Wall by WallStyle: Padded wall, or WoodFence (post-and-rail, more fencing down the foul lines).
  4. Targets: a flat coloured disc per ground target; aerial targets get no disc (their prop is the marker). Inside a stadium, a 12 m pole marks each target that is not outsideStadium.
  5. If park.stadium: StadiumCrowd (stands and fans, kept in BallparkBuilder.Crowd; null for parks without stands) and light towers.
  6. Sky extras: 260 stars for Night and Space skies; the Earth over Space parks.
  7. StadiumAmbience: flags streaming downwind, clouds drifting with the wind, gulls on day games.
  8. Scoreboard (Scoreboard), kept in BallparkBuilder.Board.
  9. ParkDressing.Build: the props.
  10. Lighting and SkyBuilder.Apply (Rendering).

Stands (StadiumLayout + StadiumCrowd)

  • StadiumLayout is shared by the builder and HitPhysics, so the seats you see are the seats the ball bounces off. Two kinds of stepped stands: outfield bleachers following the wall behind a lawn, and grandstands along each foul line. Each step is a solid block (a floor and a riser).
  • The lawn between wall and bleachers is at least 30 ft, and always deep enough to leave every in-stadium target open (target edge + 15 ft).
  • StadiumCrowd draws a GPU-instanced crowd in batches of 1023. Fans bob, stand when the ball is hit, erupt on home runs (most near where it lands), scramble when a ball lands in their seats, sit on outs, and do the wave every 25 to 45 s when quiet. Density and seat colour come from the park (crowdDensity, seatColor).
  • For the cutscenes (Cutscenes), StadiumCrowd.Celebrate(seconds) puts every fan on their feet, arms up and bouncing; Slump(seconds) sinks them into their seats with no wave; Calm() returns to following the game. OutroDirector reaches them through BallparkBuilder.Crowd.

Light towers

Four towers (two behind the outfield at +-30 deg, one beside each foul line). At night the lamps glow (unlit HDR colour for bloom) and each tower adds a spotlight aimed at the infield, its intensity set from the distance so each adds about the same light where the action is.

Park dressing (props)

ParkDressing.Build picks, in order:

  1. The park’s hand-placed prefab: Resources.Load(park.dressing) (for example Parks/farm_Dressing).
  2. Else the code layout from ParkLayouts (only farm and moon have one).

Then it strips colliders (props are visual only), Toonifys everything, makes *Glow* materials unlit and HDR-bright (big glowing parts also get a point light), and animates children by name: _Spin (turns about its flattest axis), _Yaw (pans slowly), _Bob (drifts up and down).

ParkLayouts places props from Resources/Props/Farm/ and Resources/Props/Moon/ relative to the park’s wall, foul lines and targets, so they follow any retuning. It uses a fixed System.Random seed (1717 for the farm) so the layout is the same every time. The moon’s Meteor Shower bonus gets a MeteorShower (meteors streaking through the zone; purely visual, the scoring zone is an aerial target).

Fireworks

Fireworks (in Scripts/Ballparks/, but added to [Game] by OutroDirector, not built with the park) draws the end-of-game fireworks: shells climb from behind the outfield wall and burst into spheres of HDR sparks that drift down under light gravity and drag. No particle systems or assets: instanced unlit spheres, one batch per colour. Flash lets the post-processing pulse with each burst (Rendering); Puff makes small low bursts (dust off the mound when a boss falls, confetti). Clear() removes everything when the scene ends.

Hand-arranging dressing

  1. Tools > Home Run Derby > Bake Park Dressing turns each park’s code layout into Assets/_Project/Resources/<park.dressing>.prefab, keeping prefab links to the props. It asks before replacing an existing prefab.
  2. Open the prefab. The ParkDressing inspector (ParkDressingEditor) has a Park picker and “View from batter camera” / “View field from above”; the Scene view draws foul lines, the wall, target circles, the stands footprint and the batter camera’s view.
  3. Move, add and delete props. The prefab now wins over the code layout at runtime.

Numbers

WhatValueWhere to tune
Ground size (mowed)400 m, centred 80 m outBallparkBuilder.GroundSizeM, GroundCenterZ
Lunar ground1100 m, centred 150 m outLunarGroundSizeM, LunarGroundCenterZ
Warning track15 ftWarningTrackFt
Light tower height38 mTowerHeightM
Outfield bleachers12 rows, 1.6 m deep, 1 m riseStadiumLayout.Rows, RowDepth, RowRise
Foul grandstands9 rows, 1.4 m deep, 0.9 m rise, 10 m from the line, from 28 mStadiumLayout.Foul*
Min lawn behind the wall30 ftStadiumLayout.MinGapFt
Fan scale1.5StadiumCrowd.FanScale
Flags fully out at15 mphStadiumAmbience.StrongWindMph
Clouds / birds10 / 6StadiumAmbience
Fireworks: sparks / shell climb / spark gravity / drag / glow2400 max / 1.15 s / 3.2 / 1.6 / x 3.2 HDRFireworks.MaxSparks, ShellSeconds, SparkGravity, SparkDrag, Glow

In the code

FileWhat it does
Scripts/Ballparks/BallparkBuilder.csInit, Build, ground, walls, targets, towers, sky extras, ApplyLighting.
Scripts/Ballparks/StadiumLayout.csStand geometry; SurfaceHeight for physics and shards.
Scripts/Ballparks/StadiumCrowd.csStands and the instanced crowd; Celebrate, Slump, Calm.
Scripts/Ballparks/Fireworks.csCode-built fireworks for the outros.
Scripts/Ballparks/StadiumAmbience.csFlags, clouds, gulls.
Scripts/Ballparks/ParkDressing.csProps: load, toonify, glow, animate; Scene-view field gizmos.
Scripts/Ballparks/ParkLayouts.csCode layouts for farm and moon.
Scripts/Ballparks/MeteorShower.csThe moon’s meteors.
Scripts/Ballparks/ParkTextures.csGround textures.
Scripts/Ballparks/BallparkMath.csFeet/metres and field coordinates: plate at origin, +Z to center field, spray -45 = left line.
Editor/ParkDressingTools.csParkDressingEditor and Bake Park Dressing.

Gotchas

  • No Resources/Parks/*_Dressing.prefab is in the repo on main, so the farm and the moon use their code layouts.
  • Build skips a park that is already built. A run is one park, so the park (and anything on it, like scoreboard holes) persists from inning to inning.
  • Props never collide with the ball. Only the field, wall, stands and scoreboard are physical, and those are in code.
  • Kit models face -Y in Blender, which is +Z in Unity; ParkLayouts.FaceHome turns them to home plate.