Make ship physics constants configurable via GameConfig with UI
All checks were successful
Build / build (push) Successful in 1m14s

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>
This commit is contained in:
Michael Mainguy 2025-11-07 13:05:27 -06:00
parent 72573054dd
commit 0988805652
4 changed files with 94 additions and 12 deletions

View File

@ -349,6 +349,46 @@
</div>
</div>
<!-- Ship Physics Settings -->
<div class="section">
<h2>🚀 Ship Physics</h2>
<p style="color: #aaa; font-size: 0.9em; margin-bottom: 20px;">
Advanced tuning parameters for ship movement and handling. Adjust these to customize how the ship responds to controls.
</p>
<div class="form-group">
<label for="maxLinearVelocity">Max Linear Velocity</label>
<input type="number" id="maxLinearVelocity" value="200" step="10" min="50" max="1000">
<div class="help-text">
Maximum forward/backward speed of the ship. Higher values allow faster movement.
</div>
</div>
<div class="form-group">
<label for="maxAngularVelocity">Max Angular Velocity</label>
<input type="number" id="maxAngularVelocity" value="1.4" step="0.1" min="0.5" max="5.0">
<div class="help-text">
Maximum rotation speed of the ship. Higher values allow faster turning.
</div>
</div>
<div class="form-group">
<label for="linearForceMultiplier">Linear Force Multiplier</label>
<input type="number" id="linearForceMultiplier" value="800" step="50" min="100" max="3000">
<div class="help-text">
Acceleration power for forward/backward thrust. Higher values = faster acceleration.
</div>
</div>
<div class="form-group">
<label for="angularForceMultiplier">Angular Force Multiplier</label>
<input type="number" id="angularForceMultiplier" value="15" step="1" min="5" max="50">
<div class="help-text">
Torque power for rotation. Higher values = faster rotational acceleration.
</div>
</div>
</div>
<!-- Info Section -->
<div class="section">
<h2> Quality Level Guide</h2>

View File

