<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Water Physics (stable)</title>
<style>
body { margin: 0; overflow: hidden; background: #111; }
canvas { display: block; }
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
function resize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
resize();
window.addEventListener('resize', () => {
resize();
init();
});
let points = [];
const POINT_COUNT = 140;
let WATER_LEVEL;
function init() {
WATER_LEVEL = canvas.height * 0.55;
points = [];
for (let i = 0; i < POINT_COUNT; i++) {
points.push({
x: i * (canvas.width / (POINT_COUNT - 1)),
y: WATER_LEVEL,
vy: 0
});
}
}
init();
// стабильные коэффициенты
const tension = 0.02;
const damping = 0.04;
const spread = 0.15;
const maxVelocity = 8; // ограничение скорости
canvas.addEventListener('mousemove', (e) => {
const mx = e.clientX;
const my = e.clientY;
for (let i = 0; i < points.length; i++) {
const p = points[i];
const dx = p.x - mx;
const dy = p.y - my;
const dist = Math.sqrt(dx*dx + dy*dy);
if (dist < 70) {
p.vy += (70 - dist) * 0.1;
}
}
});
function update() {
// базовая физика
for (let i = 0; i < points.length; i++) {
let p = points[i];
let dy = WATER_LEVEL - p.y;
p.vy += tension * dy;
p.vy *= (1 - damping);
// ограничение скорости
if (p.vy > maxVelocity) p.vy = maxVelocity;
if (p.vy < -maxVelocity) p.vy = -maxVelocity;
p.y += p.vy;
}
// распространение волн (без взрыва)
const leftDeltas = new Array(points.length).fill(0);
const rightDeltas = new Array(points.length).fill(0);
for (let j = 0; j < 4; j++) { // меньше итераций
for (let i = 0; i < points.length; i++) {
if (i > 0) {
let d = spread * (points[i].y - points[i-1].y);
leftDeltas[i] = d;
points[i-1].vy += d;
}
if (i < points.length - 1) {
let d = spread * (points[i].y - points[i+1].y);
rightDeltas[i] = d;
points[i+1].vy += d;
}
}
}
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.moveTo(0, canvas.height);
ctx.lineTo(points[0].x, points[0].y);
for (let i = 1; i < points.length; i++) {
ctx.lineTo(points[i].x, points[i].y);
}
ctx.lineTo(canvas.width, canvas.height);
ctx.closePath();
const gradient = ctx.createLinearGradient(0, WATER_LEVEL, 0, canvas.height);
gradient.addColorStop(0, '#4aa3ff');
gradient.addColorStop(1, '#003366');
ctx.fillStyle = gradient;
ctx.fill();
}
function loop() {
update();
draw();
requestAnimationFrame(loop);
}
loop();
</script>
</body>
</html>