Загрузка данных


<!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>