space-game/src/core/gameConfig.ts
Michael Mainguy e31e25f9e5 Fix physics issues: sleep behavior, center of mass, and input scaling
This commit resolves several physics-related issues that were causing
unexpected behavior in ship and asteroid movement:

**Physics Sleep System**
- Fixed abrupt stops by preventing Havok from putting bodies to sleep
- Added PhysicsActivationControl.ALWAYS_ACTIVE for ship and asteroids
- Made ship sleep behavior configurable via shipPhysics.alwaysActive
- Sleep was causing sudden velocity zeroing at low speeds

**Center of Mass Issues**
- Discovered mesh-based physics calculated offset CoM: (0, -0.38, 0.37)
- Override ship center of mass to (0, 0, 0) to prevent thrust torque
- Applying force at offset CoM was creating unwanted pitch rotation
- Added debug logging to track mass properties

**Input Deadzone Improvements**
- Implemented smooth deadzone scaling (0.1-0.15 range)
- Replaced hard threshold cliff with linear interpolation
- Prevents abrupt control cutoff during gentle inputs
- Added VR mode check to disable keyboard fallback in VR

**Configuration System**
- Added DEFAULT_SHIP_PHYSICS constant as single source of truth
- Added tunable parameters: linearDamping, angularDamping, alwaysActive
- Added fuel consumption rates: linearFuelConsumptionRate, angularFuelConsumptionRate
- Tuned for 1 minute linear thrust, 2 minutes angular thrust at 60Hz
- All physics parameters now persist to localStorage

**Other Fixes**
- Changed orbit center to STATIC motion type (was ANIMATED)
- Fixed linear force application point (removed offset)
- Added ship initial velocity support from level config
- Changed physics update from every 10 frames to every physics tick
- Increased linear input threshold from 0.1 to 0.15

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-24 14:03:32 -06:00

109 lines
4.0 KiB
TypeScript

/**
* Default ship physics configuration
*/
const DEFAULT_SHIP_PHYSICS = {
maxLinearVelocity: 200,
maxAngularVelocity: 1.4,
linearForceMultiplier: 100,
angularForceMultiplier: 1.5,
linearFuelConsumptionRate: 0.00002778, // 1 minute at full thrust (60 Hz)
angularFuelConsumptionRate: 0.0001389, // 2 minutes at full thrust (60 Hz)
linearDamping: 0.2,
angularDamping: 0.3, // Moderate damping for 2-3 second coast
alwaysActive: true // Prevent physics sleep (false may cause abrupt stops at zero velocity)
};
/**
* Global game configuration settings
* Singleton class for managing game-wide settings
*/
export class GameConfig {
private static _instance: GameConfig;
public debug: boolean = false;
// Physics settings
public physicsEnabled: boolean = true;
// Feature flags
public progressionEnabled: boolean = true; // Enable level progression system
// Ship physics tuning parameters
public shipPhysics = { ...DEFAULT_SHIP_PHYSICS };
/**
* Private constructor for singleton pattern
*/
private constructor() {
// Load settings from localStorage if available
this.loadFromStorage();
}
/**
* Get the singleton instance
*/
public static getInstance(): GameConfig {
if (!GameConfig._instance) {
GameConfig._instance = new GameConfig();
}
return GameConfig._instance;
}
/**
* Save current configuration to localStorage
*/
public save(): void {
const config = {
physicsEnabled: this.physicsEnabled,
debug: this.debug,
progressionEnabled: this.progressionEnabled,
shipPhysics: this.shipPhysics
};
localStorage.setItem('game-config', JSON.stringify(config));
}
/**
* Load configuration from localStorage
*/
private loadFromStorage(): void {
try {
const stored = localStorage.getItem('game-config');
if (stored) {
const config = JSON.parse(stored);
this.physicsEnabled = config.physicsEnabled ?? true;
this.debug = config.debug ?? false;
this.progressionEnabled = config.progressionEnabled ?? true;
// Load ship physics with fallback to defaults
if (config.shipPhysics) {
this.shipPhysics = {
maxLinearVelocity: config.shipPhysics.maxLinearVelocity ?? DEFAULT_SHIP_PHYSICS.maxLinearVelocity,
maxAngularVelocity: config.shipPhysics.maxAngularVelocity ?? DEFAULT_SHIP_PHYSICS.maxAngularVelocity,
linearForceMultiplier: config.shipPhysics.linearForceMultiplier ?? DEFAULT_SHIP_PHYSICS.linearForceMultiplier,
angularForceMultiplier: config.shipPhysics.angularForceMultiplier ?? DEFAULT_SHIP_PHYSICS.angularForceMultiplier,
linearFuelConsumptionRate: config.shipPhysics.linearFuelConsumptionRate ?? DEFAULT_SHIP_PHYSICS.linearFuelConsumptionRate,
angularFuelConsumptionRate: config.shipPhysics.angularFuelConsumptionRate ?? DEFAULT_SHIP_PHYSICS.angularFuelConsumptionRate,
linearDamping: config.shipPhysics.linearDamping ?? DEFAULT_SHIP_PHYSICS.linearDamping,
angularDamping: config.shipPhysics.angularDamping ?? DEFAULT_SHIP_PHYSICS.angularDamping,
alwaysActive: config.shipPhysics.alwaysActive ?? DEFAULT_SHIP_PHYSICS.alwaysActive,
};
}
} else {
this.save();
}
} catch (error) {
console.warn('Failed to load game config from localStorage:', error);
}
}
/**
* Reset to default settings
*/
public reset(): void {
this.physicsEnabled = true;
this.debug = false;
this.progressionEnabled = true;
this.shipPhysics = { ...DEFAULT_SHIP_PHYSICS };
this.save();
}
}