169 lines
7.8 KiB
JavaScript
169 lines
7.8 KiB
JavaScript
// 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. Raised from the
|
|
// wheel-well-measured 22 to 34 to lift the chassis and drop the tires
|
|
// further down for a bouncier stance - this now visibly departs from
|
|
// 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,
|
|
// 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,
|
|
|
|
// The invisible box kids ride in, local to the chassis (0,0 = chassis
|
|
// center, y down): solid floor + left/right walls, but deliberately no
|
|
// ceiling fixture at all - see Bus.js's _buildCompartment. A kid whose
|
|
// own local Y (rotation-corrected relative to the chassis) rises above
|
|
// compartmentTopY has nothing left to collide with and is airborne; the
|
|
// same check runs both directions each tick (see KidManager), so falling
|
|
// back below it while inside compartmentHalfWidth re-contains the kid.
|
|
// Tune by playtesting - not physically derived.
|
|
compartmentHalfWidth: 75 * WORLD_SCALE,
|
|
compartmentWallThickness: 10 * WORLD_SCALE,
|
|
compartmentFloorThickness: 10 * WORLD_SCALE,
|
|
compartmentFloorY: 12 * WORLD_SCALE,
|
|
compartmentTopY: -60 * WORLD_SCALE,
|
|
|
|
// 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.45,
|
|
|
|
// Softer and less damped than before - more travel, and lets it actually
|
|
// oscillate (bounce) instead of settling immediately - "more shocks."
|
|
suspensionStiffness: 0.35,
|
|
suspensionDamping: 0.035,
|
|
// 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: 30 * 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.
|
|
// Cut by ~60% (0.011 -> 0.0045) for a much longer runway to top speed.
|
|
// Note this also lowers the top speed itself, not just the time to reach
|
|
// it - top speed is where this force balances chassisFrictionAir drag, so
|
|
// a smaller force settles at a lower equilibrium speed too.
|
|
driveAcceleration: 0.0045,
|
|
brakeAcceleration: 0.007,
|
|
|
|
// Cut by more than half (both the cap and the per-tick torque step) for a
|
|
// much slower, more gradual lean - easier to fine-tune mid-air at the
|
|
// cost of snappiness.
|
|
maxLeanAngularVelocity: 0.06,
|
|
leanTorqueStep: 0.004,
|
|
};
|
|
|
|
// Kid ejection is no longer impact-triggered (see KidManager/Bus's
|
|
// compartment box) - GFORCE now only drives the DEBUG g-force readout in
|
|
// PlayScene, kept because it's still a useful "how hard did that landing
|
|
// hit" diagnostic on its own.
|
|
export const GFORCE = {
|
|
// Scaled with WORLD_SCALE so "meters" keeps the same real-world meaning
|
|
// relative to the bus.
|
|
pixelsPerMeter: 50 * WORLD_SCALE,
|
|
gracePeriodMs: 500,
|
|
};
|
|
|
|
export const KID = {
|
|
radius: 14 * WORLD_SCALE,
|
|
density: 0.001,
|
|
friction: 0.6,
|
|
// While outside the compartment (past the open top - see
|
|
// BUS.compartmentTopY), a kid ignores the world's real gravity entirely
|
|
// and KidManager applies this fraction of it instead (see
|
|
// KidManager._onBeforeUpdate) - horizontal velocity is untouched either
|
|
// way (this game's gravity is purely vertical), so a lighter fall is all
|
|
// it takes for a kid to hang in the air and arc much further than the
|
|
// bus does, Snuggle-Truck style. Primary tuning knob for "how floaty,"
|
|
// not physically derived.
|
|
ejectedGravityScale: 0.35,
|
|
};
|
|
|
|
export const CAMERA = {
|
|
lerpX: 0.1,
|
|
lerpY: 0.1,
|
|
// Horizontal position is speed-driven (see CameraRig.update - it steers
|
|
// via followOffset.x) rather than a dead zone, so this is kept tiny
|
|
// rather than removed, just to dodge exact-equality edge cases in
|
|
// Phaser's deadzone math. Vertical still uses a real dead zone below.
|
|
deadzoneWidth: 2 * WORLD_SCALE,
|
|
deadzoneHeight: 140 * WORLD_SCALE,
|
|
|
|
// Where the bus sits on screen, as a fraction of screen width from the
|
|
// left edge - primary tuning knobs, not physically derived, tune by
|
|
// playtesting. restScreenFraction leaves enough room for the chassis
|
|
// (half its width is ~0.09 of the screen) not to clip off the left edge
|
|
// while still reading as "almost touching."
|
|
restScreenFraction: 0.1,
|
|
maxSpeedScreenFraction: 1 / 3,
|
|
// Horizontal chassis speed (px/s) at which framing reaches
|
|
// maxSpeedScreenFraction; clamped beyond it. There's no hard speed cap in
|
|
// the drive physics (chassisFrictionAir just balances driveAcceleration
|
|
// out asymptotically), so this is a starting estimate - tune by
|
|
// playtesting alongside the fractions above.
|
|
lookaheadMaxSpeed: 110 * WORLD_SCALE,
|
|
};
|
|
|
|
export const TERRAIN_DEPTH = 400 * WORLD_SCALE;
|