JavaScript

индекс
246,38

Кубик Рубика на 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 не заработает).
Если кто-нибудь хочет заняться, то пожалуйста. Если есть вопросы по коду, задавайте, с радостью отвечу.
+92
30 июля 2010, 13:41
40

комментарии (97)

–65
Stepuk #
>> IE за браузер не считаем

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

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

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

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

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

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

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

0
AntiGravitY #
Чуть попроще.
0
Mezomish #
Так этот-то из полностью собранного делается в 4 поворота :)
0
lany #
А так собрать слабо? :D
+1
Mezomish #
Неа


0
svetko #
Очень надоедает крутить кубик мышкой. Имхо стоит сделать а-ля карту, где будет показано состояние все сторон сразу.
0
tegger #
Небольшая проблема: shuffle иногда крутит один и тот же слой несколько раз подряд в разных направлениях.
+1
lany #
Я знаю. Ну пускай, вам что ли жалко? :-) Если кажется, что замес недостаточно сложный, нажмите шаффл ещё раз :-)
0
tegger #
Не жалко. Клевая игрушка:)
+4
Yan169 #
Спасибо! Мне понравилось!

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

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

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