Как я сообщал ранее, прикупил клавиши с пингвинами, чтобы закончить игру про пингвина. Сейчас этими клавишами и пишу :)
Игра называется Pengu5, потому что Pengu это сокращённо Penguin, а 5 это ремейк Flash-игры на HTML5.
Всё началось с симуляции волн, и сейчас я туда заглянул и увидел какие-то не вполне очевидные цифры, так что попробую всё описать и заодно вспомнить.
Итак, ключевая особенность игры это плавание льдины по волнам.
Волны, надо сказать, получились довольно органичные (рабочая ссылка будет в конце), но это не физически достоверная симуляция. Для нужд игры её достаточно.
Как сделать волну?
Берём обычную синусоиду:
У неё есть амплитуда – это высота волны. И частота – это, соответственно, величина, обратная длине волны, а длина волны зависит от скорости распространения. Собственно, это всё, вот она, волна :)
Чтобы сделать волну более похожей на воду, нужно просто взять несколько синусоид с разными амплитудами и частотами и сложить их:
Далее, нужно заставить волны двигаться. Нам достаточно просто в каждый следующий момент времени рисовать синусоиду с каким-то смещением.
Вот теперь точно всё. Реально, это несложно сделать, и нужно только тщательно подобрать параметры по вкусу: сколько синусоид использовать, с какими амплитудами, частотами и сдвигами.
Практическая реализация
Я хочу немного отойти от старого решения и попробовать новое, которое будет почти такое же. Вышеописанные синусоиды в любом случае сохраняются, просто представить это всё можно в немного разных видах.
Так как вода это частицы, я хочу оттолкнуться от частиц. Где-то я читал, что при движении волны частицы воды движутся по эллиптическим траекториям. Попробую сделать по памяти.
Моделировать каждую частицу не надо. Представим поверхность воды как сетку точек с неким шагом.
Теперь представим, что по орбите вокруг каждой точки летает частица.
Соединив текущие положения частиц, получим текущий уровень воды.
Теперь вернёмся к частоте. Частота в данном случае это количество оборотов, совершаемых частицей за единицу времени. Обороты измеряются в радианах, и 360° это 2𝜋. Назовём частоту frequency.
Сосредоточимся только на вертикальной координате частицы (height). Она будет равна амплитуде (назовём её amplitude), умноженной на косинус текущего угла поворота частицы в момент времени t:
height = amplitude * cos(2𝜋 * frequency * t)
Если применить такой расчёт к каждой частице и пустить время t в цикле, то частицы будут плавно подниматься и опускаться, но делать это cинхронно, поэтому мы увидим колебание не волны, а горизонтальной линии. Чтобы получилась волна, нужно добавить скорость её распространения в пространстве (velocity).
В пространственном измерении каждая следующая частица находится в другом моменте времени и значит её нужно дополнительно подкручивать относительно предыдущей. Величина подкрутки это скорость распространения волны (velocity) и измеряется она также в радианах. С пространственной координатой x полная формула выглядит так:
height = amplitude * cos(2𝜋 * frequency * t + 2𝜋 * velocity * x)
Где velocity можно считать неким абстрактным параметром, подбираемым вручную для нужного результата. Он также связан с длиной волны, поэтому изменяя velocity, вы будете получать разную длину волны при той же частоте.
Теперь фазы частиц будут разными, и мы получим что-то вроде:
Думаю, идею вы ухватили.
Первую синусоиду я делаю как бы "несущей", поэтому у неё низкая частота, скорость и большая длина волны:
Затем накладываю на неё более мелкую и быструю.
...и вижу, что уже хватит. Данная волна уже вполне устраивает.
Теперь можно украсить картинку, добавив ещё один слой воды. То, что нарисовано выше, это задний план с ровной заливкой. Добавлю слой с градиентом цвета и прозрачности, а также со светлой обводкой. Он содержит три синусоиды. И добавлю всё-таки ещё синусоиду в задний план.
Теперь вспомним о том, что мы считали только вертикальную координату частицы.
Можно оставить это как есть, а можно добавить сдвиг горизонтальной координаты по тому же самому принципу, только вместо косинуса будет синус:
dx = amplitude * sin(2𝜋 * frequency * t + 2𝜋 * velocity * x)
Это добавит некоторой хаотичности в рисунок волн, и эффект можно регулировать путём умножения на какой-то коэффициент.
Смотреть на это лучше всего в динамике, поэтому вот ссылка на онлайн-редактор:
Вы можете поменять параметры вот здесь и посмотреть, как они влияют:
Обратите внимание, что frequencies и velocities сразу умножены на 2𝜋, чтобы не делать этого каждый раз в формуле.