Кубик Рубика на canvas

    Недавние посты об алгоритме сборки кубика 5×5 сподвигли меня написать эмулятор кубика на канвас. Автором статей про сборку предлагался свой кубик на OpenGL, но он мне многим не понравился. Надеюсь, с моим кому-нибудь удастся освоить алгоритм быстрее. Некоторые особенности и преимущества:
    • Кроссплатформенность, кроссбраузерность (IE за браузер не считаем), ненужность инсталлятора и прочие преимущества веб-приложения.
    • Поддержка кубиков от 2×2 и до бесконечности (пока грани не станут сильно маленькими и рендеринг не начнёт жестоко тормозить). В интерфейс вынесено до 11×11, но в библиотеке ограничений нет.
    • Псевдообъёмные грани для красоты.
    • Бесконечный undo-буфер.
    • Возможность замеса кубика (shuffle).
    • Слои вращаются легко и интуитивно, быстро привыкаешь. Крутить весь кубик (мышкой с зажатым шифтом или правой кнопкой) не так легко, но тоже можно привыкнуть.
    • Вся библиотека компактная, размещается в одном js-файле и не имеет никаких внешних зависимостей.
    • Лицензия MIT, а также открытые и не очень страшные исходники позволяют вставить кубик на ваш сайт и доработать по вкусу.
    Не знаю, стоит ли рассказывать про особенности разработки. Было много сложностей, но все достаточно мелкие. Я почему-то поленился использовать однородные координаты, из-за чего, в частности, проекция ортогональная, а не перспективная. Модель рендеринга тоже немного странная. В общем виде кубик представляется в виде 6, 12 или 18 граней, а каждая грань содержит до size^2 элементов, каждый элемент — это квадратик. На внутренних срезах, которые видно при вращении, элемент всего один площадью на всю грань. Здесь подписаны 9 видимых граней, остальные 9 расположены симметрично им:

    Потребовалось также сортировать грани в правильном порядке, чтобы корректно удалялись невидимые части. Здесь правильный порядок — вдоль оси вращения (если вращения нет, порядок неважен).

    Объёмность граней ненаучная: это просто круговой градиент канвас, центр которого отклоняется в направлении нормали. Честно считать освещённость по BRDF показалось для этой задачи неоправданно.

    Что хотелось ещё сделать, но лень:
    • Управление с клавиатуры.
    • Перед вращением слоёв мышкой подсвечивать вращаемый слой, чтобы уменьшить число ошибок. Сейчас вращение начинается, если с зажатой кнопкой провести мышкой на 50 пикселей в направлении вращения. Подсветку можно включать на меньшем расстоянии, тогда пользователь вовремя остановится. Может, это и не нужно, у меня ошибки случались редко.
    • Починить кубик 2×2, почему-то он не работает. исправлено — спасибо fllln
    • Сделать перспективную проекцию.
    • Сохранение/загрузку (можно в cookies).
    • Поддержка IE6-8 (вероятно, радиальный градиент в excanvas не заработает).
    Если кто-нибудь хочет заняться, то пожалуйста. Если есть вопросы по коду, задавайте, с радостью отвечу.
    Метки:
    Поделиться публикацией
    Похожие публикации
    Комментарии 97
    • –65
      >> IE за браузер не считаем

      Дальше не читал.
      • +18
        хорошо, что не:

        > >> Кубик Рубика
        >
        > Дальше не читал.
        • +7
          Пора переходить на что-то нормальное а не зацикливаться на старом.
          • НЛО прилетело и опубликовало эту надпись здесь
            • +3
              Меня всегда удивляло — какое другим людям дело, какой у меня браузер? Кому какое дело, на каком языке я пишу? Кому какое дело, какая у меня ОС?
              Так нет же, всегда находятся такие, кто будет кричать — ставь файрфокс! Ставь оперу! Ставь Виндоуз! Линух форева!
              Личный вопрос можно? Какое вам дело, что у кого-то стоит IE? Лично мне нет до этого никакого дела.
            • +2
            • +2
              на этот раз пятницо явилось в образе Кубика Рубика:)
              • +4
                Вы просто умничка!
                • НЛО прилетело и опубликовало эту надпись здесь
                  • +1
                    Цвета легко настраиваются. Скажите шесть хороших цветов в формате #rrggbb, я заменю :-)
                    • +2
                      Используйте оригинальные цвета кубика.
                      Красный: #FF0000
                      Оранжевый: #FF8000
                      Жёлтый: #FFEB00
                      Белый: #FFFFFF
                      Синий: #0000FF
                      Зелёный: #00DC00
                      • +3
                        И не забудьте:
                        Белый напротив желтого,
                        Синий напротив зеленого,
                        Красный напротив оранжевого.
                        И с одной стороны видны белый, синий и красный так, что белый сверху, синий справа, а красный слева.

                        Так будет максимально верно.
                        • +3

                          Как-то так.
                          • 0
                            Сделал, только зелёный поставил сильно темнее. А то приведённые цвета — пытка для дихроматов :-) У меня вроде был в детстве кубик с тёмно-зелёным.
                      • НЛО прилетело и опубликовало эту надпись здесь
                        • 0
                          Градиенты отключаются кнопкой Flat над кубиком.
                          • НЛО прилетело и опубликовало эту надпись здесь
                      • НЛО прилетело и опубликовало эту надпись здесь
                        • НЛО прилетело и опубликовало эту надпись здесь
                          • НЛО прилетело и опубликовало эту надпись здесь
                            • НЛО прилетело и опубликовало эту надпись здесь
                              • НЛО прилетело и опубликовало эту надпись здесь
                                • НЛО прилетело и опубликовало эту надпись здесь
                          • 0
                            Можно просто кодировать статус в строчку, которую человек может закинуть себе на флэшку или переслать по е-мейлу и потом назад вставить в поле для загрузки. Не хочется добавлять к этому сервер-сайд код.
                            • НЛО прилетело и опубликовало эту надпись здесь
                              • +1
                                Ну это не тот случай, чтобы защита нужна была. Чемпионат по сборке кубиков онлайн? :-) Программы должны помогать людям, даже если человек хочет читерить :-)
                                • НЛО прилетело и опубликовало эту надпись здесь
                                  • 0
                                    почему бы и нет?
                                    сделать сайт с авторизацией, рекордами и соревнованиями (как мелькавший тут тетрис), и с вашим «рубик-движком» :)
                              • 0
                                у меня прочиталось «пришел с работы дáмой» — долго думал :)
                              • +2
                                У меня в IE9 работает
                                • НЛО прилетело и опубликовало эту надпись здесь
                              • +4
                                шикарно, а из Shuffle (animated) при 11x11 вообще можно скринсейвер делать
                                • +2
                                  Спасибо, в детстве небыло, хоть сейчас покручу
                                  • +5
                                    Что-то по-моему перспектива — наоборот, задняя стенка больше передней.
                                    • +1
                                      визуальный эффект. Глаз привык к перспективе.
                                      • +2
                                        Да нет, не визуальный, вот посмотрите например на стандартное положение кубика, верхние грани, левая и правая не параллельны, ну и если кубик повернуть фронтально — то задняя стенка немного — но выпирает.
                                        • 0
                                          Правда-правда визуальный эффект :-)
                                          • +1
                                            Я даже в графическом редакторе проверил… и правда визуальный эффект… жуть :)
                                          • +1
                                            Вы знаете, я не поверю, что человек осознанно программировал обратную перспективу. А то, что аксонометрия дает легкий эффект обратной перспективы — общеизвестно.
                                            • +2
                                              Человек вполне себе осознанно может ошибаться :) в том числе при реализации перспективы.
                                              • +2
                                                Это ж как нужно ошибиться? ;) Это из разряда:
                                                — Что вы делаете в моей машине?
                                                — Ой, я просто ошибся и сел не в свою!
                                                ;)

                                                ЗЫ Undo после Shuffle прикольно работает ;)
                                        • 0
                                          Просто изометрия. То, что задняя грань такая же по длине как передняя можно легко проверить.
                                        • 0
                                          Для IE есть excanvas(http://code.google.com/p/explorercanvas/), IE9 превью умеют работать с канвасом — почему бы и не допилить?
                                        • +5
                                          перспективу бы не изометрическую и все было бы отлично :)
                                          • +1
                                            Еще бы, для ленивых владельцев разобранного кубика, сделать инструмент для быстренькой пошаговой сборки :)
                                            • +1
                                              Кнопка shuffle кладёт вращения в undo-буфер. Поэтому можно после shuffle нажать 50 раз undo, и кубик вернётся в исходное состояние =)
                                            • 0
                                              Управление — лучшее из тех, что я видел (и делал:)).
                                              Единственное, надо перспективу сделать, чтоб во время поворота самого кубика мозг не нагревался и будет великолепно.
                                              • 0
                                                Ах, да забыл, вращение кубика шифтом неудобно, идеально, когда всё ложится на мышь, например вместо зажатия шифта можно сделать зажатие правлй кнопки (всё равно не используется)
                                                • 0
                                                  Сделал. На вебе обычно не стоит закладываться на правую кнопку (к примеру, пользователь может запретить переопределять контекстно меню в опциях Javascript). Кроме того есть мако-юзеры без правой кнопки :-) Так что я оставил шифт как альтернативу.
                                                  • 0
                                                    у оперы на «зажатая правая кнопка+движение влево-вправо» повешены гестуры, т.е. взад-вперед по истории страниц можно бегать. Повернул Ваш кубик влево, отпустил правую кнопку и обратно на хабр попал :)

                                                    так, что шифт очень даже нужен.
                                              • +2
                                                lany — искренне восхищаюсь ;)
                                                сколько вы потратили времени если не секрет?
                                                • +1
                                                  Пару дней с перерывами. Чистого времени — не знаю… Часов 15, может…
                                                • +1
                                                  Спасибо, всё очень понравилось.
                                                  • +1
                                                    перспективную проекцию бы. делается просто, плюсов — много.
                                                    • 0
                                                      Самый простой способ: снять на видео «Shuffle (animated)» и прокручивая обратно — решить головоломку.
                                                      Даешь высокие технологии! :)
                                                      • 0
                                                        Нажмите после shuffle (необязательно animated) кнопку undo 50 раз (можно быстро подряд) и наслаждайтесь =)
                                                        • НЛО прилетело и опубликовало эту надпись здесь
                                                      • НЛО прилетело и опубликовало эту надпись здесь
                                                        • 0
                                                          Сделал, но у меня не было такой проблемы. Посмотрите, помогло ли :-)
                                                          • НЛО прилетело и опубликовало эту надпись здесь
                                                            • 0
                                                              А, вы про эти команды. Я думал, про мышиные эвенты на самом канвасе. Сейчас лучше?
                                                              • НЛО прилетело и опубликовало эту надпись здесь
                                                                • 0
                                                                  Ну если подскажете, что дописать, то допишу :-)
                                                        • +1
                                                          Багофича:
                                                          если усердно крутить кубик, то он увеличивается или уменьшается:

                                                          dl.dropbox.com/u/1604499/capture-2.mp4
                                                          (1,2 Мб если заботитесь о траффике)
                                                          • +1
                                                            404.
                                                            Там есть кнопки zoomIn/zoomOut. Может, вы их случайно нажали?
                                                            • 0
                                                              Сорри, сейчас будет.
                                                              • 0
                                                                Ага, интересная бага. После последней модификации вращения в матрице преобразований стала накапливаться погрешность. Сделал нормализацию матрицы, спасибо.
                                                          • 0
                                                            автор, добавьте заголовок HTML5 doctype html и ie9 автоматом переключится в режим поддержки стандартов и все заработает
                                                            • 0
                                                              Сейчас лучше?
                                                              • 0
                                                                да, все работает, спасибо
                                                            • 0
                                                              Спасибо автору, поразмялся немного. К управлению, действительно, привыкаешь довольно быстро.

                                                              • 0
                                                                Чуть попроще.
                                                                • 0
                                                                  Так этот-то из полностью собранного делается в 4 поворота :)
                                                                • 0
                                                                  А так собрать слабо? :D
                                                              • НЛО прилетело и опубликовало эту надпись здесь
                                                                • 0
                                                                  Небольшая проблема: shuffle иногда крутит один и тот же слой несколько раз подряд в разных направлениях.
                                                                  • +1
                                                                    Я знаю. Ну пускай, вам что ли жалко? :-) Если кажется, что замес недостаточно сложный, нажмите шаффл ещё раз :-)
                                                                    • 0
                                                                      Не жалко. Клевая игрушка:)
                                                                  • +4
                                                                    Спасибо! Мне понравилось!

                                                                    • 0
                                                                      А вот это мне точно слабо о_О
                                                                      • 0
                                                                        Насколько я понимаю, это делается аналогично схемам K11-K13 из алгоритма 5×5, любой из которых будто бы естественно расширяется на любые внутренние кубики. Но выглядит красиво, да :-)
                                                                        • 0
                                                                          Я ничего, кроме как 2x2x2 и 3x3x3, не пробовал ни разу.
                                                                          За что Вам ещё раз отдельное спасибо — сейчас кручу 4x4x4 :)
                                                                          • 0
                                                                            Да я тоже на своей программе большие размеры впервые попробовал :-) Теперь хочу уже купить хардварный 5×5 =)
                                                                        • +1
                                                                          Это собирается так же, как и окошки выше.
                                                                          1) Любой центральный синий слой вращаем в сторону белого
                                                                          2) Любой красный в сторону белого
                                                                          3) Синий обратно
                                                                          4) Красный обратно
                                                                          В результате 4 поворотов получаем 1 синий «пиксель» на белом фоне.
                                                                          Аналогично можно собрать любую двухцветную картинку. За это я и люблю многомерные кубики. Жаль у меня только 7*7*7 есть, уже хочу 11*11*11 и больше. )
                                                                    • 0
                                                                      я нажал Shuffle (animated), потом понял, что это надолго, и нажал Shuffle (fast)
                                                                      он сработал, но Shuffle (animated) продолжился :)
                                                                      есть ли способ остановить/отменить Shuffle (animated)?
                                                                      • 0
                                                                        Есть. Надо нажать Reset :-)
                                                                        Можно написать отдельную функцию в три строчки, которая очистит очередь анимации.
                                                                        • 0
                                                                          я имел в виду — остановить без ресета, с сохранением уже имеющегося Shuffle
                                                                          интуитивно я нажал Shuffle (fast) именно затем, чтоб Shuffle (animated) прекратился

                                                                          на самом деле — это всё плюшки :)
                                                                          сделано супер!
                                                                      • 0
                                                                        Меня предыдущие посты сподвигли на написание on-line решалки для кубика. Пока программа показывает только процесс решения по пунктам. Теперь думаю, как бы визуализировать процесс, чтобы показывала что-то типа видео-ролика с поворотами граней.
                                                                        • 0
                                                                          Ну если вы на JS пишете, то прикручивать решатель к моему коду совсем несложно. Загоняйте очередную комбинацию в cube.addSliceRotation, затем ждите, пока cube.animationQueue не опустеет, тогда продолжайте. Текущее состояние кубика в cube.state[грань][номер_элемента], взаимное расположение граней в cube.neighbors. Можно прикрутить к анимации callback, чтобы после завершения текущей анимации управление назад переходило к решателю.
                                                                          • 0
                                                                            Надо будет попробовать.
                                                                        • 0
                                                                          Впечатляет!
                                                                          Последнее время мне еще понравилась реализация классического кубика с поддержкой 3D очков — Cube. Даже заказал себе по этому поводу неплохие красно-синие очки с DealExtreme…

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