space-game/src/shipPhysics.ts
Michael Mainguy 0988805652
All checks were successful
Build / build (push) Successful in 1m14s
Make ship physics constants configurable via GameConfig with UI
Implemented Option 5: Integrate ship physics constants into centralized GameConfig

Changes to gameConfig.ts:
- Added shipPhysics object with 4 tunable parameters:
  - maxLinearVelocity (default: 200)
  - maxAngularVelocity (default: 1.4)
  - linearForceMultiplier (default: 800)
  - angularForceMultiplier (default: 15)
- Updated save() to persist shipPhysics to localStorage
- Updated loadFromStorage() to load shipPhysics with fallback defaults
- Updated reset() to restore shipPhysics defaults

Changes to shipPhysics.ts:
- Removed hardcoded constants
- Added GameConfig import
- Updated applyForces() to read values from GameConfig.getInstance().shipPhysics
- Now reads physics parameters dynamically at runtime

Changes to index.html:
- Added Ship Physics section in Settings UI
- 4 number inputs with appropriate min/max/step values
- Help text explaining each parameter's effect on ship handling
- Section positioned after Developer settings

Changes to settingsScreen.ts:
- Added input element references for ship physics controls
- Updated loadSettings() to populate ship physics inputs from config
- Updated saveSettings() to save ship physics values to config
- Values persist across sessions via localStorage

Benefits:
- Ship physics now tunable in real-time via settings UI
- Parameters persist across sessions
- Easy to reset to defaults
- Centralized configuration management
- No need to edit code to adjust ship handling

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 13:05:27 -06:00

108 lines
3.8 KiB
TypeScript

import { PhysicsBody, TransformNode, Vector2, Vector3 } from "@babylonjs/core";
import { GameConfig } from "./gameConfig";
export interface InputState {
leftStick: Vector2;
rightStick: Vector2;
}
export interface ForceApplicationResult {
linearMagnitude: number;
angularMagnitude: number;
}
/**
* Handles physics force calculations and application for the ship
* Reads physics parameters from GameConfig for runtime tuning
*/
export class ShipPhysics {
/**
* Apply forces to the ship based on input state
* @param inputState - Current input state (stick positions)
* @param physicsBody - Physics body to apply forces to
* @param transformNode - Transform node for world space calculations
* @returns Force magnitudes for audio feedback
*/
public applyForces(
inputState: InputState,
physicsBody: PhysicsBody,
transformNode: TransformNode
): ForceApplicationResult {
if (!physicsBody) {
return { linearMagnitude: 0, angularMagnitude: 0 };
}
const { leftStick, rightStick } = inputState;
// Get physics config
const config = GameConfig.getInstance().shipPhysics;
// Get current velocities for velocity cap checks
const currentLinearVelocity = physicsBody.getLinearVelocity();
const currentAngularVelocity = physicsBody.getAngularVelocity();
const currentSpeed = currentLinearVelocity.length();
let linearMagnitude = 0;
let angularMagnitude = 0;
// Apply linear force from left stick Y (forward/backward)
if (Math.abs(leftStick.y) > 0.1) {
linearMagnitude = Math.abs(leftStick.y);
// Only apply force if we haven't reached max velocity
if (currentSpeed < config.maxLinearVelocity) {
// Get local direction (Z-axis for forward/backward thrust)
const localDirection = new Vector3(0, 0, -leftStick.y);
// Transform to world space
const worldDirection = Vector3.TransformNormal(
localDirection,
transformNode.getWorldMatrix()
);
const force = worldDirection.scale(config.linearForceMultiplier);
// Calculate thrust point: center of mass + offset (0, 1, 0) in world space
const thrustPoint = Vector3.TransformCoordinates(
physicsBody.getMassProperties().centerOfMass.add(new Vector3(0, 1, 0)),
transformNode.getWorldMatrix()
);
physicsBody.applyForce(force, thrustPoint);
}
}
// Calculate rotation magnitude for torque
angularMagnitude =
Math.abs(rightStick.y) +
Math.abs(rightStick.x) +
Math.abs(leftStick.x);
// Apply angular forces if any stick has significant rotation input
if (angularMagnitude > 0.1) {
const currentAngularSpeed = currentAngularVelocity.length();
// Only apply torque if we haven't reached max angular velocity
if (currentAngularSpeed < config.maxAngularVelocity) {
const yaw = -leftStick.x;
const pitch = rightStick.y;
const roll = rightStick.x;
// Create torque in local space, then transform to world space
const localTorque = new Vector3(pitch, yaw, roll).scale(
config.angularForceMultiplier
);
const worldTorque = Vector3.TransformNormal(
localTorque,
transformNode.getWorldMatrix()
);
physicsBody.applyAngularImpulse(worldTorque);
}
}
return {
linearMagnitude,
angularMagnitude,
};
}
}