@ -9,6 +9,14 @@ export class GameConfig {
// Physics settings
public physicsEnabled: boolean = true;
// Ship physics tuning parameters
public shipPhysics = {
maxLinearVelocity: 200,
maxAngularVelocity: 1.4,
linearForceMultiplier: 800,
angularForceMultiplier: 15
};
/**
* Private constructor for singleton pattern
*/
@ -33,7 +41,8 @@ export class GameConfig {
public save(): void {
const config = {
physicsEnabled: this.physicsEnabled,
debug: this.debug
debug: this.debug,
shipPhysics: this.shipPhysics
};
localStorage.setItem('game-config', JSON.stringify(config));
}
@ -48,6 +57,16 @@ export class GameConfig {
const config = JSON.parse(stored);
this.physicsEnabled = config.physicsEnabled ?? true;
this.debug = config.debug ?? false;
// Load ship physics with fallback to defaults
if (config.shipPhysics) {
this.shipPhysics = {
maxLinearVelocity: config.shipPhysics.maxLinearVelocity ?? 200,
maxAngularVelocity: config.shipPhysics.maxAngularVelocity ?? 1.4,
linearForceMultiplier: config.shipPhysics.linearForceMultiplier ?? 800,
angularForceMultiplier: config.shipPhysics.angularForceMultiplier ?? 15
};
}
} else {
this.save();
}
@ -62,6 +81,12 @@ export class GameConfig {
public reset(): void {
this.physicsEnabled = true;
this.debug = false;
this.shipPhysics = {
maxLinearVelocity: 200,
maxAngularVelocity: 1.4,
linearForceMultiplier: 800,
angularForceMultiplier: 15
};
this.save();
}
}

View File

@ -10,6 +10,12 @@ export function initializeSettingsScreen(): void {
const physicsEnabledCheckbox = document.getElementById('physicsEnabled') as HTMLInputElement;
const debugEnabledCheckbox = document.getElementById('debugEnabled') as HTMLInputElement;
// Ship physics inputs
const maxLinearVelocityInput = document.getElementById('maxLinearVelocity') as HTMLInputElement;
const maxAngularVelocityInput = document.getElementById('maxAngularVelocity') as HTMLInputElement;
const linearForceMultiplierInput = document.getElementById('linearForceMultiplier') as HTMLInputElement;
const angularForceMultiplierInput = document.getElementById('angularForceMultiplier') as HTMLInputElement;
const saveBtn = document.getElementById('saveSettingsBtn');
const resetBtn = document.getElementById('resetSettingsBtn');
const messageDiv = document.getElementById('settingsMessage');
@ -38,6 +44,12 @@ export function initializeSettingsScreen(): void {
function loadSettings(): void {
if (physicsEnabledCheckbox) physicsEnabledCheckbox.checked = config.physicsEnabled;
if (debugEnabledCheckbox) debugEnabledCheckbox.checked = config.debug;
// Load ship physics settings
if (maxLinearVelocityInput) maxLinearVelocityInput.value = config.shipPhysics.maxLinearVelocity.toString();
if (maxAngularVelocityInput) maxAngularVelocityInput.value = config.shipPhysics.maxAngularVelocity.toString();
if (linearForceMultiplierInput) linearForceMultiplierInput.value = config.shipPhysics.linearForceMultiplier.toString();
if (angularForceMultiplierInput) angularForceMultiplierInput.value = config.shipPhysics.angularForceMultiplier.toString();
}
/**
@ -46,6 +58,13 @@ export function initializeSettingsScreen(): void {
function saveSettings(): void {
config.physicsEnabled = physicsEnabledCheckbox.checked;
config.debug = debugEnabledCheckbox.checked;
// Save ship physics settings
config.shipPhysics.maxLinearVelocity = parseFloat(maxLinearVelocityInput.value);
config.shipPhysics.maxAngularVelocity = parseFloat(maxAngularVelocityInput.value);
config.shipPhysics.linearForceMultiplier = parseFloat(linearForceMultiplierInput.value);
config.shipPhysics.angularForceMultiplier = parseFloat(angularForceMultiplierInput.value);
config.save();
}

View File

@ -1,10 +1,5 @@
import { PhysicsBody, TransformNode, Vector2, Vector3 } from "@babylonjs/core";
// Physics constants
const MAX_LINEAR_VELOCITY = 200;
const MAX_ANGULAR_VELOCITY = 1.4;
const LINEAR_FORCE_MULTIPLIER = 800;
const ANGULAR_FORCE_MULTIPLIER = 15;
import { GameConfig } from "./gameConfig";
export interface InputState {
leftStick: Vector2;
@ -18,7 +13,7 @@ export interface ForceApplicationResult {
/**
* Handles physics force calculations and application for the ship
* Pure calculation logic with no external dependencies
* Reads physics parameters from GameConfig for runtime tuning
*/
export class ShipPhysics {
/**
@ -39,6 +34,9 @@ export class ShipPhysics {
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();
@ -52,7 +50,7 @@ export class ShipPhysics {
linearMagnitude = Math.abs(leftStick.y);
// Only apply force if we haven't reached max velocity
if (currentSpeed < MAX_LINEAR_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
@ -60,7 +58,7 @@ export class ShipPhysics {
localDirection,
transformNode.getWorldMatrix()
);
const force = worldDirection.scale(LINEAR_FORCE_MULTIPLIER);
const force = worldDirection.scale(config.linearForceMultiplier);
// Calculate thrust point: center of mass + offset (0, 1, 0) in world space
const thrustPoint = Vector3.TransformCoordinates(
@ -83,14 +81,14 @@ export class ShipPhysics {
const currentAngularSpeed = currentAngularVelocity.length();
// Only apply torque if we haven't reached max angular velocity
if (currentAngularSpeed < 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(
ANGULAR_FORCE_MULTIPLIER
config.angularForceMultiplier
);
const worldTorque = Vector3.TransformNormal(
localTorque,