From aac4384c05ebd8779677eb086d3f9ee4aa6b4d91 Mon Sep 17 00:00:00 2001 From: m3ultra Date: Wed, 29 Jul 2026 00:15:05 +1000 Subject: [PATCH] Per-junction medal targets, measured; fix the last unplayable junction Medal targets are no longer one uniform 15/35/60k guess across every event. tools/tune_junctions.gd plays each junction 12 times with varied launches and sets bronze/silver/gold at the 35th/65th/88th percentile of actual damage, so they now range from $4k at Cliffs Corner to $73k gold at Melbourne x Merivale. The old numbers made half the events impossible and the other half trivial. Grey x Glenelg scored $0 in 12/12 runs and took three fixes, each found by measuring rather than reading: - The launch sat on the street centreline, so the car drove cleanly BETWEEN the two convoy lanes -- closest pass 2.9 m, almost exactly the 2.7 m lane offset. It now launches in a lane. (The first attempt offset the wrong way and widened the pass to 5.5 m, which is how the sign error announced itself.) - int(L / headway) floors to one car on a short clipped stream, so that junction fielded 9 convoy cars against the usual 20-25. Minimum 3 per stream, evenly spaced to fit. Result: $0 -> $91k, convoy 9 -> 18, and 0 of 9 junctions now unplayable. The tuner has turned out to be the event validator as much as a balance tool -- "scores nothing in every run" is an unplayable event, not a tuning problem. Also from the review: the deformer no longer crumples det_* panels after they've been shed onto their own body, and notes that rebuilding an ArrayMesh drops any imported LODs. Honest gap: Cliffs Corner and Bridge Approach show median == max at ~$4.7k -- winnable and correctly tuned, but the run ends on scenery before the convoy is reached. Both are curved approaches; they want better crossings picked by hand. Co-Authored-By: Claude Opus 5 --- README.md | 28 ++ levels/albert_parklands/junctions.json | 402 ++++++++++++------------- levels/kangaroo_point/junctions.json | 128 ++++---- levels/queen_st_mall/junctions.json | 350 ++++++++++----------- levels/southbank/junctions.json | 308 +++++++++---------- levels/story_bridge/junctions.json | 168 +++++------ levels/woolies_carpark/junctions.json | 73 ++++- src/deform.gd | 12 + src/game.gd | 9 +- tools/osm_junction.py | 9 +- 10 files changed, 800 insertions(+), 687 deletions(-) diff --git a/README.md b/README.md index 8c4444c..a0f9ae7 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,22 @@ Controls: WASD/arrows drive, Shift drift, Space boost, R reset (or retry after C runs**: a second Godot instance contends for the `.godot` import lock, and a level rebuild mid-flight silently feeds it half-written levels, which reads as "this event scores zero" rather than as an error. + + The tuner is also the event *validator*. An event that scores nothing across every + run isn't badly tuned, it's unplayable, and it prints `!!` for exactly that. Three + separate causes turned up that way, none visible by reading the generator: + convoy streams clipped so wide that you thread the intersection through a 20 m gap; + a launch point on the street centreline threading cleanly *between* the two convoy + lanes; and `int(L / headway)` flooring to one car on a short stream, leaving nine + convoy cars where the working events have twenty. Re-run it after any change to the + generator, the launch geometry, or convoy spacing — all three feed the numbers. + + Read the spread it prints, not just the targets. **Cliffs Corner** and **Bridge + Approach** both show median == max at a low ceiling (~$4.7k), which means the run + reliably ends on the first thing you hit and the convoy is never reached — they're + winnable and honestly tuned, but they're scenery crashes rather than pile-ups. Both + sit on curved approaches where the launch street bends away from the intersection. + Worth hand-picking better crossings for those two. - **Race** — 3 laps vs 3 rubber-banded rivals on the level's `RacePath`. - **Drag** — NFSU2's event, our code: a straight-line run down the level's longest genuinely straight stretch of wide road (the builder finds it and drops @@ -227,6 +243,18 @@ Make a folder `levels//` containing `level.glb` (or `level.tscn`). Blender c /Applications/Godot.app/Contents/MacOS/Godot --headless --path . --script tests/smoke.gd ``` +Covers all seven modes (cruise, crash, junction, outrun, pursuit, drag, derby, +race) in about 30 s, printing a `.. stage` line as it enters each one. + +Failures go through `_check()`, never bare `assert()`. A failed assert in a +headless `SceneTree` script halts the script but leaves the tree running, so the +process spins forever at 100% CPU instead of failing — it looks exactly like a +slow test. That cost 53 minutes of wall clock to spot once; the stage lines and +`_check()` exist so it can't happen twice. + +Only one Godot instance may touch the project at a time: a second contends for +the `.godot` import lock and can kill the first mid-run. + Visual check (opens a window, saves a PNG): ``` diff --git a/levels/albert_parklands/junctions.json b/levels/albert_parklands/junctions.json index 3fbe57e..55b3b08 100644 --- a/levels/albert_parklands/junctions.json +++ b/levels/albert_parklands/junctions.json @@ -2,445 +2,445 @@ { "name": "Alice x George", "spawn": { - "x": -165.3192678228276, - "z": 159.9955423589618, - "dx": 0.7668331983120437, - "dz": -0.6418464348787193 + "dx": 0.766833198312044, + "dz": -0.641846434878719, + "x": -163.586282448655, + "z": 162.065991994404 }, "streams": [ { + "interval": 1.5, "pts": [ [ - -71.62300756706763, + -71.6230075670676, 85.0918821008208 ], [ - -72.10279819575109, - 85.49061753866586 + -72.1027981957511, + 85.4906175386659 ], [ - -82.55345192912239, - 94.80588029839768 + -82.5534519291224, + 94.8058802983977 ], [ - -104.44928325520195, - 113.36472803055571 + -104.449283255202, + 113.364728030556 ], [ - -114.55295338424757, - 122.93815788447793 + -114.552953384248, + 122.938157884478 ], [ - -118.63551709634598, - 126.33214688818488 + -118.635517096346, + 126.332146888185 ], [ - -124.17972594270637, - 130.60060399325408 + -124.179725942706, + 130.600603993254 ], [ - -132.4126578466066, - 136.84137198262476 + -132.412657846607, + 136.841371982625 ], [ - -135.42619497476394, - 139.13115862719584 + -135.426194974764, + 139.131158627196 ], [ - -137.0173915026139, - 140.32992242527928 + -137.017391502614, + 140.329922425279 ], [ - -142.22691046279974, - 144.18129435873087 + -142.2269104628, + 144.181294358731 ] ], - "speed": 12.0, - "interval": 1.5 + "speed": 12.0 }, { + "interval": 1.5, "pts": [ [ -75.361941989609, - 84.82292365250544 + 84.8229236525054 ], [ - -80.93953886827424, - 78.61163770120406 + -80.9395388682742, + 78.6116377012041 ], [ - -82.56599989409156, + -82.5659998940916, 76.7348960854059 ], [ - -115.40558143561937, - 38.74155522137386 + -115.405581435619, + 38.7415552213739 ] ], - "speed": 12.0, - "interval": 1.5 + "speed": 12.0 }, { + "interval": 1.8, "pts": [ [ - -145.4370805808313, - 139.83908204087984 + -145.437080580831, + 139.83908204088 ], [ - -140.2367304705485, - 135.99450357474848 + -140.236730470549, + 135.994503574748 ], [ - -138.6871885076824, - 134.82698377267795 + -138.687188507682, + 134.826983772678 ], [ - -135.67603860636424, - 132.53900681717874 + -135.676038606364, + 132.539006817179 ], [ - -127.45466133363814, - 126.30702760692736 + -127.454661333638, + 126.307027606927 ], [ - -121.99640893818653, - 122.1055163120108 + -121.996408938187, + 122.105516312011 ], [ - -118.19749682812089, - 118.9535245154313 + -118.197496828121, + 118.953524515431 ], [ - -108.01476176313997, - 109.30919316947609 + -108.01476176314, + 109.309193169476 ], [ - -86.07852578965569, - 90.71517690194068 + -86.0785257896557, + 90.7151769019407 ], [ - -75.68968831102165, - 81.45400766143295 + -75.6896883110217, + 81.454007661433 ], [ - -75.08305996358739, - 80.94603629889595 + -75.0830599635874, + 80.9460362988959 ] ], - "speed": 11.0, - "interval": 1.8 + "speed": 11.0 }, { + "interval": 1.8, "pts": [ [ - -111.32018174165945, - 35.21033597859207 + -111.320181741659, + 35.2103359785921 ], [ - -78.48079808538708, - 73.20344791473178 + -78.4807980853871, + 73.2034479147318 ], [ -76.9072614072839, - 75.01987789888024 + 75.0198778988802 ], [ - -71.34412554104603, + -71.344125541046, 81.2149947472113 ] ], - "speed": 11.0, - "interval": 1.8 + "speed": 11.0 }, { + "interval": 1.5, "pts": [ [ - -72.11668883510822, - 80.61865688274891 + -72.1166888351082, + 80.6186568827489 ], [ - -63.31551687082244, - 85.23196646473183 + -63.3155168708224, + 85.2319664647318 ], [ - -54.55178175870453, - 95.53822905343011 + -54.5517817587045, + 95.5382290534301 ], [ - -39.78320194928109, - 112.96784568335697 + -39.7832019492811, + 112.967845683357 ], [ - -38.24953472930413, - 114.64142478239386 + -38.2495347293041, + 114.641424782394 ], [ - -37.466790819459995, - 115.77089209241056 + -37.46679081946, + 115.770892092411 ], [ - -36.90754547102499, - 116.86830840435711 + -36.907545471025, + 116.868308404357 ], [ - -36.64154284861633, - 117.96012844030032 + -36.6415428486163, + 117.9601284403 ], [ - -36.54962586770791, - 118.92829018795193 + -36.5496258677079, + 118.928290187952 ], [ - -36.58380403095183, - 120.63163096695364 + -36.5838040309518, + 120.631630966954 ], [ - -36.733516672801336, - 121.77324800253669 + -36.7335166728013, + 121.773248002537 ], [ - -36.949600973076684, - 122.55506784741175 + -36.9496009730767, + 122.555067847412 ], [ - -37.31118692587169, - 123.40422578212599 + -37.3111869258717, + 123.404225782126 ], [ - -38.02064964168787, - 124.38554265247478 + -38.0206496416879, + 124.385542652475 ], [ - -39.45793344555888, - 125.80100694689808 + -39.4579334455589, + 125.801006946898 ], [ - -41.96015977939887, - 127.8781767661959 + -41.9601597793989, + 127.878176766196 ] ], - "speed": 12.0, - "interval": 1.5 + "speed": 12.0 }, { + "interval": 1.8, "pts": [ [ - -45.40767874247836, - 123.72190283402932 + -45.4076787424784, + 123.721902834029 ], [ - -43.03089623055088, - 121.75206425317394 + -43.0308962305509, + 121.752064253174 ], [ -41.9792929338678, - 120.7127857471952 + 120.712785747195 ], [ - -41.99739811738572, - 120.72105141795794 + -41.9973981173857, + 120.721051417958 ], [ - -42.06268798731611, - 120.81830615252781 + -42.0626879873161, + 120.818306152528 ], [ - -42.041735423545425, - 120.78187839726885 + -42.0417354235454, + 120.781878397269 ], [ - -41.974164266802894, - 120.30911503284231 + -41.9741642668029, + 120.309115032842 ], [ - -41.94908321684239, - 119.00484301205215 + -41.9490832168424, + 119.004843012052 ], [ - -41.975684667956976, - 118.80092035936316 + -41.975684667957, + 118.800920359363 ], [ - -41.94671891520851, - 118.80911519521383 + -41.9467189152085, + 118.809115195214 ], [ -42.0788310934576, - 118.57964350736775 + 118.579643507368 ], [ - -42.38250615411705, - 118.1168452176333 + -42.3825061541171, + 118.116845217633 ], [ - -43.89081206390128, - 116.47320431640294 + -43.8908120639013, + 116.473204316403 ], [ - -58.67282832403665, - 99.02778134654227 + -58.6728283240367, + 99.0277813465423 ], [ - -66.81772305118318, + -66.8177230511832, 89.3422647349603 ], [ -74.5893786955468, - 85.41926151696784 + 85.4192615169678 ] ], - "speed": 11.0, - "interval": 1.8 + "speed": 11.0 } ], "targets": [ - 15000, - 35000, - 60000 + 26500, + 29000, + 46500 ] }, { "name": "Margaret x Edward", "spawn": { - "x": 276.7158840463856, - "z": -371.11587218595514, - "dx": -0.7427057931255263, - "dz": 0.6696178797327494 + "dx": -0.742705793125526, + "dz": 0.669617879732749, + "x": 274.907915771107, + "z": -373.121177827394 }, "streams": [ { + "interval": 1.5, "pts": [ [ - 185.8338152967176, - -292.8126451679154 + 185.833815296718, + -292.812645167915 ], [ - 193.65593395098287, - -299.88251164434115 + 193.655933950983, + -299.882511644341 ], [ - 211.37786867540518, - -315.2307257048046 + 211.377868675405, + -315.230725704805 ], [ - 216.02310568686988, - -319.25459820267537 + 216.02310568687, + -319.254598202675 ], [ - 237.6429961947087, - -338.58229333857753 + 237.642996194709, + -338.582293338578 ], [ - 239.66099718191472, - -341.2883463335457 + 239.660997181915, + -341.288346333546 ] ], - "speed": 12.0, - "interval": 1.5 + "speed": 12.0 }, { + "interval": 1.5, "pts": [ [ - 179.81812157632743, - -304.16623584225226 + 179.818121576327, + -304.166235842252 ], [ - 181.35983927566346, - -302.4069925620872 + 181.359839275663, + -302.406992562087 ], [ - 184.2133034529848, - -299.1448137854387 + 184.213303452985, + -299.144813785439 ], [ - 189.71555797124375, - -292.5416508365839 + 189.715557971244, + -292.541650836584 ], [ - 194.9234531376747, - -286.3366793395667 + 194.923453137675, + -286.336679339567 ], [ - 234.05675616721896, - -241.1315253602194 + 234.056756167219, + -241.131525360219 ], [ - 244.50993125963066, - -229.32934036140196 + 244.509931259631, + -229.329340361402 ] ], - "speed": 12.0, - "interval": 1.5 + "speed": 12.0 }, { + "interval": 1.8, "pts": [ [ - 243.95347049022743, - -338.01196526635846 + 243.953470490227, + -338.011965266358 ], [ - 241.32949950132615, - -334.63644826175323 + 241.329499501326, + -334.636448261753 ], [ - 219.61114951437548, - -315.21901379742513 + 219.611149514375, + -315.219013797425 ], [ - 214.91318335480702, - -311.1488694949895 + 214.913183354807, + -311.14886949499 ], [ - 197.21785955435436, - -295.8238559560563 + 197.217859554354, + -295.823855956056 ], [ - 189.45480420951895, - -288.8065948320647 + 189.454804209519, + -288.806594832065 ] ], - "speed": 11.0, - "interval": 1.8 + "speed": 11.0 }, { + "interval": 1.8, "pts": [ [ - 240.4674984004257, - -225.74901403845038 + 240.467498400426, + -225.74901403845 ], [ 229.982416914263, - -237.5875502401286 + -237.587550240129 ], [ - 190.83429465784906, - -282.80981346079136 + 190.834294657849, + -282.809813460791 ], [ - 185.5730615349928, - -289.07758916339617 + 185.573061534993, + -289.077589163396 ], [ - 180.09260788812207, - -295.6548470145767 + 180.092607888122, + -295.654847014577 ], [ - 177.29669340310514, - -298.8501898379666 + 177.296693403105, + -298.850189837967 ], [ - 175.7569318305437, - -300.6071997580377 + 175.756931830544, + -300.607199758038 ] ], - "speed": 11.0, - "interval": 1.8 + "speed": 11.0 } ], "targets": [ - 15000, - 35000, - 60000 + 22500, + 25000, + 30000 ] } -] \ No newline at end of file +] diff --git a/levels/kangaroo_point/junctions.json b/levels/kangaroo_point/junctions.json index 59c8ec7..cdc4dd2 100644 --- a/levels/kangaroo_point/junctions.json +++ b/levels/kangaroo_point/junctions.json @@ -2,149 +2,149 @@ { "name": "Cliffs Corner", "spawn": { - "x": 19.82910866163153, - "z": -91.88863639399733, - "dx": 0.7116289476302671, - "dz": -0.7025555073406219 + "dx": 0.711628947630267, + "dz": -0.702555507340622, + "x": 21.7260085314512, + "z": -89.9672382353956 }, "streams": [ { + "interval": 1.5, "pts": [ [ - 63.92619388342862, - -109.98937518013152 + 63.9261938834286, + -109.989375180132 ], [ 78.3750416498091, - -148.8340213803462 + -148.834021380346 ] ], - "speed": 12.0, - "interval": 1.5 + "speed": 12.0 }, { + "interval": 1.5, "pts": [ [ - 106.13660245700423, - -179.68219050814878 + 106.136602457004, + -179.682190508149 ], [ - 105.14898470103478, - -213.87167130817437 + 105.148984701035, + -213.871671308174 ] ], - "speed": 12.0, - "interval": 1.5 + "speed": 12.0 }, { + "interval": 1.8, "pts": [ [ - 83.43625143590378, - -146.95142862004474 + 83.4362514359038, + -146.951428620045 ], [ - 68.98740366952329, - -108.10678241983003 + 68.9874036695233, + -108.10678241983 ] ], - "speed": 11.0, - "interval": 1.8 + "speed": 11.0 }, { + "interval": 1.8, "pts": [ [ - 110.54673313420321, - -214.02759389225906 + 110.546733134203, + -214.027593892259 ], [ - 111.53435089017266, - -179.83811309223347 + 111.534350890173, + -179.838113092233 ] ], - "speed": 11.0, - "interval": 1.8 + "speed": 11.0 }, { + "interval": 1.5, "pts": [ [ - 110.03793689684629, - -168.49583563849748 + 110.037936896846, + -168.495835638497 ], [ - 105.07701815835642, - -166.64105720795808 + 105.077018158356, + -166.641057207958 ], [ - 102.76621908994164, - -165.6886852292976 + 102.766219089942, + -165.688685229298 ], [ - 100.0562323833477, - -163.76233037299872 + 100.056232383348, + -163.762330372999 ], [ 96.9873892973125, - -160.78656603278262 + -160.786566032783 ], [ - 94.50499850150788, - -158.03413164414619 + 94.5049985015079, + -158.034131644146 ], [ 91.4342291831665, - -153.71805517412884 + -153.718055174129 ], [ - 82.70848350683406, - -145.88280488205245 + 82.7084835068341, + -145.882804882052 ] ], - "speed": 12.0, - "interval": 1.5 + "speed": 12.0 }, { + "interval": 1.8, "pts": [ [ - 79.10280957887883, - -149.90264511833848 + 79.1028095788788, + -149.902645118338 ], [ - 87.56161285248508, - -157.4814104264721 + 87.5616128524851, + -157.481410426472 ], [ - 90.25853122720883, + 90.2585312272088, -161.369924756482 ], [ - 93.10927630970947, - -164.5442567671812 + 93.1092763097095, + -164.544256767181 ], [ - 96.57846276532892, - -167.89332522702423 + 96.5784627653289, + -167.893325227024 ], [ - 100.07071556655998, - -170.36781557108517 + 100.07071556656, + -170.367815571085 ], [ - 103.11280473039093, - -171.67115319207213 + 103.112804730391, + -171.671153192072 ], [ - 108.14657768085227, - -173.5537759619962 + 108.146577680852, + -173.553775961996 ] ], - "speed": 11.0, - "interval": 1.8 + "speed": 11.0 } ], "targets": [ - 15000, - 35000, - 60000 + 4000, + 6500, + 10500 ] } -] \ No newline at end of file +] diff --git a/levels/queen_st_mall/junctions.json b/levels/queen_st_mall/junctions.json index af4d21f..f88b412 100644 --- a/levels/queen_st_mall/junctions.json +++ b/levels/queen_st_mall/junctions.json @@ -2,397 +2,397 @@ { "name": "Albert x Adelaide", "spawn": { - "x": 18.671705882497893, - "z": -22.919507778110138, - "dx": -0.6633868531476461, - "dz": -0.7482766086621067 + "dx": -0.663386853147646, + "dz": -0.748276608662107, + "x": 20.6920527258856, + "z": -24.7106522816088 }, "streams": [ { + "interval": 1.5, "pts": [ [ - -58.84614846630014, - -114.42417420924829 + -58.8461484663001, + -114.424174209248 ], [ -53.880474905008, - -108.39185473942744 + -108.391854739427 ], [ - -51.24051503498836, - -105.52578654474546 + -51.2405150349884, + -105.525786544745 ], [ - -20.352984240690695, - -70.76962163514554 + -20.3529842406907, + -70.7696216351455 ] ], - "speed": 12.0, - "interval": 1.5 + "speed": 12.0 }, { + "interval": 1.5, "pts": [ [ - -86.70325250389301, - -94.08771386994844 + -86.703252503893, + -94.0877138699484 ], [ - -77.60701968874399, - -101.92094169090129 + -77.607019688744, + -101.920941690901 ], [ - -72.06522503228508, - -106.94786296530025 + -72.0652250322851, + -106.9478629653 ], [ - -68.79209061830386, - -109.50838129624599 + -68.7920906183039, + -109.508381296246 ], [ - -62.692661313561906, - -114.75385541597699 + -62.6926613135619, + -114.753855415977 ], [ - -56.45081914916183, - -120.13849830634709 + -56.4508191491618, + -120.138498306347 ], [ - -53.14418135326541, - -122.9809049049611 + -53.1441813532654, + -122.980904904961 ], [ - -38.75486932340002, - -135.5677577748611 + -38.7548693234, + -135.567757774861 ], [ - -8.138880164463979, - -163.05430391717795 + -8.13888016446398, + -163.054303917178 ], [ - 7.537426213222782, - -176.88629254786764 + 7.53742621322278, + -176.886292547868 ] ], - "speed": 12.0, - "interval": 1.5 + "speed": 12.0 }, { + "interval": 1.8, "pts": [ [ - -24.38938905950134, - -67.18250076477023 + -24.3893890595013, + -67.1825007647702 ], [ - -55.272013374374126, - -101.93315225504524 + -55.2720133743741, + -101.933152255045 ], [ - -57.98533525129133, - -104.88327646076375 + -57.9853352512913, + -104.883276460764 ], [ - -63.01508813331892, - -110.99198219061685 + -63.0150881333189, + -110.991982190617 ] ], - "speed": 11.0, - "interval": 1.8 + "speed": 11.0 }, { + "interval": 1.8, "pts": [ [ - 11.110167779562063, - -172.83715465195058 + 11.1101677795621, + -172.837154651951 ], [ - -4.543064055336218, - -159.02564328250827 + -4.54306405533622, + -159.025643282508 ], [ - -35.16387720923361, - -131.5347966250365 + -35.1638772092336, + -131.534796625037 ], [ - -49.59536988091847, - -118.91077749494814 + -49.5953698809185, + -118.910777494948 ], [ - -52.92601130212681, - -116.04756569366813 + -52.9260113021268, + -116.047565693668 ], [ - -59.168575286057155, - -110.66230098388816 + -59.1685752860572, + -110.662300983888 ], [ - -65.33626025215173, - -105.35901550369637 + -65.3362602521517, + -105.359015503696 ], [ -68.5423745958537, - -102.85524463438601 + -102.855244634386 ], [ -74.0429581637501, - -97.86416150877923 + -97.8641615087792 ], [ - -83.17948939242227, + -83.1794893924223, -89.9958813300908 ] ], - "speed": 11.0, - "interval": 1.8 + "speed": 11.0 }, { + "interval": 1.5, "pts": [ [ - -63.049013950748005, - -111.03404120330288 + -63.049013950748, + -111.034041203303 ], [ - -67.67311197746825, - -116.88556835863362 + -67.6731119774683, + -116.885568358634 ], [ - -69.33640432781439, - -119.01651536179543 + -69.3364043278144, + -119.016515361795 ], [ - -72.74965354025018, - -122.55658461736515 + -72.7496535402502, + -122.556584617365 ], [ - -98.24408864239251, - -142.51997682349207 + -98.2440886423925, + -142.519976823492 ], [ - -106.03262882232805, - -149.46281622691504 + -106.032628822328, + -149.462816226915 ], [ - -127.2548410984026, - -167.5083127878196 + -127.254841098403, + -167.50831278782 ] ], - "speed": 12.0, - "interval": 1.5 + "speed": 12.0 }, { + "interval": 1.8, "pts": [ [ - -123.7567869560363, - -171.62214521234466 + -123.756786956036, + -171.622145212345 ], [ - -102.50831375382124, - -153.55417337313145 + -102.508313753821, + -153.554173373131 ], [ - -94.84937670776534, - -146.71949237661244 + -94.8493767077653, + -146.719492376612 ], [ -69.3394816295263, - -126.74355578269574 + -126.743555782696 ], [ - -65.32529933336386, - -122.63190423762802 + -65.3252993333639, + -122.631904237628 ], [ - -63.432906391639634, - -120.22931724123647 + -63.4329063916396, + -120.229317241236 ], [ - -58.81222264887106, - -114.38211519656227 + -58.8122226488711, + -114.382115196562 ] ], - "speed": 11.0, - "interval": 1.8 + "speed": 11.0 } ], "targets": [ - 15000, - 35000, - 60000 + 23000, + 25500, + 29500 ] }, { "name": "Edward x Elizabeth", "spawn": { - "x": 173.87950117253465, - "z": -177.50987452854054, "dx": 0.688388502507091, - "dz": 0.7253421741606128 + "dz": 0.725342174160613, + "x": 171.921077302301, + "z": -175.651225571771 }, "streams": [ { + "interval": 1.5, "pts": [ [ - 228.7426016851313, - -123.80938841141814 + 228.742601685131, + -123.809388411418 ], [ - 250.48785179439338, - -101.12418691157934 + 250.487851794393, + -101.124186911579 ], [ - 253.19184475779528, - -98.13216139604938 + 253.191844757795, + -98.1321613960494 ], [ - 258.48528328991137, - -92.28343983096748 + 258.485283289911, + -92.2834398309675 ] ], - "speed": 12.0, - "interval": 1.5 + "speed": 12.0 }, { + "interval": 1.5, "pts": [ [ - 184.8196819904455, - -31.59973983603264 + 184.819681990446, + -31.5997398360326 ], [ - 200.9901724381037, - -45.56696118289086 + 200.990172438104, + -45.5669611828909 ], [ - 206.29822476676847, - -50.115127103271014 + 206.298224766768, + -50.115127103271 ], [ - 208.01277161716473, - -51.59585061763732 + 208.012771617165, + -51.5958506176373 ], [ - 243.56749157860247, - -82.55471207644285 + 243.567491578602, + -82.5547120764429 ], [ - 246.1313684904348, - -84.84463727526342 + 246.131368490435, + -84.8446372752634 ], [ - 254.68470539632878, - -92.48524564052305 + 254.684705396329, + -92.485245640523 ] ], - "speed": 12.0, - "interval": 1.5 + "speed": 12.0 }, { + "interval": 1.8, "pts": [ [ - 254.4815819963581, - -88.65985376851496 + 254.481581996358, + -88.659853768515 ], [ - 249.1869798707451, - -94.50986140343801 + 249.186979870745, + -94.509861403438 ], [ - 246.5771986992584, - -97.40037268829819 + 246.577198699258, + -97.4003726882982 ], [ - 224.8443191668579, - -120.07262598818004 + 224.844319166858, + -120.07262598818 ] ], - "speed": 11.0, - "interval": 1.8 + "speed": 11.0 }, { + "interval": 1.8, "pts": [ [ - 258.28215988994066, + 258.282159889941, -88.4580479589594 ], [ - 249.72869976275985, - -80.81732952477397 + 249.72869976276, + -80.817329524774 ], [ - 247.11707918748664, - -78.48526152300741 + 247.117079187487, + -78.4852615230074 ], [ - 211.55809324014456, - -47.52268298180012 + 211.558093240145, + -47.5226829818001 ], [ - 209.81572383420533, - -46.017908496633005 + 209.815723834205, + -46.017908496633 ], [ - 204.51598169911696, - -41.47689161686228 + 204.515981699117, + -41.4768916168623 ], [ - 188.34948976520272, - -27.51312056415722 + 188.349489765203, + -27.5131205641572 ] ], - "speed": 11.0, - "interval": 1.8 + "speed": 11.0 }, { + "interval": 1.5, "pts": [ [ - 258.4805413787254, - -92.28866542876725 + 258.480541378725, + -92.2886654287672 ], [ - 262.2737122591504, - -88.11954201221562 + 262.27371225915, + -88.1195420122156 ], [ - 266.8273793037693, + 266.827379303769, -83.1100839184909 ], [ - 270.87333374760516, - -78.65784777138674 + 270.873333747605, + -78.6578477713867 ], [ - 298.08928934155523, - -47.30427629341134 + 298.089289341555, + -47.3042762934113 ] ], - "speed": 12.0, - "interval": 1.5 + "speed": 12.0 }, { + "interval": 1.5, "pts": [ [ - 254.70925209424783, - -92.50690682734246 + 254.709252094248, + -92.5069068273425 ], [ - 259.70303711688206, + 259.703037116882, -96.8600914480509 ], [ - 263.66545095997486, + 263.665450959975, -100.3447248693 ], [ - 288.61557906385735, - -122.1176793727558 + 288.615579063857, + -122.117679372756 ] ], - "speed": 12.0, - "interval": 1.5 + "speed": 12.0 } ], "targets": [ - 15000, - 35000, - 60000 + 22000, + 24500, + 28500 ] } -] \ No newline at end of file +] diff --git a/levels/southbank/junctions.json b/levels/southbank/junctions.json index 4da7554..70e45a7 100644 --- a/levels/southbank/junctions.json +++ b/levels/southbank/junctions.json @@ -2,345 +2,345 @@ { "name": "Melbourne x Merivale", "spawn": { - "x": -598.2786454342968, - "z": -212.65545062278278, - "dx": 0.8528773292725991, - "dz": -0.5221113494388324 + "dx": 0.852877329272599, + "dz": -0.522111349438832, + "x": -596.868944790812, + "z": -210.352681833747 }, "streams": [ { + "interval": 1.5, "pts": [ [ - -522.2431469994345, - -263.2916099068527 + -522.243146999435, + -263.291609906853 ], [ - -513.2984743659174, - -268.5646201058227 + -513.298474365917, + -268.564620105823 ], [ - -505.76645618454586, - -272.8477143314658 + -505.766456184546, + -272.847714331466 ], [ - -497.90899041561073, - -277.2629244179048 + -497.908990415611, + -277.262924417905 ] ], - "speed": 12.0, - "interval": 1.5 + "speed": 12.0 }, { + "interval": 1.5, "pts": [ [ - -518.3319604245614, - -316.20816625786284 + -518.331960424561, + -316.208166257863 ], [ - -502.53998920863535, - -289.11772214349674 + -502.539989208635, + -289.117722143497 ], [ - -501.0310720126822, - -286.5339989119062 + -501.031072012682, + -286.533998911906 ], [ - -499.3074920997309, - -283.76972490400925 + -499.307492099731, + -283.769724904009 ], [ - -498.93054530357944, - -283.2413778417831 + -498.930545303579, + -283.241377841783 ], [ - -494.34501447411924, + -494.345014474119, -276.414559193545 ] ], - "speed": 12.0, - "interval": 1.5 + "speed": 12.0 }, { + "interval": 1.8, "pts": [ [ - -495.26368453007734, - -272.55523318206934 + -495.263684530077, + -272.555233182069 ], [ - -503.1094123444767, - -268.14663806831595 + -503.109412344477, + -268.146638068316 ], [ - -510.58925218160783, - -263.8934194939837 + -510.589252181608, + -263.893419493984 ], [ - -519.5007896114952, - -258.6397848932893 + -519.500789611495, + -258.639784893289 ] ], - "speed": 11.0, - "interval": 1.8 + "speed": 11.0 }, { + "interval": 1.8, "pts": [ [ - -498.82766047156883, - -273.4035984064291 + -498.827660471569, + -273.403598406429 ], [ - -503.4072640108861, - -280.2216113581537 + -503.407264010886, + -280.221611358154 ], [ - -503.85991989590116, - -280.8653486954825 + -503.859919895901, + -280.865348695483 ], [ - -505.6522751490968, - -283.7403486882755 + -505.652275149097, + -283.740348688276 ], [ - -507.20498688872703, - -286.3978330566516 + -507.204986888727, + -286.397833056652 ], [ -522.997174842978, - -313.4886489421985 + -313.488648942198 ] ], - "speed": 11.0, - "interval": 1.8 + "speed": 11.0 }, { + "interval": 1.5, "pts": [ [ - -497.7097209821479, - -277.3642792991366 + -497.709720982148, + -277.364279299137 ], [ - -489.2653413897242, - -281.21700470668776 + -489.265341389724, + -281.217004706688 ], [ - -470.16395422466655, - -292.9741741951012 + -470.163954224667, + -292.974174195101 ], [ - -453.3973200149641, - -303.3696498434199 + -453.397320014964, + -303.36964984342 ], [ - -438.7171383481014, - -313.0237718470059 + -438.717138348101, + -313.023771847006 ], [ - -428.17568968279613, - -319.6952218182481 + -428.175689682796, + -319.695221818248 ] ], - "speed": 12.0, - "interval": 1.5 + "speed": 12.0 }, { + "interval": 1.5, "pts": [ [ - -490.9127030755138, - -271.2416907037699 + -490.912703075514, + -271.24169070377 ], [ - -487.07948135301893, - -265.2321814476218 + -487.079481353019, + -265.232181447622 ], [ - -460.79611403958603, - -221.7057389459239 + -460.796114039586, + -221.705738945924 ], [ - -449.78766148749827, - -203.62165684766288 + -449.787661487498, + -203.621656847663 ] ], - "speed": 12.0, - "interval": 1.5 + "speed": 12.0 } ], "targets": [ - 15000, - 35000, - 60000 + 35500, + 38000, + 73000 ] }, { "name": "Grey x Glenelg", "spawn": { - "x": -135.06485953132193, - "z": -97.50127625771249, - "dx": 0.5279471843098005, - "dz": 0.8492772047920241 + "dx": 0.5279471843098, + "dz": 0.849277204792024, + "x": -137.35790798426, + "z": -96.075818860076 }, "streams": [ { + "interval": 1.5, "pts": [ [ -66.8941396578206, - 18.021454924938546 + 18.0214549249385 ], [ - -68.93721227192415, - 14.729250272207434 + -68.9372122719242, + 14.7292502722074 ], [ - -74.03417645108553, - 5.788135121643277 + -74.0341764510855, + 5.78813512164328 ], [ - -78.66584427851572, - -1.692678191469608 + -78.6658442785157, + -1.69267819146961 ], [ - -82.82069253186671, - -8.344352365976752 + -82.8206925318667, + -8.34435236597675 ] ], - "speed": 12.0, - "interval": 1.5 + "speed": 12.0 }, { + "interval": 1.5, "pts": [ [ - -33.05020815528413, - -14.758620186231095 + -33.0502081552841, + -14.7586201862311 ], [ - -35.06751528318885, - -14.599409411489315 + -35.0675152831888, + -14.5994094114893 ], [ - -37.27001626186296, - -13.996146050544787 + -37.270016261863, + -13.9961460505448 ], [ - -43.35852481930847, - -10.760668273887504 + -43.3585248193085, + -10.7606682738875 ], [ - -53.694918113870564, - -4.204520462618362 + -53.6949181138706, + -4.20452046261836 ], [ - -56.331462588402815, - -2.4702458690280507 + -56.3314625884028, + -2.47024586902805 ], [ - -63.091151948462084, - 2.2185465904455017 + -63.0911519484621, + 2.2185465904455 ] ], - "speed": 12.0, - "interval": 1.5 + "speed": 12.0 }, { + "interval": 1.8, "pts": [ [ - -78.24074203456223, - -11.205130833848836 + -78.2407420345622, + -11.2051308338488 ], [ - -74.07981104388904, - -4.543695408341438 + -74.079811043889, + -4.54369540834144 ], [ - -69.38832494823436, - 3.0356700785490762 + -69.3883249482344, + 3.03567007854908 ], [ - -64.27327518677029, - 12.007542928328153 + -64.2732751867703, + 12.0075429283282 ], [ - -62.30660151137585, - 15.172859875635417 + -62.3066015113759, + 15.1728598756354 ] ], - "speed": 11.0, - "interval": 1.8 + "speed": 11.0 }, { + "interval": 1.8, "pts": [ [ -66.1688465571084, - -2.2185465904455017 + -2.2185465904455 ], [ - -59.37835881390333, - -6.9285441308125515 + -59.3783588139033, + -6.92854413081255 ], [ - -56.602733425687326, - -8.754752337189586 + -56.6027334256873, + -8.75475233718959 ], [ - -46.12004993919494, - -15.401140126214159 + -46.1200499391949, + -15.4011401262142 ], [ - -39.50773651812935, - -18.910676349026538 + -39.5077365181293, + -18.9106763490265 ], [ -36.1005431869604, - -19.899678588618844 + -19.8996785886188 ], [ - -33.51553068408273, - -20.138534213814854 + -33.5155306840827, + -20.1385342138149 ] ], - "speed": 11.0, - "interval": 1.8 + "speed": 11.0 }, { + "interval": 1.5, "pts": [ [ - -62.42866919418658, - -1.5633764655737972 + -62.4286691941866, + -1.5633764655738 ], [ - -56.22534149367183, - 7.176315693408943 + -56.2253414936718, + 7.17631569340894 ], [ - -31.608294574960304, - 46.399012606383145 + -31.6082945749603, + 46.3990126063831 ] ], - "speed": 12.0, - "interval": 1.5 + "speed": 12.0 }, { + "interval": 1.5, "pts": [ [ - -105.44415325837058, - 17.29338138921854 + -105.444153258371, + 17.2933813892185 ], [ - -124.85549758561747, - 29.02803771609806 + -124.855497585617, + 29.0280377160981 ], [ - -145.9651989732041, - 41.680234308480806 + -145.965198973204, + 41.6802343084808 ] ], - "speed": 12.0, - "interval": 1.5 + "speed": 12.0 } ], "targets": [ - 15000, - 35000, - 60000 + 22500, + 25000, + 29000 ] } -] \ No newline at end of file +] diff --git a/levels/story_bridge/junctions.json b/levels/story_bridge/junctions.json index b8919e3..f5a8f98 100644 --- a/levels/story_bridge/junctions.json +++ b/levels/story_bridge/junctions.json @@ -2,185 +2,185 @@ { "name": "Bridge Approach", "spawn": { - "x": 32.83372074498513, - "z": -118.28842427027045, - "dx": -0.11409585864571734, - "dz": -0.9934697454074263 + "dx": -0.114095858645717, + "dz": -0.993469745407426, + "x": 35.5160890575852, + "z": -118.596483088614 }, "streams": [ { + "interval": 1.5, "pts": [ [ - 21.82446567810751, - -237.81387509878263 + 21.8244656781075, + -237.813875098783 ], [ - 23.145720027383163, - -226.45520770652828 + 23.1457200273832, + -226.455207706528 ], [ - 24.788209612143817, - -213.84815371354867 + 24.7882096121438, + -213.848153713549 ], [ - 26.145569174952232, - -200.29741976993301 + 26.1455691749522, + -200.297419769933 ] ], - "speed": 12.0, - "interval": 1.5 + "speed": 12.0 }, { + "interval": 1.5, "pts": [ [ - 2.199941588527042, - -240.32717119002737 + 2.19994158852704, + -240.327171190027 ], [ - -2.5248172223755736, - -243.91950536774928 + -2.52481722237557, + -243.919505367749 ], [ - -6.325349530807717, + -6.32534953080772, -247.60965512377 ], [ - -15.183983237537262, - -255.2613583327868 + -15.1839832375373, + -255.261358332787 ], [ - -19.822722086570074, - -258.6729952966697 + -19.8227220865701, + -258.67299529667 ], [ - -24.279515332983824, - -261.70335578638884 + -24.2795153329838, + -261.703355786389 ], [ - -29.011437974400625, - -263.89076106496833 + -29.0114379744006, + -263.890761064968 ] ], - "speed": 12.0, - "interval": 1.5 + "speed": 12.0 }, { + "interval": 1.8, "pts": [ [ - 20.772447151780117, - -199.75931223039953 + 20.7724471517801, + -199.7593122304 ], [ - 19.423377981138138, - -213.23286388675078 + 19.4233779811381, + -213.232863886751 ], [ - 17.78654515972297, - -225.7924522932427 + 17.786545159723, + -225.792452293243 ], [ - 16.46063564037367, - -237.18991410136036 + 16.4606356403737, + -237.18991410136 ] ], - "speed": 11.0, - "interval": 1.8 + "speed": 11.0 }, { + "interval": 1.8, "pts": [ [ - -26.737042902514784, - -268.7884265350654 + -26.7370429025148, + -268.788426535065 ], [ - -21.61124337794858, - -266.3980682135746 + -21.6112433779486, + -266.398068213575 ], [ - -16.704188313209045, - -263.0814811029762 + -16.704188313209, + -263.081481102976 ], [ - -11.761774350471743, - -259.43849686691397 + -11.7617743504717, + -259.438496866914 ], [ - -2.7224195143774796, - -251.63195487598963 + -2.72241951437748, + -251.63195487599 ], [ - 0.9839307874462617, - -248.02422063236523 + 0.983930787446262, + -248.024220632365 ], [ - 5.4649806575202335, - -244.6282780101317 + 5.46498065752023, + -244.628278010132 ] ], - "speed": 11.0, - "interval": 1.8 + "speed": 11.0 }, { + "interval": 1.5, "pts": [ [ - 11.27070084290225, - -197.84784324166512 + 11.2707008429023, + -197.847843241665 ], [ - 10.896175804718348, - -204.76641770228525 + 10.8961758047183, + -204.766417702285 ], [ - 10.476477879675205, - -211.20975788808624 + 10.4764778796752, + -211.209757888086 ], [ 9.92304078347784, - -216.20700696593718 + -216.207006965937 ], [ - 8.932958301853615, - -221.62531766816238 + 8.93295830185362, + -221.625317668162 ], [ - 7.508738699199866, - -226.8653717079938 + 7.50873869919987, + -226.865371707994 ] ], - "speed": 12.0, - "interval": 1.5 + "speed": 12.0 }, { + "interval": 1.5, "pts": [ [ - 28.875188928696993, - -229.49242546244793 + 28.875188928697, + -229.492425462448 ], [ - 28.72548025209394, - -214.05366159277472 + 28.7254802520939, + -214.053661592775 ], [ - 28.150874632761848, - -209.45956029627345 + 28.1508746327618, + -209.459560296273 ], [ - 27.279147353059784, - -204.7812989955361 + 27.2791473530598, + -204.781298995536 ], [ - 26.094879529030933, - -199.44340263065618 + 26.0948795290309, + -199.443402630656 ] ], - "speed": 12.0, - "interval": 1.5 + "speed": 12.0 } ], "targets": [ - 15000, - 35000, - 60000 + 5000, + 7500, + 11500 ] } -] \ No newline at end of file +] diff --git a/levels/woolies_carpark/junctions.json b/levels/woolies_carpark/junctions.json index 0292ea6..5669850 100644 --- a/levels/woolies_carpark/junctions.json +++ b/levels/woolies_carpark/junctions.json @@ -1,13 +1,74 @@ [ { "name": "Trolley Run", - "spawn": {"x": 33.0, "z": 52.0, "dx": 0.0, "dz": -1.0}, + "spawn": { + "dx": 0.0, + "dz": -1.0, + "x": 33.0, + "z": 52.0 + }, "streams": [ - {"pts": [[-70.0, 15.0], [70.0, 15.0]], "speed": 11.0, "interval": 2.0}, - {"pts": [[70.0, 12.0], [-70.0, 12.0]], "speed": 12.0, "interval": 2.4}, - {"pts": [[-70.0, -21.0], [70.0, -21.0]], "speed": 10.0, "interval": 2.2}, - {"pts": [[70.0, -24.0], [-70.0, -24.0]], "speed": 12.0, "interval": 2.8} + { + "interval": 2.0, + "pts": [ + [ + -70.0, + 15.0 + ], + [ + 70.0, + 15.0 + ] + ], + "speed": 11.0 + }, + { + "interval": 2.4, + "pts": [ + [ + 70.0, + 12.0 + ], + [ + -70.0, + 12.0 + ] + ], + "speed": 12.0 + }, + { + "interval": 2.2, + "pts": [ + [ + -70.0, + -21.0 + ], + [ + 70.0, + -21.0 + ] + ], + "speed": 10.0 + }, + { + "interval": 2.8, + "pts": [ + [ + 70.0, + -24.0 + ], + [ + -70.0, + -24.0 + ] + ], + "speed": 12.0 + } ], - "targets": [8000, 20000, 40000] + "targets": [ + 12500, + 15000, + 46000 + ] } ] diff --git a/src/deform.gd b/src/deform.gd index 79c3966..af542b4 100644 --- a/src/deform.gd +++ b/src/deform.gd @@ -16,6 +16,10 @@ extends RefCounted ## ## ponytail: normals are left alone. Recomputing them per impact costs more than ## it buys at this crumple scale; revisit if the shading reads flat. +## ponytail: _write() rebuilds a whole ArrayMesh via add_surface_from_arrays(), +## which takes no LOD or shadow-mesh argument -- a deformable car therefore loses +## any LODs its import generated. Harmless for the procedural fleet (no LODs to +## lose) but worth knowing before wiring the deformer to a dense imported model. const ALPHA := 2.0 # distance falloff exponent; PDF suggests 1.0-3.0 const NEAR := 4 # control points blended per vertex @@ -34,6 +38,7 @@ var _meshes: Array = [] # one entry per MeshInstance3D, all its surfaces toget var _cp := PackedVector3Array() var _disp := PackedVector3Array() var _ok := false +var _root: Node3D = null # the car model; panels reparented away stop deforming var _skins: Array = [] # {mat, albedo, rough}: per-car material copies to dirty up var damage := 0.0 # 0..1, drives the paint getting scratched and dulled @@ -126,6 +131,7 @@ func setup(root: Node3D) -> bool: (m["mi"] as MeshInstance3D).mesh = copy m["mesh"] = copy _meshes.append(m) + _root = root _ok = true _write() return true @@ -198,6 +204,12 @@ func _wear() -> void: m.detail_enabled = damage > 0.35 func _write() -> void: + # car.gd reparents det_* panels onto their own RigidBody when shed and frees + # them seconds later; left in the list they'd be debris still being crumpled + # by a car they've come off, and eventually freed nodes being written to + if is_instance_valid(_root): + _meshes = _meshes.filter(func(m) -> bool: + return is_instance_valid(m["mi"]) and _root.is_ancestor_of(m["mi"])) for m in _meshes: var mesh: ArrayMesh = m["mesh"] var inv: Transform3D = (m["xform"] as Transform3D).affine_inverse() diff --git a/src/game.gd b/src/game.gd index 13438e8..d947e65 100644 --- a/src/game.gd +++ b/src/game.gd @@ -269,11 +269,16 @@ func _ready() -> void: add_child(path) var L := curve.get_baked_length() var headway: float = stream["speed"] * stream["interval"] - var n: int = clampi(int(L / headway), 1, 14) + # At least 3 per stream, spaced to fit. int(L / headway) floors to 1 + # on a short clipped stream, which is how Grey x Glenelg ended up + # with 9 convoy cars against the usual 20-25 and gaps wide enough to + # drive clean through -- it scored nothing in 12 of 12 tuning runs. + var n: int = clampi(int(L / headway), 3, 14) + var spacing := L / float(n) for i in n: var t := TrafficCar.new() t.path = path - t.offset = fposmod(i * headway, L) + t.offset = fposmod(i * spacing, L) t.speed = stream["speed"] t.model_idx = midx midx += 1 diff --git a/tools/osm_junction.py b/tools/osm_junction.py index b83982d..1d7e674 100644 --- a/tools/osm_junction.py +++ b/tools/osm_junction.py @@ -87,7 +87,14 @@ def launch_point(pts, jpt): end = [end[0] + dx / L * grow, end[1] + dz / L * grow] dx, dz = jpt[0] - end[0], jpt[1] - end[1] L = math.hypot(dx, dz) or 1.0 - return {"x": end[0], "z": end[1], "dx": dx / L, "dz": dz / L} + dx, dz = dx / L, dz / L + # Sit in a lane, not on the centreline. Convoys are offset +/-LANE either + # side, so a centreline launch threads straight between them -- Grey x + # Glenelg passed within 2.9 m of a convoy car and never touched one, + # scoring nothing in 12 of 12 tuning runs. Same transform as offset(). + # sign matters: offsetting the other way moved the launch AWAY from the + # convoy lane and widened Grey x Glenelg's closest pass from 2.9 m to 5.5 m + return {"x": end[0] - dz * LANE, "z": end[1] + dx * LANE, "dx": dx, "dz": dz} events = [] for spec in sys.argv[5:]: