// Every spatial (pixel) constant in this file and in src/data/levels/*.js is // multiplied by WORLD_SCALE, so the whole game - canvas, physics bodies, // terrain, UI - resizes together. Change this one number to rescale it again. export const WORLD_SCALE = 2; // 960x540 base design -> 1920x1080 export const GAME_WIDTH = 960 * WORLD_SCALE; export const GAME_HEIGHT = 540 * WORLD_SCALE; // Set true to show live g-force / debug readouts during PlayScene. export const DEBUG = false; export const STORAGE_KEY = 'monsterplex.progress.v1'; // Matter runs Phaser's default fixed 60Hz step. export const PHYSICS_TIMESTEP_SECONDS = 1 / 60; export const BUS = { chassisWidth: 170 * WORLD_SCALE, chassisHeight: 64 * WORLD_SCALE, // Measured directly from assets/sprites/bus_chassis.png's baked-in wheel // wells (it's a real photo bus - long rear overhang, short front hood, so // the axles are NOT symmetric around the chassis center). Offsets are from // the chassis center; re-measure these if bus_chassis.png is replaced. wheelRadius: 17 * WORLD_SCALE, rearWheelOffsetX: -35 * WORLD_SCALE, frontWheelOffsetX: 64 * WORLD_SCALE, // Where the wheel's CENTER rests at equilibrium - this is the measured // wheel-well position itself, not an attachment point the wheel then // hangs further below (that was the placeholder-art version's model, // before there was real art dictating exactly where the wheel belongs). wheelRestOffsetY: 22 * 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 // by two constraints spread by this much, which resists side-to-side // wander while still allowing the wheel to compress/extend vertically. axleSpread: 6 * WORLD_SCALE, maxSeats: 5, // Density/friction/stiffness/damping are dimensionless ratios, not pixel // distances - they don't scale with WORLD_SCALE. chassisDensity: 0.0015, chassisFriction: 0.4, chassisFrictionAir: 0.01, wheelDensity: 0.004, wheelFriction: 0.9, wheelFrictionStatic: 1.4, // Lowered a lot from the original 0.02 - that was quietly eating most of // the wheel's spin-up each second (it's a per-tick multiplicative decay, // so 0.02 was burning off roughly a third of angular velocity per second) // and was the main reason the bus felt sluggish rather than Trials-fast. wheelFrictionAir: 0.008, // Some bounce on landing, not just suspension absorbing everything. wheelRestitution: 0.3, // Softer and less damped than before - more travel, and lets it actually // oscillate (bounce) instead of settling immediately - "more shocks." suspensionStiffness: 0.45, suspensionDamping: 0.08, // How far the wheel can move up/down from wheelRestOffsetY. This will // visibly pop the wheel outside its wheel well on a hard landing - that's // the tradeoff for real suspension travel/bounce instead of a stiff ride. suspensionTravel: 12 * WORLD_SCALE, // Angular velocities/torque steps are rotational (radians), not linear // pixel distances, so they're left unscaled - wheel radius already scaled, // so linear surface speed (angularVelocity * radius) scales automatically. // Pushed way up from the original values for Trials/Snuggle-Truck-style // speed - the old numbers made the bus crawl. maxWheelAngularVelocity: 5, driveTorque: 0.6, brakeTorque: 0.4, maxBrakeAngularVelocity: 3.5, // Measured via headless testing: spinning the wheel faster alone barely // moved the chassis - past a point the wheel just slips (friction force // is capped by frictionCoefficient * normalForce regardless of how fast // the wheel spins beyond matching ground speed), so throttle applies a // direct force to the chassis itself, along its current facing/tilt, on // top of the wheel spin. This is the standard fix in arcade 2D driving // games for exactly this problem. Expressed as target acceleration // (Bus.js computes force = chassis mass * this) rather than a raw force, // so it stays correct if chassisDensity/size ever changes - tune these // to change top speed feel. driveAcceleration: 0.011, brakeAcceleration: 0.007, // Bumped up to stay responsive at the new higher speed - sluggish lean // control would feel wrong on a bus that's now moving quickly. maxLeanAngularVelocity: 0.13, leanTorqueStep: 0.018, }; export const GFORCE = { // Scaled with WORLD_SCALE so "meters" keeps the same real-world meaning // relative to the bus, and ejectThresholdG doesn't need re-tuning. pixelsPerMeter: 50 * WORLD_SCALE, ejectThresholdG: 6, // primary tuning knob - not physically derived, tune by playtesting gracePeriodMs: 500, ejectImpulseMagnitude: 0.03 * WORLD_SCALE, // A single hard landing can stay above threshold for several consecutive // physics ticks; without a cooldown that would eject several kids from one // impact instead of one. Debounces ejections to one per impact. ejectCooldownMs: 400, }; export const KID = { radius: 14 * WORLD_SCALE, density: 0.001, friction: 0.6, seatStiffness: 0.22, seatDamping: 0.1, seatLength: 4 * WORLD_SCALE, settleTimeMs: 2000, }; export const CAMERA = { lerpX: 0.1, lerpY: 0.1, deadzoneWidth: 220 * WORLD_SCALE, deadzoneHeight: 140 * WORLD_SCALE, }; export const TERRAIN_DEPTH = 400 * WORLD_SCALE;