Пользователь
0,0
рейтинг
18 ноября 2013 в 12:48

Разработка → Крошечный арканоид на JavaScript (30 строк кода) из песочницы

Наблюдая за тем, как люди в 30 строк джаваскрипта умещают excel и змейку, я решил не отставать от прогресса, и создать что-нибудь подобное.
Итак, дамы и господа — 30ти строчный арканоид на чистом JS.



Ссылка на fiddle.
Также продублирую на codepen, а то фиддл всю ночь 500кой отвечал.

JavaScript:
(function (fld, pF, px, py, dx, dy, lifes, score) {
  var cycle = setInterval(function () {
    var bx = pF(ball.style.left = pF(ball.style.left) + dx + 'px'),
      by = pF(ball.style.top = pF(ball.style.top) + dy + 'px'),
      row = ((by - 30) / 14) | 0, col = (bx / 32) | 0;

    if (bx < 0 && dx < 0 || bx >= 314 && dx > 0) dx *= -1;
    if (bx + 6 >= px && bx + 6 <= px + 64 && by >= 259 && by <= 264) {
      dy *= -1;
      if (bx + 6 <= px + 21) dx = -6;
      else if (bx + 6 >= px + 43) dx = 6;
      else if (Math.abs(dx) == 6) dx = (dx * 2 / 3) | 0;
    }
    if (by < 0) dy *= -1;
    if (by >= 288 && !--lifes) clearInterval(cycle), alert('Game over!');
    if (by >= 288 && lifes) dy *= -1, lifesNode.innerHTML = lifes;
    if (by >= 18 && by <= 100 && fld[row * 10 + col].className != 'removed') {
      dy *= -1, fld[row * 10 + col].className = 'removed';
      if (dx < 0 && ((bx | 0) % 32 < 10 || (bx | 0) % 32 > 22)) dx *= -1;
      if (dx > 0 && (((bx + 12) | 0) % 32 < 10 || ((bx + 12) | 0) % 32 > 22)) dx *= -1;
      scoreNode.innerHTML = ++score;
      if (score == 50) clearInterval(cycle), alert('Victory!');
    }
  }, 1000 / 60);

  document.addEventListener('mousemove', function (e) {
    px = (e.pageX > 40) ? ((e.pageX < 290) ? e.pageX - 40 : 256) : 0;
    paddle.style.left = px + 'px';
  }, false);
}(field.children, parseFloat, 129, 270, -4, -4, 3, 0));


В целом я старался добиться максимальной аутентичности:
  • угол отражения шарика зависит (немножко) от того, на какую сторону ракетки он упал: при падении на левую треть мячик отлетает влево, при попадании на правую треть — вправо (в обоих случаях снаряд отражается под немного бо́льшим углом, чем при ударе о середину), при попадании в центр шарик отлетает под 45° а его направление по оси икс не меняется.
  • Подсчет очков (а как же без этого).
  • Дается три жизни. Правда, при попадании шарика на нижнюю грань игра не ресетится, а шарик просто отскакивает и отнимается одна жизнь.


Из недостатков: шарик иногда неадекватно себя ведет и ломает слишком много кирпичей.

Под капотом


С версткой все просто. Кирпичики — инлайн-блоки, ракетка и снаряд — position: absolute.

А вот с collision detection чуть интереснее. Область, где расположены кирпичи ограничена сверху и снизу, а значит проверять соударения есть смысл только тогда, когда снаряд в этой области. Высота и ширина кирпичей определена. Поэтому, взяв координаты шарика, мы точно сможем определить номер кирпича, в который он попал. Если его координаты X и Y, а ширина и высота кирпичей width и height, то взяв целую часть от частного X / width и Y / height мы получим в точности номер столбца и строки col и row текущей цели. Зная это мы можем вычислить номер этого элемента:
number = row * rowLength + col.
Благо, querySelectorAll возвращает элементы именно в том порядке, в котором они расположены в html. И мы легко можем удалить текущий кирпич:
elements[number].className = 'removed'.

setInterval


Не смотря на то, что нативный requestAnimationFrame уже реализован во всех десктопных браузерах, было решено отказаться от него в пользу setInterval. Во-первых, это позволяет охватить также старые версии, а во-вторых это экономит одну (драгоценную!) строчку кода:
requestAnimationFrame(function () frame {
  requestAnimationFrame(frame);
});
// против
var cycle = setInterval(function () {
}, delay);


