- Enforced 'Style 32 - Dark Chibi Vector' for all ground assets. - Fixed critical Prologue-to-Game crash (function renaming). - Implemented Tiled JSON/TMX auto-conversion. - Updated Asset Manager to visualize 1800+ assets. - Cleaned up project structure (new assets/grounds folder). - Auto-Ground logic added to GameScene.js.
203 lines
5.9 KiB
JavaScript
203 lines
5.9 KiB
JavaScript
/**
|
|
* WaterPhysicsSystem.js
|
|
*
|
|
* Handles player movement in water with realistic physics:
|
|
* - Movement drag (30% slower)
|
|
* - Buoyancy (upward drift)
|
|
* - Jump reduction
|
|
* - Hair floating effect (integrates with WindFoliageSystem)
|
|
* - Swimming animation trigger
|
|
*
|
|
* Style 32 Dark-Chibi Noir compatible
|
|
*/
|
|
|
|
class WaterPhysicsSystem {
|
|
constructor(scene) {
|
|
this.scene = scene;
|
|
|
|
// Physics constants
|
|
this.waterDragFactor = 0.7; // 30% slower movement
|
|
this.waterJumpReduction = 0.5; // 50% jump power
|
|
this.buoyancyForce = -15; // Upward drift (pixels/s)
|
|
this.hairFloatStrength = 1.5; // Hair rises more in water
|
|
|
|
// Water zones (areas with water)
|
|
this.waterZones = [];
|
|
|
|
// Player state
|
|
this.playerInWater = false;
|
|
this.waterDepth = 0;
|
|
|
|
console.log('🌊 WaterPhysicsSystem: Initialized');
|
|
}
|
|
|
|
/**
|
|
* Add water zone
|
|
* @param {number} x - X position
|
|
* @param {number} y - Y position
|
|
* @param {number} width - Zone width
|
|
* @param {number} height - Zone height
|
|
* @param {number} depth - Water depth (0-100)
|
|
*/
|
|
addWaterZone(x, y, width, height, depth = 50) {
|
|
const zone = this.scene.add.rectangle(x, y, width, height, 0x4682B4, 0.3);
|
|
zone.setOrigin(0, 0);
|
|
zone.setDepth(-10);
|
|
|
|
this.waterZones.push({
|
|
zone,
|
|
x, y, width, height, depth
|
|
});
|
|
|
|
console.log(`🌊 Water zone added at (${x}, ${y}) - ${width}x${height}, depth: ${depth}`);
|
|
}
|
|
|
|
/**
|
|
* Check if player is in water
|
|
* @param {Object} player - Player object with x, y position
|
|
* @returns {number} Water depth (0 = no water, 100 = deep)
|
|
*/
|
|
checkWaterDepth(player) {
|
|
if (!player) return 0;
|
|
|
|
for (const waterData of this.waterZones) {
|
|
const { x, y, width, height, depth } = waterData;
|
|
|
|
// Check if player is inside water zone
|
|
if (player.x >= x && player.x <= x + width &&
|
|
player.y >= y && player.y <= y + height) {
|
|
return depth;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Apply water physics to player
|
|
* @param {Object} player - Player object
|
|
* @param {number} delta - Time delta
|
|
*/
|
|
applyWaterPhysics(player, delta) {
|
|
if (!player || !player.body) return;
|
|
|
|
// Check water depth
|
|
const depth = this.checkWaterDepth(player);
|
|
const wasInWater = this.playerInWater;
|
|
this.playerInWater = depth > 0;
|
|
this.waterDepth = depth;
|
|
|
|
if (this.playerInWater) {
|
|
// Apply movement drag
|
|
player.body.velocity.x *= this.waterDragFactor;
|
|
player.body.velocity.y *= this.waterDragFactor;
|
|
|
|
// Apply buoyancy (slow upward drift)
|
|
player.body.velocity.y += this.buoyancyForce * (delta / 1000);
|
|
|
|
// Reduce jump power if jumping in water
|
|
if (player.isJumping && player.body.velocity.y < 0) {
|
|
player.body.velocity.y *= this.waterJumpReduction;
|
|
}
|
|
|
|
// Trigger swimming animation
|
|
if (player.sprite && player.sprite.anims) {
|
|
const currentAnim = player.sprite.anims.currentAnim;
|
|
if (!currentAnim || currentAnim.key !== 'swim') {
|
|
// player.sprite.play('swim'); // Uncomment when swim animation exists
|
|
}
|
|
}
|
|
|
|
// Float hair upward (if WindFoliageSystem exists)
|
|
if (this.scene.weather && this.scene.weather.windSystem) {
|
|
this.floatHair(player, true);
|
|
}
|
|
|
|
// Entry splash effect (once)
|
|
if (!wasInWater) {
|
|
this.createSplash(player.x, player.y);
|
|
}
|
|
|
|
} else {
|
|
// Player left water
|
|
if (wasInWater) {
|
|
// Reset hair physics
|
|
if (this.scene.weather && this.scene.weather.windSystem) {
|
|
this.floatHair(player, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Make hair float upward in water
|
|
* @param {Object} player - Player object
|
|
* @param {boolean} float - Enable/disable floating
|
|
*/
|
|
floatHair(player, float) {
|
|
if (!player.hairLayer) return;
|
|
|
|
const windSystem = this.scene.weather.windSystem;
|
|
|
|
windSystem.windAffectedLayers.forEach(layer => {
|
|
if (layer.sprite === player.hairLayer) {
|
|
layer.buoyantMode = float;
|
|
layer.floatStrength = float ? this.hairFloatStrength : 0;
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Create splash effect when entering water
|
|
* @param {number} x - X position
|
|
* @param {number} y - Y position
|
|
*/
|
|
createSplash(x, y) {
|
|
// Create ripples if WaterRipplesSystem exists
|
|
if (this.scene.waterRipples) {
|
|
this.scene.waterRipples.createSplashRipples(x, y);
|
|
}
|
|
|
|
// Splash particles (simple white particles)
|
|
const splash = this.scene.add.particles(x, y, 'particle_white', {
|
|
lifespan: 500,
|
|
speed: { min: 50, max: 150 },
|
|
angle: { min: 240, max: 300 },
|
|
scale: { start: 0.5, end: 0.1 },
|
|
alpha: { start: 0.8, end: 0 },
|
|
quantity: 10,
|
|
frequency: -1
|
|
});
|
|
|
|
splash.explode();
|
|
|
|
// Auto destroy
|
|
this.scene.time.delayedCall(500, () => {
|
|
splash.destroy();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get player state info
|
|
* @returns {Object} State info
|
|
*/
|
|
getPlayerState() {
|
|
return {
|
|
inWater: this.playerInWater,
|
|
depth: this.waterDepth,
|
|
dragFactor: this.playerInWater ? this.waterDragFactor : 1.0,
|
|
buoyancy: this.playerInWater ? this.buoyancyForce : 0
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Cleanup
|
|
*/
|
|
destroy() {
|
|
this.waterZones.forEach(data => {
|
|
if (data.zone) data.zone.destroy();
|
|
});
|
|
this.waterZones = [];
|
|
}
|
|
}
|