Сетка является одной из основ всей практики дизайна и проявляется почти во всем, что мы видим, от пользовательских интерфейсов до макетов печати. Babylon.js расширяет возможности управления графическим пользовательским интерфейсом (GUI), добавляя сетки в систему, что является одной из самых важных функций версии 3.3. Чтобы продемонстрировать контроль, который у нас теперь есть в системе GUI, я решил заняться расширением одного из наших существующих элементов управления GUI, палитры цветов.

Сначала немного обо мне. Я был визуальным дизайнером на протяжении десятилетий, а в последнее время стал 3D-художником и техническим художником. У меня есть опыт написания кода для Интернета (HTML, CSS и PHP) и для игровых движков (C #), но я далек от эксперта. Я нахожусь где-то между художником и инженером, и у меня очень небольшой опыт работы с JavaScript, что делает этот проект идеальным тестом для простоты создания и участия в Babylon.js.

У нас уже есть элемент управления GUI для выбора цвета в движке, но только графическое цветовое колесо вернет Color3. Что, если я хочу вызвать палитру цветов, чтобы назначить определенный цвет? А как насчет сохранения цвета для использования позже, как мы можем это сделать? Все мы видели окна выбора цвета в программном обеспечении, которое мы используем ежедневно, и все они имеют сходство - возможность вручную вводить RGB или шестнадцатеричные значения, интерактивное графическое представление цветового круга и палитру сохраненных цветов для повторного использования. Это был хороший тест для сеток и для понимания того, насколько сложным будет код для создания полнофункционального окна выбора цвета.

Дизайн окна

Первое, что я сделал, - это набросал то, что, как я думал, нам нужно с точки зрения элементов управления, и это исходные данные, которые я выбрал.

  • Инструмент выбора цветового круга, который я бы использовал в нашем текущем элементе управления, BABYLON.GUI.ColorPicker ()
  • Образцы для текущего и последнего выбранных цветов, чтобы помочь пользователю выбрать новый цвет на основе последнего выбранного цвета.
  • Ввод текста для значений RGB в 8-битных целых числах (0–255)
  • Ввод текста для значений RGB в числах с плавающей запятой (0–1), который является вводом цвета по умолчанию для Babylon.js
  • Ввод текста для шестнадцатеричных значений цвета (# 000000 - #ffffff), который используется по умолчанию для элементов управления GUI.
  • Обновление всех значений в окне в реальном времени, поскольку любое отдельное значение изменяется при вводе пользователя
  • Функция сохранения, которая сохранит текущий выбранный цвет в ящик для дальнейшего использования.
  • Проверка ошибок, чтобы не дать пользователю ввести недопустимые значения или символы и избежать невозможности вернуть цвет

С этими рекомендациями я набросал образец окна с несколькими линиями сетки, чтобы я мог получить некоторые базовые измерения. Я использовал Adobe Illustrator для этого шага, но это можно сделать с помощью любого удобного вам инструмента. Я считаю, что использование рабочего процесса, который используют большинство художников, наброски вашей композиции с низкой точностью, чтобы помочь сделать выбор и спланировать окончательную композицию, позволяет мне знать, что мне нужно построить, прежде чем я напишу свою первую строку кода. Я более подготовлен к структуре, которую мне нужно построить, и могу обратиться к моему эскизу, чтобы увидеть, как сетки должны размещаться, если я потеряюсь во время написания кода.

Сила сетки заключается в том, что я могу легко создавать строки и столбцы для выравнивания по моему макету и назначать элементы управления определенной ячейке. Я, конечно, мог бы расположить все окно с одной ячейкой и стилизовать положение каждого элемента управления вручную, используя смещение сверху и слева от элемента управления, но этот метод не подходит для адаптивного дизайна или быстрого редактирования размещения групп элементов управления. Чтобы понять сложность вложенных сеток, я создал диаграмму ниже, чтобы проиллюстрировать отдельные элементы управления сеткой, сколько строк и столбцов у каждой из них и где каждый размещен в иерархии.

Построение системы

Теперь, когда у меня есть план для окна, я решил написать функции, которые будут вызывать окно по запросу. В качестве прототипа я просто добавил прослушиватель событий для вызова функции при нажатии клавиши. Когда я добавлял элементы управления сеткой в ​​окно, я назначил каждому элементу управления случайный цвет фона, чтобы определить, что у меня правильный макет, прежде чем добавлять какие-либо элементы управления вводом или кнопками. На последнем уровне сетки мне нужно было убедиться, что блокировка сделана правильно для кнопок и полей ввода. Для этого я вставил функцию для создания BABYLON.GUI.Rectangle () с шириной и высотой 100% и случайным цветом фона и вызвал эту функцию в каждой ячейке, которая будет иметь ввод.

После настройки сетки по мере необходимости я просто добавил элемент управления в каждую из ячеек по мере необходимости: BABYLON.GUI.ColorPicker (), BABYLON.GUI.InputText () , BABYLON.GUI.CreateSimpleButton () и BABYLON.GUI.Text (). После включения элементов управления доступ к новым функциям отображения отладки в обновленном инспекторе помогает гарантировать, что все выровнено, как показано ниже. Наибольшая часть сложности возникла не из-за макета окна, а из-за желания обновлять все элементы управления в реальном времени, когда пользователь вносит изменения с помощью щелчка мышью или ввода с клавиатуры.

Проверки и противовесы

Чтобы обеспечить максимальную гибкость, я использовал свойство name элементов управления, дав каждому элементу управления уникальное имя. Это служит двум целям. Во-первых, ваш элемент управления появится в древовидной структуре инспектора с описательным именем, позволяющим легко переходить к нужному элементу управления. Во-вторых, я могу проверить имя элемента управления, чтобы узнать, следует ли мне обновлять его значение или нет. Я создал функцию, которая обновляла бы все элементы управления сразу и передавала значение имени текущего элемента управления в функцию. Имя каждого элемента управления сравнивается с именем выбранного элемента управления, и обновляются только те, которые не совпадают.

В результате, когда пользователь вводит число, обновляются остальные значения для других элементов управления и оценивается новый цвет, но ввод, которым управляет пользователь, не изменяется. Это становится особенно важным при редактировании значений с плавающей запятой для канала, поскольку значения «0», «0» и «.» все должны иметь значение 0 для обновления цвета, но мы не хотим изменять поле, которое пользователь активно редактирует, иначе они не смогут ввести желаемое значение.

Также была некоторая сложность с вводом шестнадцатеричной строки, поскольку мы также хотели обновить ее на лету, без необходимости нажимать Enter для подтверждения. Для этого я просто проверяю шестнадцатеричную строку, чтобы убедиться, что она содержит менее 6 символов. Если это так, я добавляю один или несколько символов «0» в начало строки, пока она не станет длиной в 6 символов. Опять же, элемент управления с фокусом не обновляется, поэтому пользователь не видит начальные символы «0», если они не изменяют фокус с шестнадцатеричного элемента управления, и в этом случае мы обновляем строку с правильным значением с начальными символами «0». Это позволяет нам передавать действительные данные о цвете другим элементам управления, чтобы они корректно обновлялись при редактировании шестнадцатеричного числа.

Другая небольшая функция, которую я добавил для шестнадцатеричных значений, - это автоматическое понимание сокращенного представления. Сокращенное представление шестнадцатеричного числа выглядит как «#abc», которое оценивается как «#aabbcc». Для этого я добавил тест в шестнадцатеричные функции, чтобы проверить, состояла ли в любое время строка ровно из трех символов. Если это так, вместо добавления начальных символов «0» я оцениваю строку как расширенное шестнадцатеричное число, сгенерированное из сокращенной строки. Это означает, что если вы хотите использовать сокращенный цвет, вам нужно только ввести сокращенное значение, и цвет будет оцениваться правильно. Как только элемент управления теряет фокус, сокращенная строка преобразуется в полное шестнадцатеричное, но я хотел дать пользователю возможность ускорить ввод общих цветов.

Последней частью работы в элементах управления вводом было добавление проверки регулярного выражения, чтобы убедиться, что каждый элемент управления будет получать только правильные символы, а любые недопустимые символы вернут элемент управления в фокусе к последней допустимой записи. Это препятствует тому, чтобы пользователь мог ввести символ, который не мог бы правильно оценить и заполнить все элементы управления предупреждениями «NAN» или «not-a-number». Это особенно важно, потому что все элементы управления графическим интерфейсом используют строки для ввода, поэтому для того, чтобы все работало, требуется много преобразований между строками и числами.

Сохранение прогресса

Последним шагом в создании окна было добавление сохраненного ящика цветов. Окно принимает в качестве части своего конструктора массив строк для сохраненных цветов. Я решил использовать массив строк вместо массива цветов, потому что для всех элементов управления графическим интерфейсом требуется шестнадцатеричная строка для цвета. Для передачи цвета обратно в приложение из окна выбора цвета потребуется одно преобразование в Color3, но для ввода массива Color3 потребуется много преобразований в шестнадцатеричный формат для установки цветов в элементах управления.

При создании окна выбора цвета, если сохраненный массив цветов не пуст, новый элемент управления добавляется под главным окном, и для каждого сохраненного цвета создается образец цвета, представленный кнопкой, с этим цветом в качестве фона. Нажатие на кнопку образца цвета установит активный цвет в окне на этот сохраненный цвет, позволяя пользователям повторно использовать цвет без ввода значений вручную. Размер образца цвета и количество образцов в строке настраиваются и автоматически переносятся в другую строку, если сохранено достаточно цветов.

Существует также конфигурация общего количества цветов, которые можно сохранить, чтобы ящик не становился слишком большим. После достижения предела кнопка «Сохранить цвет» будет отключена до тех пор, пока не будут удалены некоторые из сохраненных цветов. Нажатие на кнопку «Изменить сохраненные цвета» изменяет кнопки образцов цвета, и в центре их появляется значок удаления, так как их поведение меняется от изменения активного цвета к удалению этого цвета из массива сохраненных цветов.

Из-за сложности взаимодействий, проверки ошибок и компоновки окна выбора цвета мы решили поместить его как класс в Babylon.js, и он может вызываться по мере необходимости в его завершенном состоянии. В настоящее время я работаю над преобразованием прототипа в TypesScript и над настройкой размера окна, чтобы содержащиеся элементы управления автоматически перекомпоновывались в зависимости от общего размера. Это будет мой первый вклад в кодовую базу Babylon.js, поскольку моя роль в команде заключалась в том, чтобы быть творческим руководителем, а не инженером. Однако я скажу, что процесс участия очень прост, и если вы также заинтересованы в участии, вы можете найти все, что вам нужно, на https://doc.babylonjs.com/how_to/how_to_start

Я надеюсь, что это даст вам некоторое представление о том, как использовать сетки в Babylon.js, а также о том, как функция в движке может появиться из простого исследования, чтобы упростить задачу. Этот проект был забавным исследованием системы графического интерфейса пользователя, и у меня есть некоторые мысли о том, как расширить эту функцию. Но это будет тема для следующего поста.

Патрик Райан, ведущий креативный директор Babylon.js