Сверхплавное передвижение объектов

    Иногда у веб-разработчиков возникает задача, которая требует плавного движения объекта по экрану. Это может быть строка загрузки, какой-то спрайт (например, машинки на клавогонках) или что-то ещё. Проблема возникает, когда сдвиг даже на одну точку кажется слишком резким и портит общее ощущение от происходящего. Как этого избежать? Использовать приёмы антиалиасинга.

    Мы сделали небольшой пример (а затем и ещё один с зацикленным фоном), в котором можно посмотреть, как выглядит плавный сдвиг с субпиксельной точностью и антиалиасингом, и как выглядит тот же сдвиг без этого эффекта.

    Как это сделано?

    Это сделано при помощи спрайтов, а также «умного» уменьшения исходного изображения. Теперь, по порядку.

    Во-первых, мы взяли большое изображение машинки:


    Затем, подчистили его от ненужного фона:


    Дальше мы расположили 4 одинаковых машинки с шагом в 600 точек в одном большом файле (2400х260 точек).

    После этого, мы сдвинули каждую копию машинки на одну точку, относительно предыдущего кадра. То есть, вторую машинку — на точку, третью — на две, а четвёртую — на все три. Теперь на нашем спрайте есть машинка, которая преодолевает расстояние в 4 точки за 4 кадра.

    Осталось последнее действие, заставить машинку проезжать за 4 кадра одну точку и сделать это максимально плавно. Для этого мы уменьшаем картинку в 4 раза, не забыв включить опцию антиалиасинга при уменьшении в вашем редакторе, и получаем картинку такого вида (которую, к слову, мы и используем в нашем примере):


    Ниже — картинка, на которой в увеличении видно, как машинка проезжает сквозь одну точку:


    Дальше дело за малым: как использовать этот спрайт? Самым простым способом: во время движения картинки, определять дробную часть и использовать её для выбора нужного кадра. Поскольку вебовские средства не позволяют использовать неточное позиционирование, мы распологаем спрайт ровно по нужной нам координате, например, при позиции X=15,25 мы размещаем картинку на 15 точке по оси X, а дробную часть переводим в номер спрайта, в нашем случае это будет второй спрайт.

    В принципе, по аналогичной схеме можно сделать движение и по двум осям, а также использовать этот метод для плавной анимации фона, например для css анимации фонов у кастомных кнопок или других схожих js эффектов.

    Комментарии 103

      +16
      всё гениальное — просто! :)
        0
        спасибо
          –19
          самое простое это выводить эту машину через флеш, который работает с субпикселями. и не генерировать пустой трафик.
            +4
            вот конкретно этот блог — про javascript.
              +1
              то что блог про JS не является препятствием для того, чтобы узнать что задача оптимально решается другими способами без костылей и извращений.
                0
                Чем меньшим количеством средств вы обойдётесь, тем лучше у вас всё будет работать.
                  –3
                  в таком случае эволюция технологии остановилась бы на «палке копалке»
                    0
                    Мы вроде бы про код говорили, а не про эволюцию. Чем больше внешних факторов — тем больше энтропия. Смирись с энтропией, чувак!
              +2
              но флеш антиалиасит не так плавно и при движении сабпикселями в нём картинка размывается
                –1
                видимо, тоже нужно использовать большую изначально картинку?
          • НЛО прилетело и опубликовало эту надпись здесь
              +1
              добавил анимацию в последний момент :)
                +1
                интересно, но только с такой частотой вращения колёс машинка быстрее ехать должна. мне так кажется )
                  0
                  факт. пока что это просто демка, но можно дойти и до колёс — дьявол в деталях, как говорится.
                    +2
                    Это тюнинг такой. Внешние вращающиеся диски.
                      –1
                      тюнинг самый уродливый из всех возможных, надо сказать :)
                        +3
                        Самый уродливый — когда глушитель отрывают, чтоб «ревело».
                –2
                Классно, но на мой взгляд непрактично… поскольку кроме внешнего контроля спрайта ещё потребутеся предварительная работа (и временами не маленькая) с изображением. С другой стороны можно конечно такой процесс автомитизировать.
                  0
                  Подобные нужды не возникают каждый день. Но тем, кто ищет как сделать ещё какое-то необычное дополнение к сайту — может помочь. А автоматизации поддаётся очень просто, да. Несложно даже сделать скрипт для фотошопа или програмку на gd для php.
                  +2
                  прекрасное решение, я считаю. Весьма изящно!
                    +3
                    Отлично! Только через стекла всегда небо проглядывает)
                      0
                      не, это тонировка третьтьего уровня ;)
                        –1
                        и водителя нет, лол :)
                        +2
                        я сначала подумал, что как-то Canvas / VML использовали…
                          +1
                          про canvas/vml тоже что-нибудь напишем. :)
                          +1
                          Очень круто. Вещь из разряда «забыть про завтрак и разобраться как это работает». Скажите, а жопку у машинки специально обрезали, чтобы не цеплялась, или случайно вышло?
                            0
                            случайно, только потом заметил. о боже мой, z4 без спойлера похожа на лексус :)
                            +1
                            а субпиксельное вращение колёс? ,)
                              0
                              оно есть!
                              0
                              Того же можно добиться используя canvas,
                              и колёcа тоже в нём крутить :)
                                –6
                                Только я вижу что оно дёргается?
                                Кстати анимация на колёсах очень сильно отвлекает пользователя от дёргания картинки — это +… но картинка всё равно дёргается и очень заметно…
                                Возможно для более мелких спрайтов это будет и незаметно — но в данном конкретном примере это не так.
                                  0
                                  Кстати да, зря минусуете.
                                  Попробуйте увеличить масштаб страницы, процентов так до 800. Машинка действительно дергается, но я бы не сказал что это так уж заметно при масштабе 100%
                                    +1
                                    Если уж очень хочется смотреть с увеличением, можно сделать больше спрайтов
                                      –1
                                      я не говорил что это нужно, я сказал что при большом масштабе можно заметить подергивания :)
                                      при оригинальном размере все ок
                                      0
                                      я полагаю, что есть некоторые проблемы с тем, как работают браузеры при увеличении контента. ну и вся эта точность — увеличивая картинку, вы сводите на нет шаги по её уменьшению и она начинает дёргаться как обычный спрайт без АА.
                                      +1
                                      Версия без вращения колёс, попробуйте:
                                      www.kittyhug.ru/subpixel/?nowheels=true
                                        –1
                                        ну извините :) — я всё-равно вижу как машина дёргается… немного дергается… наверное на сайте с графикой это будет совсем незаметно…
                                          0
                                          досадно!
                                          будем считать, что это proof of concept и в реальности в этих скриптах нужно что-то доточить — на первая версия этого примера мы потратили всего пять минут после идеи, а потом ещё 15 минут — на переделку для хабра и на пример с машинкой.
                                            0
                                            Попробуйте в другом браузере с более быстрым js. Или перезапустите, если у вас Fx и открыто много вкладок. В моем Fx 3.5 тоже дергалось пока не перезапустил.
                                              0
                                              не хочу показаться занудой — но вы посетителя вашего сайта тоже будете просить закрыть все другие вкладки браузера чтобы нормально отображалась ваша спрайтовая графика?

                                              я ж говорю… если на странице будет текст, графика, не белый фон — то этот информационный шум подавит дёргание картинки — оно совсем-совсем незаметное :))) — пользователь просто не будет акцентироваться на нём (подергивании)
                                                0
                                                я думаю, что чем больше и плотнее будет страница, тем более заметным будет каждое конкретное подёргивание. но если рассматривать ускорение js и браузеров как самый стабильный нынешний тренд, то все эти проблемы будут решены за нас.
                                                  +2
                                                  Могу посоветовать переделать с горизонтального спрайте на вертикальный, при масштабе ≠ 100% будет лучше.
                                                    0
                                                    а какая будет разница?
                                                      0
                                                      Масштаб не кратен 100%. Это значит, что некоторые пиксели изображения браузер рисует больше, некоторые меньше. Эти неровности равномерны, в виде паттерна. Вы смещаете изображение туда-сюда, и при некратности ширины этого паттерна ширине вашего изображения, вы получаете картинку, начинающуюся с разных мест паттерна, соответственно первыми оказываются то увеличенные пиксели, то уменьшенные, картинка скачет туда-сюда. Если сделать вертикально, смещение по Х всегда будет одним и тем-же, картинка будет начинаться с одного паттерна.
                                                        0
                                                        По поводу масштаба и дергания вы были правы, а вот вертикальным или горизонтальным будет спрайт — ничего не изменится, так как в примере смещение по X всегда целочисленное, а уже внутри этого div'а с картинкой background сдвигается на определённый кадр.

                                                        Но всё равно — спасибо.
                                                          0
                                                          Проверил сам. В Опере без изменений, а в фаерфоксе еще и вверх-вниз начало скакать, такое впечатление, что машина по кочкам едит, забавно :)
                                                            0
                                                            А еще я вижу, что у вас какие-то проблемы с библиотекой prototype, она генерирует такой код в DOM:
                                                            style=«position:absolute;background:url(all-moved3.gif);repeat:none;width:150px;height:60px;;left:0px;;background-position:-150px 0px;;left:0px;;background-position:-300px 0px;;left:0px;;background-position:-450px 0px;;left:1px;;background-position:0px 0px;;left:1px;;background-position:-150px 0px;;left:1px;;background-position:-300px 0px;;left:1px;
                                                            И так далее.
                                                              0
                                                              я думаю что это ваш браузер так отрабатывает историю изменения css свойств. я проверил dom вывод из скрипта и там такого нет.
                                                                0
                                                                Проблем ведь явно не в браузере, а в библиотеке. Через некоторое время работы пример начинает очень сильно тормозить. Ладно, буду знать что proptotype так себя ведет.
                                                                  0
                                                                  стало интересно. а что за браузер? и как вы смотрите эти свойства?
                                                                    0
                                                                    Опера, драгонфлай.
                                                                      0
                                                                      изменил прототайповское обращение к свойству на прямое, в опере исчезло накопление изменений. надеюсь, всё в порядке :)
                                                                        0
                                                                        (Глядя на минусы у всех своих сообщений)
                                                                        Может кто-то хочет высказаться?
                                                                          0
                                                                          это не я. я думаю что это что-то про оперу.
                                                      0
                                                      У вас масштаб страницы в фф не кратен 100%. Вид — Масштаб — Сбросить. Или Ctrl+0.
                                                        0
                                                        кратен :) — поверьте наслово :)
                                                  • НЛО прилетело и опубликовало эту надпись здесь
                                                    0
                                                    машина не дерегается, просто в какой-то момент скрипт замирает и продолжает заново… движется она достаточно плавно, если бы на javascript который затухает от раза к разу.
                                                      0
                                                      я думаю, это что-то отнимает системное время — диск, много закладок, ну или ещё что-то. javascript с обновлением каждые 50мс не успевает отработать и происходит скачок.
                                                    +7
                                                    это у тебя глазищи от зависти дергаются:)
                                                      +3
                                                      :))))))))
                                                    +4
                                                    Что-то у машинки с одним цилиндром, потраивает чуток.
                                                      0
                                                      Это вроде Z4. Насколько я помню там 6 цилиндров :)))
                                                      0
                                                      Спасибо за статью, полезно!
                                                      Такой подход хорош когда объект движется медленно и постоянно, но если бы движение было однократное или более быстрое, то лично я бы не стал заморачиваться с АА. ИМХО.
                                                        0
                                                        У js анимации с easing всегда есть некий последний или первый момент, когда объект двигается ещё слишком медленно. Обычно это решают за счёт уменьшения общего времени действия эффекта, а с таким методом можно делать практически произвольное время и субпиксельность будет задействована только в тот момент, когда она нужна.
                                                        0
                                                        Изящно. Только не думаю, что на клавогонках это сильно полезно — машинки преодолевают большее расстояние и достаточно быстро. А вот стрелка спидометра сделана уже через canvas, поэтому вращается плавно.

                                                        Да, и спасибо за пиарчик :) Хотя на Хабре вроде уже и так все про клавогонки знают.
                                                          0
                                                          ну, мало-ли :) вдруг пригодилось бы
                                                            0
                                                            Вообще, очень красивое решение, может где-то да пригодится (в марафоне?). Спасибо.
                                                          +4
                                                          Ради таких статей я читаю Хабр.
                                                            0
                                                            спасибо!
                                                          • НЛО прилетело и опубликовало эту надпись здесь
                                                              0
                                                              расскажите, если где-то используете, было бы любопытно посмотреть.
                                                              • НЛО прилетело и опубликовало эту надпись здесь
                                                              +1
                                                              впечатляюще
                                                              думаю можно воспользоваться этой идеей можно и при анимировании обычных html элементов
                                                                +1
                                                                Обычные html элементы не поддаются субпиксельному позиционированию, так что с ними неясно как быть. А вот всякие эффекты завязаные на картинки, css спрайты и фоны — сколько угодно.
                                                              • НЛО прилетело и опубликовало эту надпись здесь
                                                                  0
                                                                  спасибо, пользуйтесь :)
                                                                  +1
                                                                  Вопрос — необходимость в четырёх спрайтах — это получено опытным путём или как? Может быть хватило бы двух или трёх?
                                                                    0
                                                                    Теоретическим. Если мы хотим точность движения до 0.25 пиксела, то нужно 4 кадра. До 0.1 пиксела — 10 кадров. Вопрос в том, насколько медленно мы хотим двигать полученный объект в итоге и том, когда глаз перестанет замечать разницу. Я думаю, что на 10 кадрах уловить изменения уже просто невозможно.
                                                                    –1
                                                                    Я уже было обрадовался, но когда дошел до сути метода… мда, в моем случае это к сожалению не пройдет :)
                                                                    А вообще — зачет за саму идею!
                                                                    Я вот тоже стараюсь везде где это можно, обходиться javascript'ом. Хотя вопрос: «Может стоило сделать это на флеше»? Остается для меня открытым.
                                                                    Спасибо за статью.
                                                                      0
                                                                      подойдёт, почему нет?
                                                                        0
                                                                        Потому что
                                                                        а) В некоторых браузерах движение шапки моего сайта и так немного подтормаживает (и загружает во всю процессор) даже на достаточно мощных машинах, а работать с картинками в 3-4 раза больше, подозреваю, будет еще хуже.
                                                                        б) вот эта картинка и так весит 136 кб (975х429 px), куда уж больше.

                                                                        Для таких больших картинок, лучше все-таки использовать флеш, если плавности движения не хватает (имхо).

                                                                        Так что в моем случае можно конечно попробовать так сделать, но я считаю, что игра не стоит свеч, а то, что есть — вполне приемлемо.
                                                                        0
                                                                        вот пример на вашу тему.
                                                                        только мне нужно было облако зациклить чуть более тщательно, у меня при уменьшении по краю картинки пошла белая полоска.

                                                                        kittyhug.ru/subpixel/index2.php
                                                                          +1
                                                                          Спасибо за пример, было очень полезно посмотреть на производительность этого на практике.
                                                                          В IE8 безбожно глючит (Core 2 Duo 1.8 Ghz) и жрет больше половины процессорного времени. Удивительно, но IE6,7 (через IETester) показывают нормальную производительность.
                                                                          Opera, Chrome, FF — все нормально.

                                                                          Вот видите — я бы может и сделал так(кстати, моя картинка по площади почти в три раза больше), но Microsoft со своим новым детищем мне не дает.

                                                                          Правильно говорили, что избавляться нужно не только от IE6, а от всего семейства :(

                                                                            0
                                                                            Всё с ie в порядке. Я запустил под ie8 в виртуальной(!) машине и всё работает также, как и у меня во всех других браузерах. Могу сказать, что мы недавно практиковали css спрайт 15000х10000 в одном проекте и пока никто не жаловался.
                                                                            0
                                                                            Отличный пример! Гораздо более интересный, чем с машинкой ))

                                                                            Предлагаю добавить пример в текст поста (если ещё что-нибудь будет, тоже было бы неплохо).
                                                                              0
                                                                              Кстати, даже «дёргания» при изменении масштаба смотрятся симпатично))))
                                                                                0
                                                                                полоса видимо из-за бикубического метода интерполяции в фотошопе. Нужно использовать билинейный.
                                                                                  0
                                                                                  да, уже поменял, спасибо
                                                                                  0
                                                                                  в класс «about» добавьте «position:absolute;z-index:1» чтоб было совсем круто
                                                                                    0
                                                                                    чтобы под текстом ехало? )
                                                                                      0
                                                                                      ага, смотрится круче IMHO
                                                                                        0
                                                                                        сделал ) лол
                                                                                          0
                                                                                          О! То что надо. Продолжим?
                                                                                          два полупрозрачные png с облаками плывут с разной скоростью.
                                                                                            0
                                                                                            Это уже лишнее. Proof of concept готов, а дальше — пусть занимаются те, кому это нужно. :)
                                                                                  0
                                                                                  Оффтоп — сделайте облака слоями, отдельными png, движущимися с разной скоростью (с параллаксом). Симпатичней смотреться будет. У меня нечто подобное на клавогонках в шапке тоже.
                                                                                  +1
                                                                                  Снимите галочку и увидите тормозной путь :)
                                                                                    0
                                                                                    лол
                                                                                    +2
                                                                                    ха. прикольно…
                                                                                    все у кого дергается идут лесом. речь шла о картинке которая не попикселям бегает.
                                                                                      0
                                                                                      в точку! )
                                                                                        +1
                                                                                        да выглядит шикарно.
                                                                                          0
                                                                                          поправил, спасибо
                                                                                        0
                                                                                        Ссылки битые. Подправьте пожалуйста.

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

                                                                                        Самое читаемое