Этот туториал — часть серии Начало работы — День 3, Неделя 3.
Проблема: обычный скроллинг не заменяет целенаправленный поиск.
Вчера вы отсортировали коллекцию Карты и сохранили вид под каждую задачу. И хотя сортировка стала существенным шагом вперёд, разместив карты с максимальным уроном в самом верху списка, подобный подход быстро теряет свою практическую пользу, как только вопрос «у кого самый большой урон» перестаёт быть актуальным.
При работе над балансом разработчиков крайне редко интересует банальный поиск абсолютного максимума; куда чаще возникают условные задачи вроде поиска всех карт с уроном выше 20, отбора любых нелегендарных карт стоимостью более 3 или выделения урона в диапазоне от 10 до 30. В таких сценариях требуется не порядок сортировки, а полноценный фильтр, точечно описывающий критерии нужной выборки.
Подобные карты можно искать и вручную, скрупулезно просматривая отсортированный столбец и вглядываясь в каждое значение. Однако этот метод работает лишь до тех пор, пока колода достаточно мала и всё, что находится ниже границы видимости, заведомо относится к совершенно другим задачам. Ручная прокрутка лишь демонстрирует верхушку списка, но абсолютно ничего не говорит о том, какие именно данные скрываются в остальной части коллекции
Строка фильтра
В интерфейсе коллекции предусмотрен специальный элемент управления фильтрацией. Достаточно кликнуть по нему и начать ввод: строка фильтра представляет собой динамическое поле выражений, которое сопоставляет данные в режиме реального времени прямо по мере набора текста.

Основы: поле и значение
Самая простая конструкция фильтра включает в себя имя поля и конкретное значение, по которому происходит сопоставление:
props.damage:20— карты, чей урон ровно20.type:gamecard— элементы, чей тип имеет сервисное имяgamecard.inside:Cards— элементы внутри рабочего пространства с сервисным именемCards.name:Fire— элемент с сервисным именем ровноFire. Сервисные имена уникальны, поэтому результат — не более одной карты.
Части :prop вы заполняли всю дорогу. Двоеточие — это просто «равно».
Работает и просто слово. Опустите поле и введите только Fire - строка фильтра воспримет его как обычный текстовый поиск по заголовку, и вернутся все карты, в заголовке которых есть «Fire». Синтаксис с двоеточием необходим в тех случаях, когда значение требуется жестко привязать к конкретному полю, в то время как одиночное слово служит для быстрого поиска по заголовкам
Сравнения: хороший баланс - это величина, а не равенство
Фильтры, проверяющие строгое равенство вида «урон равен 20», на практике используются довольно редко, поскольку задачи балансировки обычно оперируют понятиями «больше», «меньше» или «в заданном диапазоне». Специальный язык выражений позволяет легко закрывать такие задачи с помощью операторов сравнения, указываемых сразу после двоеточия:
props.damage:>20— урон больше 20 — завышенные карты.props.damage:<3— урон меньше 3 — те, что никогда не имеют значения.props.damage:>=10— не меньше 10.props.damage:<=30— не больше 30.props.damage:<>3— не равен 3 — всё, кроме выбросов.
А так как значения типизированы, сравниваются они как числа, а не как текст. 20 обрабатывается именно как двадцать, а не как последовательность символов «2» и «0
Диапазоны
«Между» умещается в одно выражение. Чтобы найти каждую карту с уроном от 10 до 30:
props.damage:[10..30]
Диапазон [start..end] включает обе границы. Один диапазон вместо двух сравнений.
Комбинируйте: AND, OR и скобки
Интересные вопросы комбинируют условия. Язык поддерживает AND, OR и скобки для группировки:
type:gamecard AND props.damage:>20
Карты с уроном выше 20. Добавьте проверку легендарности и найдите завышенную не-легендарную карту — случайный перекос силы:
type:gamecard AND props.damage:>20 AND props.isLegendary:false
Скобки делают составные вопросы читаемыми:
props.damage:<5 OR props.damage:>30 — «карты вне играбельной полосы», или как диапазон: NOT (props.damage:[10..30]).
Язык компактный и продуманный. Он не предназначен для описания произвольного текста, что является огромным плюсом, так как корректное выражение всегда дает исчерпывающее и точное описание выборки карт без малейшей двусмысленности.

