From 8cba62923296e143909ec15afe4c72126b5faa42 Mon Sep 17 00:00:00 2001 From: Brian Fertig Date: Sun, 23 Aug 2026 18:39:07 -0600 Subject: [PATCH] Add "lift kit" for Campaign 2 bus Campaign 2's larger wheels now hang further under the chassis via a new `wheelRestOffsetY` theme knob (42 vs 34 design units), making the bus visibly sit taller. The wishbone anchor and initial wheel position derive from this per-campaign offset, so both size and mount point stay correctly centered on the axle line. - Add `BUS.wheelRestOffsetY2` in config - Expose `wheelRestOffsetY` in theme `bus` blocks (default = campaign 1) - Use themed offset in Bus constructor for anchor and wheel placement - Update docs/comments to explain the lift-kit behavior --- sprites.md | 9 ++++++--- src/config.js | 4 ++++ src/data/themes.js | 13 ++++++++++--- src/entities/Bus.js | 35 ++++++++++++++++++++++------------- 4 files changed, 42 insertions(+), 19 deletions(-) diff --git a/sprites.md b/sprites.md index dd7fe56..32506f9 100644 --- a/sprites.md +++ b/sprites.md @@ -46,10 +46,13 @@ with it (same ratios, just re-derive from that one constant). speed than fine detail. - Campaign 2 uses its own wheel image, `bus_wheel_2.png` (bigger - it's displayed at a ~1.2x radius around the same axle center, selected via the - `bus` block in `src/data/themes.js`), and its own chassis image, + `bus` block in `src/data/themes.js`), its own chassis image, `bus_chassis_2.png` (same 340x128 design box, physics body unchanged - - only the texture is swapped per campaign). - Both wheels still share one image per campaign. + only the texture is swapped per campaign), and a "lift kit": the wheel + mount point sits ~8 design units lower under the chassis (see + `wheelRestOffsetY2` in `src/config.js` and the `bus` block in + `src/data/themes.js`), so it reads as a lifted bus. Both wheels still + share one image per campaign. - If you want a bus with different proportions (longer, taller, etc.) than 340x128, tell me the size you want art at - that number is also the physics body size in `src/config.js` (`BUS.chassisWidth`/`chassisHeight`), so it diff --git a/src/config.js b/src/config.js index dcfa485..0b3a043 100644 --- a/src/config.js +++ b/src/config.js @@ -41,6 +41,10 @@ export const BUS = { // bus_chassis.png's painted wheel wells (a gap opens above the tire), // a deliberate look/feel tradeoff rather than a measurement. wheelRestOffsetY: 34 * WORLD_SCALE, + // Campaign 2's "lift kit": the same mount point 8 design units lower + // (see `bus` in data/themes.js), so the bigger wheels hang further under + // the chassis and the bus visibly sits taller. + wheelRestOffsetY2: 42 * WORLD_SCALE, // Horizontal spread between the two suspension links each wheel hangs // from (a "wishbone") - a single point-to-point constraint can't resist // sideways drift at all (it's radially symmetric), so each wheel is held diff --git a/src/data/themes.js b/src/data/themes.js index 4a5f324..8b866c8 100644 --- a/src/data/themes.js +++ b/src/data/themes.js @@ -82,13 +82,16 @@ export const DEFAULT_THEME = { // `chassisKey` is the chassis texture (purely visual - the physics body // stays the same BUS.chassisWidth/Height rectangle either way); // `wheelTextureKey` is the texture both wheels render with; `wheelRadius` - // is the physics/display radius in world pixels. Changing the radius - // keeps the wheel centered on the same spot (the wishbone anchors and - // wheelRestOffsetY are radius-agnostic) - only the size changes. + // is the physics/display radius in world pixels; `wheelRestOffsetY` is + // the wheel mount point, local to the chassis (y down) - raising it is + // the "lift kit" knob (campaign 2). A bigger radius keeps the wheel + // centered on its axle (the wishbone anchors derive from these + // offsets, so they stay put) - only the size changes. bus: { chassisKey: 'bus_chassis', wheelTextureKey: 'bus_wheel', wheelRadius: BUS.wheelRadius, + wheelRestOffsetY: BUS.wheelRestOffsetY, }, // The three parallax layers, back to front. `far` is the full-viewport // sky; `mid`/`near` are bottom-anchored ground tiles (see PlayScene's @@ -122,6 +125,10 @@ export const THEMES = { chassisKey: 'bus_chassis_2', wheelTextureKey: 'bus_wheel_2', wheelRadius: BUS.wheelRadius2, + // "Lift kit": drop the wheel mount point 8 design units below + // campaign 1's (see BUS.wheelRestOffsetY2) - the bus sits taller and + // the bigger wheels hang lower under the body. + wheelRestOffsetY: BUS.wheelRestOffsetY2, }, }, // Add campaign03: { ... } here when it's ready. diff --git a/src/entities/Bus.js b/src/entities/Bus.js index 076ddaa..742e391 100644 --- a/src/entities/Bus.js +++ b/src/entities/Bus.js @@ -11,20 +11,26 @@ export default class Bus { constructor(scene, x, y, angle = 0, busTheme = null) { this.scene = scene; const matter = scene.matter; - // Per-campaign bus look (see `bus` in data/themes.js): which chassis - // texture and wheel texture to render and the physics/display wheel - // radius. Defaults to campaign 1's values, so existing callers (and - // any bus built outside a themed scene) are unchanged. The chassis - // texture is visual only - the physics body stays the same - // BUS.chassisWidth/Height rectangle either way. NOTE: only the wheel - // size varies - the wheel's CENTER is anchored to the chassis via the - // wishbone below (anchorY/wheelRestOffsetY are radius-agnostic), so a - // bigger radius grows the wheel around the same center, exactly as - // intended. - const { chassisKey = 'bus_chassis', wheelTextureKey = 'bus_wheel', wheelRadius = BUS.wheelRadius } = busTheme || {}; + // Per-campaign bus look (see `bus` in data/themes.js): chassis and + // wheel texture, the physics/display wheel radius, and the wheel + // mount point (wheelRestOffsetY - campaign 2's "lift kit", which drops + // the wheels further under the chassis). Defaults to campaign 1's + // values, so existing callers (and any bus built outside a themed + // scene) are unchanged. The chassis texture is visual only - the + // physics body stays the same BUS.chassisWidth/Height rectangle + // either way. (The wishbone anchors below are DERIVED from these + // values, so a bigger radius and/or a lower mount point both stay + // correctly centered on the same axle line.) + const { + chassisKey = 'bus_chassis', + wheelTextureKey = 'bus_wheel', + wheelRadius = BUS.wheelRadius, + wheelRestOffsetY = BUS.wheelRestOffsetY, + } = busTheme || {}; this.chassisKey = chassisKey; this.wheelTextureKey = wheelTextureKey; this.wheelRadius = wheelRadius; + this._wheelRestOffsetY = wheelRestOffsetY; this.group = matter.world.nextGroup(true); // Dedicated category so the compartment fixtures below can target kids @@ -50,7 +56,10 @@ export default class Bus { // so the spring pulling the wheel out to its full constraint length is // what lands it exactly on wheelRestOffsetY (anchorY + travel = restY), // while still leaving suspensionTravel of compress/droop room. - const anchorY = BUS.wheelRestOffsetY - BUS.suspensionTravel; + // this._wheelRestOffsetY is the campaign's mount point (the lift-kit + // knob) - raising it lowers the wheel under the chassis and, since + // the anchor rides with it, the bus visibly sits taller. + const anchorY = this._wheelRestOffsetY - BUS.suspensionTravel; // The wheel doesn't hang straight down from a single point (that point // is split into two, spread by axleSpread), so the constraint's target // length is the hypotenuse to the spread anchor, not just the vertical @@ -74,7 +83,7 @@ export default class Bus { // alpha. this.chassis.setDepth(2); - const wheelY = y + BUS.wheelRestOffsetY; + const wheelY = y + this._wheelRestOffsetY; this.wheelRear = this._createWheel(x + BUS.rearWheelOffsetX, wheelY, this.wheelTextureKey, this.wheelRadius); this.wheelFront = this._createWheel(x + BUS.frontWheelOffsetX, wheelY, this.wheelTextureKey, this.wheelRadius);