Итого


Код, на мой взгляд, получился довольно компактный. Самая длинная строчка — 88 символов (с учетом индентации). Сама игра немного кривенькая, ну, а чего ещё ожидать от 30ти строчек?)
Сейчас видимо, как кто-то заметил в комментариях к предыдущим постам, стоит ждать 'Крошечную Windows' в 30 строк.
@linoleum
карма
8,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (42)

  • +6
    Извините, не удержался — новый тренд в js — «написать TaskName в 30 строк»

    А по теме, да, интересно, спасибо
    • +2
      Ну, не сказать, чтобы тренд, и не сказать, чтобы в js — думаю, это было всегда с тех самых пор, когда программирование только появилось — «написать X используя язык Y в N строк». Думаю, просто js для этого очень хорошо подходит, а тут ещё и этот триклятый (всю ночь ведь код писал) пост с excel'ем:)

      А вообще — да, ждем новых поступлений js-микроговнокода:)
    • +5
      Астрологи объявили неделю игр на JS. Количество строк сократилось до 30.
  • +2
    Красиво и просто! Скоро на хабре можно будет целую коллекцию 30-строчных программ собрать. Ждем следующую…
    • +3
      Новый хаб под это дело?
  • +12
    на хабре неделя ненормального программирования

    gist.github.com/aemkei/1134658 — game of life
    habrahabr.ru/post/138335/ — тетрис
    habrahabr.ru/post/202304/ — excel
    habrahabr.ru/post/202476/ — змейка
    habrahabr.ru/post/202530/ — арканоид
    • +4
      habrahabr.ru/post/202556/ — гонки
    • +4
      Астрологи объявили двухкратный прирост постов про JS
    • +5
      Буквально неделю назад писал свой арканоид (вернее, «арканоидо-оид», потому как управление другое) по правилам js1k. Выкладывать на хабр не стал, не думал, что кого-то заинтересует, видимо, зря.

      Но сейчас, с позволения хабровчан, скромно оставлю ссылку: демо, код.
    • +1
  • +10
    Ждём серию статей: CRM в 30 000 строк кода.
  • +2
    а то фиддл всю ночь 500кой отвечал.

    Так всю ночь народ свои тридцатистрочники постил ;)

    По сабжу — элегантно, даже хватило места двум пустым строкам и переменной px
    • +2
      Благодарю за отзыв.
      А px, она же положение ракетки дублирует, куда же без неё?)
      • +1
        Каюсь, не углядел.
        Кстати, почему-то совершенно напрасно остаётся пустым поле «Name you fiddle», не только у вас.
  • +1
    Между рендерингом и осознанием того, что страница загрузилась — потерял первую жизнь, дёрнув мышкой загнал шарик под ракетку и он дважды быстро ударился об нижнюю часть экрана :(
    • +1
      Да, каюсь — тот факт, что шарик просто отлетает от нижней грани, а не попадает обратно на ракетку может сильно расстроить. Но я, к сожалению, не нашел воможности (читай — строк кода) впихнуть инициализацию шара в рантайме.
  • +2
    Жду-не дождусь «пишем шутер от первого лица на JS, в 30 строк». Пусть даже на порядок больше было бы, пусть 300. Но было бы адски круто о_О
    • +1
      Я немного знаком с OpenGL и с её высокоуровневой js-оберткой Three.js и могу точно сказать что в 300 строк не уложить (не используя что-то ещё более высокоуровневое). В 3000 — вот тут можно поспорить уже. Ну а на чистом js без библиотек точно не выйдет.
      И, да — буду только счастлив узнать, что я ошибаюсь)
      • +2
        Ну на чистом JS+Canvas можно попробовать замутить нечто вроде Wolfenstein 3D (без обсчета полигональных моделей, никакого освещения, только спрайты). Но тоже думаю, 3000 будет мало, да. Тоже немного писал на OpenGL)
        • +1
          Хм, если вы этого не знали, то вам, думаю, будет интересно — Wolfenstein был портирован под браузер (читай — WebGL). Правда, сейчас переход по ссылке твердит 403, но он там был, клянусь)
          • +1
            О, я видел запуск в браузере и Doom'а, и даже Quake 1 ) Но речь то шла о «в минимальное число строк» )
            • +1
              Да, Doom я тоже видел. И КК тоже хорошо выглядит) Но тут имхо минимальность будет слишком ущербной — результат будет сильно отличаться от того, что предлагают не-30ти строчные аналоги. А вот с теми тремя примерами, что прозвучали на хабре, все вроде как бы похоже на правду)
        • +1
          Вольфенштейно-подобную графику в 300 строк — вполне реально, думаю)
  • +2
    На Opera Presto кирпичи немного не умещаются, и игра очень странно выглядит.На Opera Blink вроде порядок.
    • +1
      У меня опера 12 c чем-то, тестировал в ней, вроде все работало. Это какой движок?
      К слову, я, пока писал, себе 300 раз сказал спасибо за то, что jQuery использую только там, где это того стоит. Разумеется, речь идет о кроссбраузерности голого js — я его знаю(!).

      И ещё интересный момент, который для мне непонятен до сих пор. Лежат кирпичи, точно знаю, что их длина в ряд 320px. Открываю документ на локальной машине — всё нормально. Открываю на фиддле — в каждом ряду последний кирпич не взлазит и сползает на следующий ряд. Код ровно тот же. Так и не понял почему это происходит. Пришлось для кроссФиддловости сделать ширину поля 322px.
      • +2
        Так и не понял почему это происходит
        Zoom — он у вас разный на локальной машине и на фиддле. Нажмите в браузере Ctrl+0 (Cmd+0 на маке). В своё время я долго мучался с непонятными багами у юзеров, пока понял про zoom — некоторые слабовидящие делают трёхкратный zoom.
  • +4
    Ребята, но ведь количество строк не значит ничего, правда? У меня вот на проекте весь функционал умещается в одну строку… после closure compiler…
    • +3
      Разумеется, вы правы — любой код можно написать в одну строку, можно размазать на 1оо5оо)
      Здесь речь идет не много о другом, и, каюсь, я не могу строго сформулировать эту идею, но суть в том, чтобы строки были логичными — здесь думаю, суть в том, чтобы каждая строка выполняла не более одной высокоуровневневой операции. И чтобы этот код можно было разобрать 'без лупы'.
      Разумеется, 'высокоуровневневость' вещь катострофически относительная, и вот здесь-то, на мой взгляд, вся субъективность и кроется.
      Как бы ты это не определял, всегда можно просто взять и найти контрпример, который выставит несостоятельными все предыдущие аргументы).
      Но я сдесь к задаче подошел скорее с точки зрения синтаксической нежели семантической. Если по простому — один 'if' — одна строка, то есть больше опирался на языковые конструкции чем на логические.
    • +1
      Есть такая нотация для листинга программ — мне кажется, «академическая» называется. Точно не знаю, откуда такой термин. Думаю, этот вид нотации рассчитан на то, что студенты к каждой строке могут захотеть написать комментарий, а значит там много переводов строк и много свободного места справа.
  • +1
    C двадцатью четырьмя жизнями игру можно пройти не шевеля мышкой.
    • +1
      Грязный хак —
          //if (by >= 288 && !--lifes) clearInterval(cycle), alert('Game over!');
      
  • +7
    делаем общую репу на гитхабе для 30-строчного js?
    • +2
      Не очень понимаю, что такое общий репозиторий, но идея мне понравилась
      Речь идёт о публичном репозитории? Вот — сделал, добавляйтесь в колабораторы.
      github.com/pvolyntsev/thirty-lines-js-games: A set of small browser games that comprises about 30 lines of JavaScript
      Если ошибся — подскажите в личку, что сделал не так.

      У меня тоже есть мозголомка на javascript, но она с использованием jQuery UI, потому что drag&drop: projects.copist.ru/gues-color/ — делал как демо простого визуального программирования для дочери.
      Вряд ли смогу её переписать в 30 строк.
  • +2
    Хм, а если сделать минимизацию, то получится крошечный арканоид на одну строку кода?
  • +3
    Хмм, прочитав пост, первым делом мне подумалось о том что выйдет, лет так через десять, новость на хабре и будет называться она «Battlefield на досуге. 30 строк кода».

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.