что такое спрайт персонажа
Разработка игр под NES на C. Главы 4-6. Рисуем персонажа
В этой части рассмотрим работу с графикой: фон и спрайты персонажей.
>>
Что такое V-blank?
PPU — графический процессор — может или отправлять сигнал в телевизор, или получать информацию от процессора, но не одновременно. Так что единственное время для пересылки это V-blank, период кадрового гасящего импульса.
90% времени PPU отправляет пиксели в видеовыход, строка за строкой слева направо и сверху вниз. Внизу экрана делается пауза, и все повторяется снова. Это происходит 60 раз в секунду. Пауза после отрисовки кадра и есть V-blank. Это весьма короткий промежуток времени. В него реально вложить обновление 2-4 столбцов фоновых тайлов и обновление спрайтов. Обновление фона особенно критично для игр с прокруткой.
Сейчас мы напишем программу, которая будет выводить “HELLO WORLD” по 1 букве каждые 30 кадров. После вывода всей фразы очистим экран, и повторим все по кругу.
Обратите внимание на фрагмент
в файле reset.s. Это код обработчика немаскируемого прерывания, который фактически реализует счетчик кадров в глобальной переменной. Каждый кадр выставляет флаг NMI_flag, и в случае если прошло 30 кадров (0.5 секунды), выводится спрайт очередной буквы. Вся логика реализована в main().
В идеале, надо ждать V-blank перед вызовом All_On(), иначе один кадр после него будет искажен, и экран будет мерцать. В этом примере этот эффект незаметен, потому что All_On() вызывается единственный раз при старте приставки, экран в это время черный, и искажение незаметно.
Немного цвета
Теперь можно раскрасить то что получилось.
Таким образом можно одновременно отрисовать 25 цветов из 50 возможных.
Для фона палитра определяется для блока из 2х2 тайлов, размером 16х16 точек. Для этой разбивки удобно использовать Nes Screen Tool. Большинство игр строит фон именно из таких счетверенных метатайлов.
Здесь одна буква соответствует одному тайлу, малый квадрат — метатайл 2х2.
То есть чтобы поменять палитру правого нижнего квадранта на первую из 4 возможных, надо поменять два старших бита атрибута на 01: 01хххххх.
Я добавил к прошлому примеру палитры, так что буквы теперь разноцветные. Палитры вынесены в отдельный файл и импортируются через #include, а переменные определены в нулевой странице памяти через #pragma — просто для демонстрации этой фичи. Нулевая страница работает быстрее, но 10-20 переменных там используется для внутренних нужд компилятора. Так что надо рассчитывать где-то на 235 доступных байт.
Вот полезная шпаргалка по адресам таблицы атрибутов и ее привязке к экранным координатам:
Экран шириной 256 точек, каждая клетка таблицы соответствует квадрату 32х32
Спрайты
Спрайт — это картинка 8х8, которая может перемещаться по экрану. Есть хитрый способ использовать спрайты 8х16, но мы так делать не будем. Почти все персонажи игр состоят из спрайтов. Хотя в некоторых случаях нужно отрисовывать их фоновыми тайлами из-за ограничений на количество спрайтов, такое используется для финальных боссов в некоторых играх.
8х8 точек это очень мало, поэтому придется собирать персонажа из нескольких спрайтов: маленького Марио из 2х2, а большого из 2х4.
Надо помнить об ограничениях. Поддерживается не больше 64 спрайтов, и не более 8 на одной строке экрана. При превышении лимита будут отрисованы только спрайты с большим приоритетом. Если менять приоритет спрайта между кадрами, он будет мигать. Этот способ часто используется в играх.
PPU хранит информацию о спрайтах в таблице OAM. Ее размер 256 байт: по 4 байта на каждый из 64 возможных спрайтов. Если накладываются два спрайта с одинаковым приоритетом, то спрайт с меньшим номером отрисовывается поверх. Если на одной строке экрана будет больше 8 спрайтов, то отрисуются только 8 с меньшими номерами.
Таблица OAM хранит такие атрибуты:
В нашем примере мы сделаем метаспрайт из 4 спрайтов и добавим анимацию.
Надо помнить, что спрайты отрисовываются на 1 точку ниже от ожидаемой координаты. На картинке с Марио вверху поста видно, что он на 1 пиксель ушел в пол.
Есть немного улучшенная версия, где персонаж поворачивается при движении по квадрату.
Модульные спрайтовые персонажи и их анимация
Эта запись девлога целиком посвящена моей системе анимации персонажей, она наполнена полезными советами и фрагментами кода.
За последние два месяца я создал целых 9 новых действий игрока (такие забавные вещи как блокировка щитом, уворачивание в прыжке и оружие), 17 новых носимых предметов, 3 набора брони (пластинчатый, шёлковый и кожаный) и 6 видов причёсок. Также я завершил создавать всю автоматизацию и инструменты, поэтому всё уже используется в игре. В статье я расскажу, как этого добился!
Надеюсь, эта информация окажется полезной и докажет, что необязательно быть гением, чтобы самостоятельно создать подобные инструменты/автоматизацию.
Краткое описание
Изначально я хотел проверить, можно ли совместить наложенные друг на друга спрайты с синхронизованными аниматорами для создания модульного персонажа с заменяемыми причёсками, снаряжением и носимыми предметами. Можно ли объединить нарисованную вручную пиксельную анимацию с по-настоящему настраиваемым персонажем.
Разумеется, такие функции активно используются в 3D- и 2D-играх с пререндеренными спрайтами или в 2D-играх со скелетной анимацией, но насколько я знаю, существует не так много игр, совмещающих созданную вручную анимацию и модульных персонажей (обычно потому, что процесс оказывается слишком монотонным).
Я раскопал этот древний GIF моего первого месяца работы с Unity. На самом деле этот модульный спрайт оказался одним из первых моих экспериментов в разработке игр!
Я создал прототип при помощи системы анимаций Unity, а затем для проверки концепции добавил одну рубашку, одну пару штанов, одну причёску и три предмета. Для этого потребовалось 26 отдельных анимаций.
В то время я создавал всю свою анимацию в Photoshop и не заморачивался автоматизацией процесса, поэтому он был очень скучным. Потом я подумал: «Так, основная идея сработала, позже я добавлю новые анимации и снаряжение». Оказалось, что «потом» — это несколько лет спустя.
В марте этого года я нарисовал дизайн большого количества брони (см. мой предыдущий пост), и заметил, как этот процесс можно сделать более удобным. Я продолжал откладывать реализацию, потому что даже при наличии автоматизации нервничал, что ничего не получится.
Я ожидал, что придётся отказаться от кастомизации персонажа и создать единственного главного героя, как в большинстве игр с ручной анимацией. Но у меня был план действий, и настало время проверить, смогу ли я победить этого монстра!
Спойлер: всё получилось замечательно. Ниже я раскрою свои ***секреты***
Модульная система спрайтов
I. Познай свои границы
Предварительно я провёл много тестов арта и контроля времени, чтобы выяснить, сколько может занять такая работа, и будет ли достижим для меня подобный уровень качества.
Я придумал численную оценку для каждой анимации и отказался от всего с плохими показателями. Изначально я планировал создать 6 наборов брони, но быстро осознал, что это перебор, и выбросил три типа.
Аспект отслеживания времени оказался очень важным, и я крайне рекомендую использовать его, чтобы отвечать на вопросы типа: «Сколько врагов могу я позволить себе создать в игре?». Всего после нескольких тестов мне удалось экстраполировать достаточно точную оценку. При дальнейшей работе над анимациями я продолжил следить за временем и пересматривать мои ожидания.
Поделюсь копией моего журнала работы за последние два месяца. Учтите, что это время идёт в добавок к моей обычной работе, где я провожу по 30 часов в неделю:
II. Смена палитры ради светлого будущего
С умом используя цвета в дизайне спрайтов, можно отрисовать один спрайт и создать множество различных вариаций при помощи смены палитры. Можно менять не только цвета, но и создавать различные включаемые и отключаемые элементы (например, заменой цветов на прозрачность).
Каждый набор брони имеет 3 вариации, а смешивая верхние и нижние части, можно получить множество комбинаций. Я планирую реализовать систему, в которой можно собрать один набор брони для внешнего вида персонажа, а другой — для его характеристик (как в Terraria).
В процессе работы меня приятно удивляли обнаруживаемые любопытные комбинации. Если соединить пластинчатый верх с шёлковым низом, то можно получить нечто в стиле боевого мага.
Лучше всего реализовывать смену палитр, используя в спрайте цвета, кодирующие значение, чтобы в дальнейшем можно было брать их для поиска настоящего цвета из палитры. Я знесь немного упрощаю, так что вот видео, с которого можно начать:
Я не буду объяснять всё в подробностях, а вместо этого расскажу о способах реализации этой техники в Unity, и об их плюсах и минусах.
1. Текстура поиска для каждой палитры
Это наилучшая стратегия для создания вариаций врагов, фонов и всего того, где множество спрайтов иеет одинаковую палитру/материал. Различные материалы нельзя сгруппировать в батчи, даже если они используют одинаковый спрайт/атлас. Работа с текстурами довольно мучительна, но палитры можно изменять в реальном времени, заменяя материалы, с помощью SpriteRenderer.sharedMaterial.SetTexture или MaterialPropertyBlock, если вам нужны разные палитры для каждого экземпляра материала. Вот пример фрагментной функции шейдера:
2. Массив цветов
Я остановился на этом решении, потому что мне нужно было заменять палитры каждый раз, когда меняется внешний вид персонажа (например, при надевании предметов), и создавать некоторые палитры динамически (чтобы отобразить выбранные игроком цвета волос и кожи). Мне показалось, что во время выполнения и в редакторе для этих целей гораздо проще будет работать с массивами.
Я представил свои палитры как тип ScriptableObject и использовал для их редактирования инструмент MonoBehaviour. Проработав долгое время над редактированием палитр в процессе создания анимаций в Aseprite, я понял, какие инструменты мне требуются и писал эти скрипты соответствующим образом. Если вы хотите написать собственный инструмент для редактирования палитр, то вот какие функции я обязательно рекомендую реализовать:
— Обновление палитр на различных материалах при редактировании цветов для отображения изменений в реальном времени.
— Присваивание названий и изменение порядка цветов в палитре (используйте поле для хранения индекса цвета, а не его порядка в массиве).
— Выбор и редактирование нескольких цветов за раз. (Совет: поля Color в Unity можно копипастить: просто нажмите на один цвет, скопируйте, нажмите на другой цвет, вставьте — теперь они одинаковы!)
— Применение цвета оверлея ко всей палитре
— Запись палитры в текстуру
3. Единая текстура поиска для всех палитр
Если вы хотите переключать палитры на лету, но в то же время вам необходим батчинг для снижения количества вызовов отрисовки, то можно использовать эту технику. Она может оказаться полезной для мобильных платформ, но использовать её довольно неудобно.
Во-первых, нужно будет упаковать все палитры в одну большую текстуру. Затем вы используете цвет, заданный в компоненте SpriteRenderer (AKA цвет вершины) для определения строки, которую надо считать из текстуры палитры в шейдер. То есть палитра этого спрайта управляется через SpriteRenderer.color. Цвет вершины — это единственное свойство SpriteRenderer, которое можно менять без нарушения батчинга (при условии, что все материалы одинаковы).
В большинстве случаев лучше всего использовать для управления индексом альфа-канал, потому что вам скорее всего не понадобится куча спрайтов с различной прозрачностью.
Чудеса замены палитр и слоёв спрайтов. Так много комбинаций.
III. Автоматизируйте всё и применяйте подходящие инструменты
Для реализации этой функции автоматизация была совершенно необходимой, потому что в результате у меня получилось около 300 анимаций и тысячи спрайтов.
Первым моим шагом стало создание экспортёра для Aseprite, чтобы управлять моей безумной схемой слоёв спрайтов при помощи удобного интерфейса командной строки. Это просто скрипт на perl, который обходит все слои и метки в моём файле Aseprite и эспортирует изображения в определённой структуре каталогов и имён, чтобы я смог в дальнейшем их считывать.
На стороне Unity серьёзные проблемы у меня возникли в двух местах: в загрузке/нарезке спрайтшита и в построении клипа анимации. Мне бы очень помог понятный пример, поэтому вот фрагмент кода из моего импортёра, чтобы вы не так мучились:
Если вы этого ещё не делали, то поверьте — начать создавать собственные инструменты очень легко. Самый простой трюк заключается в размещении в сцене GameObject с привязанным к нему MonoBehaviour, которое имеет атрибут [ExecuteInEditMode]. Добавьте кнопку, и вы готовы к бою! Помните, что ваши личные инструменты не обязаны выглядеть хорошо, они могут быть чисто утилитарными.
При работе со спрайтами автоматизировать стандартные задачи довольно легко (например, создание текстур палитр или пакетную замену цветов в нескольких файлах спрайтов). Вот пример, с которого можно начать учиться изменению своих спрайтов.
Как я перерос возможности Mecanim: жалоба
Со временем прототип системы модульных спрайтов, который я создал с помощью Mecanim, стал самой большой проблемой при апгрейде Unity, потому что API постоянно сильно менялся и был плохо задокументирован. В случае простого конечного автомата было бы разумно иметь возможность запрашивать состояния каждого клипа или менять клипы во время выполнения. Но нет! Из соображений производительности Unity запекает клипы в их состояния и заставляет нас использовать для их смены неуклюжую систему переопределений.
Сам по себе Mecanim не такая уж плохая система, но мне кажется, что ему не удаётся реализовать свою основную заявленную особенность — простоту. Идея разработчиков заключалась в том, чтобы заменить то, что казалось сложными и мучительным (скриптинг) чем-то простым (визуальным конечным автоматом). Однако:
— Любой нетривиальный конечный автомат быстро превращается в дикую паутину узлов и соединений, логика которой разбросала по разным слоям.
— Простым случаям использования мешают обобщённые требования системы. Чтобы проиграть одну-две анимации, вам нужно создавать новый контроллер и назначать состояния/переходы. Разумеется, присутствует и излишняя трата ресурсов.
— Забавно, что в результате вам всё равно приходится писать код, ведь чтобы конечный автомат делал что-то интересное, нужен скрипт, вызывающий Animator.SetBool и подобные ему методы.
— Для многократного использования конечного автомата с другими клипами нужно дублировать его и заменять клипы вручную. В дальнейшем вам придётся вносить изменения в нескольких местах.
— Если вы хотите изменять то, что находится в состоянии во время выполнения, то у вас проблемы. Решением будет или плохой API, или безумный граф с одним узлом для каждой возможной анимации.
Рассказ о том, как разработчики Firewatch попали в ад визуального скриптинга. Самое забавное в том, что когда докладчик показывает наиболее простые примеры, они всё равно выглядят безумно. Зрители в буквальном смысле стонут на 12:41. Добавьте огромные затраты на обслуживание, и вы поймёте, почему я сильно не люблю эту систему.
Многие из этих проблем даже не вина разработчиков Mecanim, а просто естественный результат несовместимых идей: нельзя создать общую и в то же время простую систему, а описывать логику при помощи изображений сложнее, чем просто словами/символами (кто-нибудь помнит флоучарты UML?). Я вспомнил фрагмент из доклада Зака Макклендона на Practice NYC 2018, и, если найдётся время, рекомендую вам посмотреть видео целиком!
Однако я разобрался. Визуальный скриптинг всегда порицается агрессивными «пиши свой собственный движок» нердами, не понимающими потребностей художника. К тому же нельзя отрицать, что бОльшая часть кода выглядит как непостижимый технический жаргон.
Если вы уже немного программист и делаете игры со спрайтами, то вам возможно стоит подумать дважды. Когда я начинал, то меня был уверен, что никогда не смогу написать что-то связанное с движком лучше, чем разработчики Unity.
Основы пиксельарта (Часть 1)
Пиксельарт, также известный как дот-арт в Японии, это вид цифрового искусства, где рисование происходит на пиксельном уровне. В основном он ассоциируется с графикой игр 80-90 годов, в которых художники преодолевали технические ограничения (небольшое количество памяти и маленькое разрешение), создавая все более захватывающие картины.
Порог вхождения в пиксельарт довольно низкий, по сравнению с традиционным рисунком и 3D графикой, позволяя инди разработчикам воплощать свои идеи в жизнь. Но это никоим образом не означает, что закончить игру с ним будет легко. Я видел много пиксельарт проектов на кикстартере, которые думали, что управятся с игрой за год, когда в реальности нужно было около шести лет. Пиксельарт на том уровне, который хотят видеть люди требует достаточно много времени и усилий, есть лишь пару путей, позволяющих ускорить этот процесс.
Работая с 3D моделью ты, по крайней мере, можешь крутить ее, деформировать, перемещать её конечности, копировать анимацию с одной модели на другую и т.д, чего не скажешь о пиксельарте. Профессиональный пиксельарт почти всегда подразумевает под собой большое количество кропотливого размещения пикселей на каждом кадре анимации.
Как говорится “Кто предупрежден, тот вооружен!”, а теперь о моем стиле: по большей мере я использую пиксельарт для своих игр, они же и воодушевляют меня продолжать заниматься этим. Если быть точным, то я фанат Famicon(NES), 16 битных консолей и аркадных автоматов 90ых годов.
Мои любимые игры этой эры имели пиксельарт, который нельзя описать иначе как насыщенный, дерзкий и чёткий. но не настолько, чтобы быть чопорным или минималистичным. Это стиль, который я взял за основу своего, но вы можете легко использовать техники, применяемые в этом туториале для чего-то совсем другого. Смотрите на художников, которые вам нравятся и делайте пиксельарт, какой вашей душе угодно!
Самыми базовыми инструментами для занятия пиксельартом являются лупа и карандаш. Также будут полезными линия, фигуры, выделение и заливка цветом. Есть большое количество как платных, так и бесплатных программ, в которых имеются данные инструменты. Я расскажу о самых популярных из них (включая те, которые использую сам).
Если у вас Windows, вы можете использовать Paint, несмотря на скудность программы, в ней имеются все нужные инструменты, чтобы заниматься пиксельартом.
На удивление неплохой редактор, которым вы можете пользоваться прямо через ваш браузер. Может производить экспорт как в png и gif, так и сохранять спрайты в браузере. Неплохой способ начать заниматься пиксельартом.
Самый популярный редактор на данный момент. Содержит большое количество полезных функций и инструментов, постоянно обновляется, доступен как на Windows и Mac, так и на Linux. К тому же вы можете пользоваться программой бесплатно, скомпилировав её исходный код. Если вы серьёзно хотите заниматься пиксельартом и ещё не выбрали себе редактор, то Aseprite будет неплохим вариантом.
Так как Photoshop требует ежемесячную плату и не приспособлен для пиксельарта, я не рекомендую его, если только вы уже не используете его. Несмотря на выше сказанное, его вполне можно использовать для статических спрайтов, но он достаточно громоздкий по сравнению с GraphicsGale или Aseprite.
Я настоятельно рекомендую пользоваться графическим планшетом для любого вида иллюстраций, чтобы предотвратить заболевания повторяющейся длительной нагрузки на запястье (туннельный синдром). Такие заболевания намного легче предотвратить, чем вылечить. Когда появляется боль, вы уже обречены ( мои дни рисования мышкой, сделали невозможным играть в игры с быстрым нажатием кнопок). Так, что позаботьтесь о себе пока не поздно – это того стоит! В данный момент я использую маленький Wacom Intuous Pro.
Если у вас нет возможности купить планшет, по крайней мере, возьмите лучезапястный бандаж. Я использую от компании Mueller Green Fitted Wrist Brace. У других брендов бандажи были либо слишком неудобными, либо недостаточно эффективными.
Давайте приступим к делу! Мы начнем со спрайта персонажа размером 96×96 пикселей. Я решил нарисовать орка, но вы вправе выбрать что-то другое. Конечный вариант орка находится на скриншоте Final Fight, который вы можете увидеть выше, для того, чтобы вы понимали масштаб спрайта– он большой для большинства ретро игр (оригинальный скриншот имеет размер 384×224 пикселя).
Причина по которой мы начинаем с такого большого спрайта заключается в том, что мне будет легче показать техники пиксельарта именно на нем. К тому же, создание больших спрайтов очень похоже на обычное рисование, которое может быть вам знакомо. После того, как мы изучим базовые техники можно будет уменьшить размер спрайта.
Пиксельарт характеризуется своими ограничениями. Каждый пиксель имеет большое значение, по сравнению с другими видами иллюстраций, также как и цвета, количество которых должно быть ограничено.
Так, что да, выбор палитры цветов очень важен и помогает обозначить ваш стиль. Но для начинающих пиксельарт художников лучшим вариантом будет отложить теорию насчёт цветов в сторону и просто выбрать одну из существующих палитр ( или несколько рандомных цветов), чтобы начать рисовать. Одно из преимуществ пиксельарта заключается в том, что вы в любой момент можете поменять палитру цветов.
Именно для этого туториала я буду использовать палитру из 32 цветов, созданную специально для UFO 50. Палитры из 32 и 16 цветов используются достаточно часто. Данная палитра была создана для выдуманной консоли, которая бы находилась где-то между Famicon и PC Engine. Можете спокойно взять эту палитру и двигаться дальше (или нет! Это не столь важно).
Мы начнем рисовать наш спрайт с наброска карандашом, также как если бы мы рисовали на бумаге. Опираясь на свой опыт, могу сказать, что неплохие пиксельарт художники достаточно хороши в обычном рисовании и наоборот. Так что никогда не помешает улучшить свои навыки рисования.
Дальше мы должны убрать лишние пиксели и сделать все линии толщиной в один пиксель. Но какие пиксели являются лишними? – для того, чтобы ответить на данный вопрос, нам нужно познакомиться с таким понятием как зазубрины.
Нам нужно научиться делать два вида линий: прямые и закруглённые. На бумаге все будет зависеть от контроля мышц, но мы работаем с маленькими цветными блоками, что создает свои трудности.
Для того, чтобы делать хорошие линии, нужно свести к минимуму количество зазубрин: маленьких пикселей или группы пикселей, которые нарушают последовательность линии. Так как в пиксельарте каждый пиксель имеет большое значение, пару зазубрин могут испортить весь спрайт. Представьте, что вы рисуете линию на кусочке бумаги и кто-то внезапно стукает по столу, получившаяся у вас загогулина является тем же, что и зазубрины в пиксельарте.
Библиотека Pygame / Часть 2. Работа со спрайтами
Библиотека Pygame / Часть 2. Работа со спрайтами
Вторая часть серии руководств « Разработка игр с помощью Pygame ». Она предназначена для программистов начального и среднего уровней, которые заинтересованы в создании игр и улучшении собственных навыков кодирования на Python. Начать стоит с урока: « Библиотека Pygame / Часть 1. Введение ».
Что такое спрайт?
Спрайт — это элемент компьютерной графики, представляющий объект на экране, который может двигаться. В двухмерной игре все, что вы видите на экране, является спрайтами. Спрайты можно анимировать, заставлять их взаимодействовать между собой или передавать управление ими игроку.
Для загрузки и отрисовки спрайтов в случай этой игры их нужно добавить в разделы “Обновление” и “Визуализация” игрового цикла. Несложно представить, что если в игре много спрайтов, то цикл довольно быстро станет большим и запутанным. В Pygame для этого есть решение: группировка спрайтов.
Набор спрайтов — это коллекция спрайтов, которые могут отображаться одновременно. Вот как нужно создавать группу спрайтов в игре:
Теперь этой возможностью можно воспользоваться, добавив группу целиком в цикл:
Создание спрайта
Можно переходить к созданию первого спрайта. В Pygame все спрайты выступают объектами. Если вы не работали с этим типом данных в Python, то для начала достаточно знать, что это удобный способ группировки данных и кода в единую сущность. Поначалу это может путать, но спрайты Pygame — отличная возможность попрактиковаться в работе с объектами и понять, как они работают.
Начнем с определения нового спрайта:
Дальше необходимо определить rect спрайта. Это сокращенное от rectangle (прямоугольник). Прямоугольники повсеместно используются в Pygame для отслеживания координат объектов. Команда get_rect() оценивает изображение image и высчитывает прямоугольник, способный окружить его.
rect можно использовать для размещения спрайта в любом месте. Начнем с создания спрайта по центру:
Сейчас, если запустить программу, по центру окна будет находиться зеленый квадрат. Увеличьте значения WIDTH и HEIGHT в настройках программы, чтобы создать достаточно пространства для движения спрайта в следующем шаге.
Движение спрайта
Это значит, что при каждом игровом цикле x-координата спрайта будет увеличиваться на 5 пикселей. Запустите программу, чтобы посмотреть, как он скрывается за пределами экрана, достигая правой стороны.
Исправить это можно, заставив спрайт двигаться по кругу — когда он добирается до правой стороны экрана, просто переносить его влево. Это легко сделать, используя элемент управления rect спрайта:
Так, если левая сторона rect пропадает с экрана, просто задаем значение правого края равное 0:
Теперь можно видеть, как спрайт будто бы двигается по кругу.