то они превращаются в шарики.
Глядя на название игры Lines 9753, можно подумать, что этот рассказ про 9753-ий клон известной игры Color Lines, в которой надо составлять по 5 шариков в ряд одного цвета. Да, так и есть, клон. Ну что ещё может быть нового? Я поделюсь своими идеями и некоторыми тонкостями реализации на HTML+CSS+JavaScript. Расскажу что значат цифры 9753. Предложу способ найти другую комбинацию цифр и посмотреть, как изменится игра. Станет она интереснее или скучнее — решать вам. Ещё не догадались, что значит 9753? Тогда, прошу под кат.
Многообразие вариантов игры
Никогда не задумывались, откуда в оригинальной игре взялась размерность поля 9×9? Удивительно, насколько хорошо подобраны не только размерность игры, но и другие параметры, так что играть интересно: количество цветов — 7, количество шариков в ряд — 5 и количество появляющихся шаров за ход — 3. Эти 4 параметра поставлены в название игры — Lines 9753. Именно эта четвёрка по-большому счёту определяет сложность игры, которая скорее всего, подходит не всем.
Возможно, кому-то придётся по душе другой набор. Например:
- 3333 — легкотня типа пасьянса, можно не бояться зайти в тупик и постараться схлопывать как можно больше шариков за раз (5 ещё легко, 6 уже сложнее, 7 и 8 практически нереально), подойдёт в случае, когда совсем не хочется думать;
- 5643 — на доске 5×5 клетки не такие мелкие как 9×9, поэтому удобно играть на телефоне, однако сложность, кажется чуть выше, чем в 9753;
- 5543 — несколько более лёгкий вариант чем 5643, потому что количество различных цветов меньше, а значит больше вероятность составить ряд шаров одного цвета;
- 4443 — по сложности сравнима с 5643, но шарики ещё крупнее — всего 4 шара по короткой стороне экрана.
Думаю, каждый найдёт подходящие варианты игры для себя. Не отключайтесь от сети и мы вместе сможем увидеть наиболее популярные варианты в таблице на сайте.
Ход назад
Разрешается делать ходы назад. Давным-давно, когда деревья были высокими, а я был ещё студентом довелось, мне поиграть в Color Lines. Игра очень понравилась. Один раз, проиграв в неё полдня и, набрав несколько тысяч очков, я зашел в тупик. Пришло осознание того, что это была случайность, что шары выпадали удачно, и что в ближайшее время так далеко я пройти не смогу. Чтобы побить свой же рекорд, мне надо будет убить раз в десять больше времени, и то если повезёт. С тех пор я долго не играл в эту игру. Ощущение вселенской несправедливости засело глубоко в душе. И сидело оно там до тех пор, пока не выкристаллизовался коварный план мести — сделать такую же игру, но с возможностью отматывать ходы назад хоть до самого начала. Именно эта опция стала для меня главной мотивирующей причиной написать игру по-своему.
Фиксированная случайность
Некоторые игроки говорили, что иногда машина специально ставит шары в неудобные места, чтобы усложнить прохождение. Особенно, когда остаётся совсем мало свободных клеток, невозможно дождаться нужного шара в нужном месте. Другими, словами, случайность в игре совсем не случайна. С новой возможностью отматывать ходы назад, было бы не логично предлагать каждый раз новое место для новых шаров. Так можно было бы ходить вперёд и назад до тех пор, пока не появится нужный шар в нужном месте. Поэтому в игре все ходы машины детерминированы и зависят случайным образом от номера хода и расположения шаров на поле. Мало того, все играют одну и туже игру. То есть, игра начинается с одной и той же расстановки (первый ход машины), и далее ходы машины зависят от того, как сходит игрок: если игроки ходят одинаково, то и на поле у них будет одинаковая расстановка шаров. Это позволяет объективно и независимо от случайности сравнивать разные решения. Некоторые любят меряться кто дальше, кто быстрее,… Решения в виде последовательности ходов игрока отправляются на сервер. Ходы машины вычисляются всё по тому же случайному алгоритму. Обмануть сервер не получится, вся последовательность проверяется на корректность, и только потом результат заносится в таблицу. Все рекорды сохраняются вместе с последовательностью ходов игрока. Потом проанализируем и опубликуем лучшие решения тех кто наберет 9999 очков. Нужно будет придумать, по какому критерию выбирать лучших.
Некоторые критерии можно найти в статистике, которая доступна по клику на правом или нижнем счётчике. Если придумаете другие интересные критерии, то присылайте, я попробую формализовать подсчёт и добавить.
Подсказка
Показываются позиции и цвета следующих шариков. Из-за того, что игру можно перематывать вперёд и назад, нет смысла скрывать следующие ходы. Можно было бы показывать на несколько ходов вперёд, но простого интерфейса в голову не пришло (нужно учитывать, что ходы машины меняются, если клетки оказываются занятыми в результате действий игрока).
Подсчёт очков
Подсчёт очков сделан по классической формуле N * (1 + N — DIMENSION), где N — количество шаров в линии, DIMENSION — размерность игрового поля. То есть 5, 6, 7, 8 собранных вместе шаров дают соответственно 5, 12, 21 и 32 очка. Для варианта игры 3333 при схлопывании 3, 4, 5 и 6 шаров получается 3, 8, 15, 24.
Графика
Графика только векторная — не люблю артефакты масштабирования, особенно нечёткие границы. Основные анимированные графические элементы: винтажный магнитофонный счётчик и прыгающие шарики с бликами и градиентным освещением. Они выполнены с использованием CSS и приправлены кусочками JavaScript. Изначально была сделана тёмная цветовая схема. Её можно попробовать, включив в настройках. Однако всё выглядит мрачновато. Светлая мне больше нравится.
Трёхмерный шарик
Как ни парадоксально звучит, но из 3-х вложенных друг в друга прямоугольников получается трёхмерный шарик:
- контейнер, задающий размер и положение на экране
- круглый квадрат, создающий двухмерную форму, сжимающуюся и растягивающуюся во время подпрыгивания
- квадрат с эллиптической градиентной заливкой, определяющий цвет и освещение шарика, добавляющие третье измерение.
С контейнером всё просто. Его CSS атрибуты position, left и top задают координаты шарика на поле, а font-size задаёт размер, относительно которого масштабируются два других квадрата. Круглый квадрат, это, как подавляющее большинство кругляшков, на наших web страницах, просто квадрат с максимально закруглёнными углами. Когда на него нажимаем мышкой, его плющит, сжимая сверху и расширяя бока. А если нажатие оказывается быстрым как мышиный клик, то шарик аж подпрыгивать начинает.
@keyframes flat {
0% {height: 1.0em; width: 1.0em; top: 0; left: 0em;}
100% {height: 0.9em; width: 1.05em; top: 0.1em; left: -0.025em;}
}
@keyframes jumping {
0% {height: 0.9em; width: 1.025em; top: 0.1em; left: -0.0125em;}
10% {height: 1.02em; width: 1.0em; top: -0.02em; left: 0em;}
40% {height: 1.008em; width: 1.0em; top: -0.18em; left: 0em;}
50% {height: 1.01em; width: 1.0em; top: -0.2em; left: 0em;}
60% {height: 1.0em; width: 1.0em; top: -0.18em; left: 0em;}
70% {height: 1.0em; width: 1.0em; top: -0.1em; left: 0em;}
90% {height: 1.0em; width: 1.0em; top: 0em; left: 0em;}
100% {height: 0.9em; width: 1.025em; top: 0.1em; left: -0.0125em;}
}
Максимальное количество цветов 15.
Не все цвета имеют достаточно плавные градиенты даже на хорошем мониторе, поэтому я подбирал цвета на глаз. Чем больше цветов, тем сложнее отличать шарики по цвету на поле. Кажется, 15 цветов достаточно.
Счётчик
Главный секрет счётчика состоит в лентах с цифрами. Каждая лента скрыта внутри прямоугольника, через который видна только одна цифра. Края этого прямоугольника слегка затемнены, чтобы создавался эффект закругления, как будто внутри не лента, а диск. Скорость анимации прокрутки пропорциональна оставшемуся приращению счётчика и ограничена некоторыми разумными величинами. Последняя цифра докручивается 1 секунду.
Звук
Звуки (взрыв и прыжки) синтетические. Они генерируются по незамысловатым математическим формулам. Это создаёт некоторый привкус 80-х, когда большинство звуков в играх генерировалось с использованием одноголосного частотного генератора. К плюсам можно отнести компактность программы: простенький генератор таких звуковых эффектов, написанный на JavaScript, оказывается значительно меньше по размеру, чем mp3 файл. Для каждого шарика выбираем свою пару нот lowFreq и highFreq (см. wikipedia) и заполняем аудиобуфер примерно вот так:
var soundUpBuffer = audioCtx.createBuffer(1, frameCount, sampleRate);
for (var i = 0; i < frameCount; i++) {
var x = i / frameCount; // from 0.0 to 1.0
var time = duration * x;
var volume = Math.sin(x * Math.PI);
var freq = lowFreq + Math.sqrt(x) * (highFreq - lowFreq);
buffer[i] = volume * Math.sin(2 * Math.PI * freq * time);
}
Здесь частота изменяется от lowFreq до highFreq по кривой x½, а громкость sin(π x).
У взрыва громкость затухает по формуле 1/(1+10*x+1000*x*x), а частота выбирается случайно с первой по пятую октаву.
Адаптивный размер диалогового окна
Реализован алгоритм подбора размера диалогового окна, так чтобы оно занимало как можно больше пространства и не выходило за границы видимой области. Проблема заключается в том, что на разных устройствах размер диалогов разный — иногда получается слишком мелко, а иногда не входит в экран. Я сделал размер диалогов зависимым от размера шрифта (CSS единицы em). Далее, перебираю размер шрифта, чтобы диалог занимал не более 95% любой из размерностей экрана. Так не пришлось городить кейсы для адаптивного CSS.
Небольшой размер программы
Вся игра умещается в одном html файле около 150Кб. Около 3000 строк исходного кода (конечно без серверной части). Никакие JavaScript библиотеки и фреймворки не использовались — всё натурально, как в каменном веке. Иногда просто не хочется разбираться со сторонним API, а иногда полезно понять, насколько сильно фреймворки упрощают жизнь изобретателя велосипедов и испытателя новых граблей. Полезно бывает сначала придумать самому как можно реализовать ту или иную идею, а уж потом сравнить с тем как это сделали другие. Например, версия под Андроид занимает всего 250Кб. Она состоит из тонкой WebView обёртки и пачки png-шек под разные разрешения телефонов. Кстати, png-шки можно было бы заменить одной векторной xml-кой. Получилось бы точно в духе минимализма.
Форум
Форум работает на phpBB. Эккаунт позволяет:
- сохранять свои достижения на сервере, чтобы они не потерялись при смене телефона или компьютера
- играть поочерёдно то на одном устройстве, то на другом
- оставлять сообщения и задавать вопросы другим игрокам или разработчикам.
i18n и l10n
Интернационализация и локализация. Игра переведена на русский и английский. Всего 35 коротких фраз. Я бы не отказался от бесплатной помощи по переводу ещё на несколько популярных языков (Китайский, Немецкий, …).
Никакой рекламы
Часто можно услышать мнение, что если программа бесплатная и без рекламы, то значит троян, бэкдор, вирус, … Другими словами, бесплатный сыр только в мышеловке. Иначе зачем? Почему кто-то готов делать что-то для других безвозмездно? Я общего ответа не знаю. Мало того, не знаю точно, почему сам это делаю. Мне просто интересно. Если что-то нравится, то я часто задумываюсь, как автору это удалось. Хочется попробовать сделать так же или даже лучше. Иногда всё нравится, за исключением каких-то деталей, и возникает желание сделать подобное, но со своим блэк джеком и финтифлюшками.
Заключение
На этом пока всё. Надеюсь игра вам понравится настолько, насколько мне было интересно её создавать. Буду рад любым комментариям.
Ссылки
- Интерактивный оригинал этих заметок можно найти здесь
- Lines 9753
- https://ru.wikipedia.org/wiki/Color_Lines
- http://4pda.ru/forum/lofiversion/index.php?t394525
- http://www.softholm.com/igra/lines/
- http://lines-98.ru/
- https://gamefile.ru/games/lines/#
- http://linesgame.ru/online.html
- https://habrahabr.ru/post/41775/
Специально для сайта ITWORLD.UZ. Новость взята с сайта Хабр