Сохраните фильтр вместе с видом
Однократно введенный фильтр представляет собой разовый вопрос, в то время как сохраненный фильтр превращается в полноценный регулярный отчет. Вчерашние виды поскольку сохраненные виды легко интегрируют фильтры в свою раскладку, ваш запрос «Завышенные» станет постоянным именованным видом, доступным в один клик при каждой необходимости освежить баланс.
Рабочий процесс сократился до 3-х шагов:
- Введите
type:gamecard AND props.damage:>20. - Проверьте, что совпадения имеют смысл.
- Сохраните как вид
Завышенныеи двигайтесь дальше.
Фильтр автоматически выполняется по актуальным данным при каждом открытии вида, поэтому если в процессе правки баланса характеристика какой-либо карты превысит 20 единиц, она автоматически отобразится в списке «Завышенные» без необходимости ручного обновления.
Нужный набор — вычислен, а не прокручен
Пролистывание находит верх списка. Фильтры находят ответ — и продолжают его находить, пока данные под ними меняются. Сохранённый фильтр — это постоянный вопрос, который переспрашивается против сегодняшних карт при каждом взгляде.
Далее: экспорт
Теперь вы можете отслеживать коллекцию Карты как угодно. Однако игровой движок и смежные специалисты работают вне данного приложения: движку требуются данные в строго определенном формате, а команде - удобные таблицы. В следующем материале мы разберем процесс экспорта, в ходе которого коллекция преобразуется в форматы CSV и JSON, адаптированные под потребности получателей.
Автоматизируйте рутину - Скачайте IMS Creators, откройте ims.cr5.space/desktop, откройте свою коллекцию Карты и введите props.damage:>20 в строку фильтра — проблемные карты всплывут одной строкой.
Готовы? Экспортируйте баланс в CSV и JSON - следующий пост в этой серии.
FAQ
Где вводить выражение фильтра?
Выражение вводится в специальный элемент управления фильтром коллекции, расположенный в строке прямо над таблицей. Это поле для ввода выражений, а не выпадающее меню: по мере того как вы печатаете текст, таблица коллекций сужается на лету. В десктопном приложении данное поле находится рядом с кнопкой фильтрации.
Какие операторы я могу использовать?
Сравнения: : равно, :> больше, :< меньше, :>= не меньше, :<= не больше, :<> не равно. Диапазоны — [start..end], включая границы. Условия комбинируются через AND, OR и скобки.
По каким полям можно фильтровать?
По значениям полей типа (props.damage, props.cost), а также по свойствам уровня элемента вроде type, name и inside для местоположения. Фильтры name, type и inside ищут по сервисному имени — дополнительному имени, которое можно задать элементу, рабочему пространству или типу в настройках, отдельно от отображаемого заголовка. Сервисные имена уникальны, поэтому name:X вернёт не более одного результата. Математические сравнения работают по числовым полям; остальное ведёт себя как равенство и совпадение текста.
Я ввёл props.damage:>20, и ничего не изменилось. Что не так?
Проверьте, что имя поля ровно то, которое объявляет тип, если поле карты называется Damage, а вы ввели damage, путь не совпадёт. Язык выражений чувствителен к регистру в путях полей, а сравниваемые значения должны быть типизированы как числа, а не текст, чтобы сработали математические операторы.
Может ли вид помнить свой фильтр?
Да. Фильтр, который вы задали, становится частью сохранённой раскладки вида, точно как колонки и сортировка. Откройте вид и его рабочий набор восстановлен.
Работают ли фильтры на чём-то кроме коллекций?
Фильтры — это способ фокусировки наборов элементов в IMS Creators, поэтому единый язык выражений применяется и за пределами сетки коллекции.Тем не менее коллекция остается для них наиболее естественной средой, так как отфильтрованный результат сразу выводится в виде удобной редактируемой таблицы.
Чувствителен ли язык фильтров к регистру в ключевых словах?
Ключевые слова вроде AND, OR, NOT и операторы имеют фиксированное написание. Пути полей чувствительны к регистру в точном соответствии реальным полям типа. Достаточно один раз прочитать этот небольшой список правил, чтобы писать и читать выражения так же легко, как обычные предложения.