Skip to content

Repository files navigation

True Joint Tile Maker

Редактор пиксельной графики и карт локаций на PascalABC.NET.

Два режима над одним окном:

  • тайл — рисование пиксельной картинки;
  • карта — локация игры Andors-Love в её формате data/maps/*.map.

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

Требования

  • Windows с .NET Framework 4.x
  • PascalABC.NET для сборки из исходников

Сборка и запуск

Откройте TJTM.pas в среде PascalABC.NET и нажмите F9. Модули рядом компилируются автоматически.

pabcnetcclear.exe TJTM.pas

Рядом с исполняемым файлом должны находиться:

Путь Назначение
Config.txt настройки; создаётся автоматически, если файла нет
Resources/ палитра по умолчанию
Картинки/ стартовое изображение debug.png

Отсутствие любого из них не мешает запуску: палитра заменяется радужной заготовкой, а вместо стартового изображения создаётся пустой тайл размера из настроек.

Структура

Файл Содержимое
TJTM.pas состояние документов, отрисовка, ввод, экраны интерфейса
TJTMColor.pas преобразования HSV и RGB, смешивание с прозрачностью, растровые буферы
TJTMConfig.pas чтение и запись Config.txt
TJTMMap.pas разбор, запись и проверка карт локаций

Ввод

Обработчики мыши выполняются в потоке интерфейса, параллельно основному циклу, поэтому клик приходит в произвольный момент — в том числе посреди отрисовки кадра. Раньше каждый экран в конце кадра просто сбрасывал признак нажатия, и клик, пришедший после того, как его кнопка уже нарисована, не доставался никому: чем дольше перерисовка, тем чаще кнопка «не срабатывала».

Теперь кадр начинается со снимка (BeginFrameInput): накопленное нажатие снимается под замком целиком — и признак, и координаты, — и весь кадр работает с этим снимком, а живой признак снова копит то, что приходит. Клик, пришедший посреди кадра, достаётся следующему. Кнопка, сработав, забирает снимок себе, поэтому одно нажатие приводит в действие ровно одну кнопку.

Замерено на экране справки: до правки из 16 долетевших нажатий кнопки ловили 14, при частых нажатиях — 23 из 25; после правки — 17 из 17, 25 из 25 и 21 из 21 на итоговой сборке.

Удерживаемые клавиши лежат в наборе (KeyHeld, карта по коду), а не в отдельных переменных на Shift, Ctrl и Alt: спросить IsKeyPressed можно про любую клавишу, и добавление новой не требует ни новой переменной, ни правки двух обработчиков. Именно карта по коду, а не список нажатых: список пришлось бы искать перебором и дописывать при каждом повторе автоповтора — система шлёт нажатие снова и снова, пока клавишу держат, — заново выделяя память. Уход фокуса гасит весь набор: отпускание после переключения окна придёт уже не нам, и снять клавишу было бы нечем.

Управление

Правило кнопок мыши одинаково во всей программе:

  • левая применяет: рисует, заливает, кладёт цвет, ставит объект;
  • правая берёт: пипетка цвета или местности, убирает объект;
  • ролик как кнопка: протяжка двигает изображение, щелчок без протяжки меняет местами рабочие цвета;
  • вращение ролика меняет масштаб вокруг курсора.

Обзорная панель

Внизу панели справа документ показан целиком, жёлтая рамка отмечает видимую на холсте часть. Протяжка средней кнопкой по обзору двигает холст, а панорама холста двигает рамку: обзор и редактор всегда смотрят на одно место документа, только в разных масштабах.

Инструменты режима тайла

Карандаш, ластик, заливка, пипетка, линия, прямоугольник, овал, дизеринг, выделение.

Фигуры строятся протяжкой с предпросмотром. Ctrl во время протяжки делает фигуру заполненной, Shift приводит её к квадрату или кругу.

Выделение: рамка бежит «муравьями» — пунктиром со сдвигом фазы, — поэтому её видно и на пёстром тайле. Протяните рамку, чтобы скопировать область в буфер; щелчок без протяжки вставляет буфер; протяжка за выделенную область копирует её на новое место.

Инструменты режима карты

Местность, заливка, прямоугольник, объект, выделение.

Строка объекта правится по средней кнопке настоящим полем ввода: работают выделение, Ctrl+C и Ctrl+V. Строки вроде exit 46 8 forest 2 8 key=rusty quest=ink:2 длинные, и их переносят между локациями целиком, а не набирают заново.

Инструмент объектов: левая кнопка ставит объект выбранного вида или перетаскивает уже стоящий, правая убирает, средняя открывает правку строки.

Клавиатура

Клавиша Действие
Escape главное меню
Tab переключить режим тайла и карты
N / L / S создать, загрузить, сохранить
A сохранить выделение или буфер отдельным файлом
Z / Y отменить и повторить
V вставить буфер в позицию курсора
X поменять местами первый и второй цвета
P точный выбор цвета по каналам ARGB
G / C сетка, шахматка под прозрачными пикселями
B бесшовный предпросмотр
W заворот рисования через край тайла
F / D вертикальная и горизонтальная оси симметрии
E режим замены вместо смешивания
I индексная палитра
T набор тайлов Andors-Love
R / Delete случайные цвета, очистить тайл
19 выбор инструмента
+ масштаб
стрелки сдвиг изображения
Пробел вернуть изображение в центр
Alt над холстом временно включает пипетку
H справка и благодарности

Наборы тайлов

Пункт меню Наборы тайлов (или клавиша T) показывает четыре набора:

Набор Что в нём Откуда состав
Основные 17 слотов игры: пол, стена, вода, герой… список в редакторе
Жители по картинке на жителя: npc_elder.png файлы в папке
Враги по картинке на врага: mob_wolf.png файлы в папке
Значки картинки на кнопках инструментов список в редакторе
  • правая кнопка открывает тайл в редакторе;
  • левая записывает на его место текущий тайл, спросив подтверждение, если файл уже есть.

Папка набора задаётся ключом TilesFolder или прямо на экране; у значков своя — IconsFolder. Открытый из набора тайл становится текущим файлом, поэтому S сохраняет его обратно туда же.

Имена основных слотов повторяют src/gfx/tiles.cpp игры — это контракт между двумя проектами, такой же, как коды клеток в картах: слот, названный иначе, игра просто не найдёт.

А вот состав жителей и врагов редактор не хранит. Он читает саму папку: что в ней лежит с приставкой npc_ или mob_, то и показывает. Список существ живёт в игре, и вторая его копия здесь рано или поздно от неё отстала бы. Завели нового врага в игре, её скрипт создал ему заготовку — и он появился в редакторе сам.

Пустое место — не ошибка: игра рисует такой тайл прежним способом, заливкой и знаком шрифта, поэтому набор можно делать по одному тайлу и в любом порядке. Первые семь основных слотов — местность, она рисуется непрозрачной; остальные десять — объекты, у них фон прозрачный.

Значки кнопок

Кнопки инструментов рисуются картинками из Resources/Icons — по файлу на инструмент, tool_pen.png и так далее. Они правятся тем же редактором: набор Значки, правая кнопка открывает, левая записывает. Изменённый значок появляется на кнопке сразу, как только вы вышли из экрана наборов.

Пока файла нет, кнопка выглядит подписью, как раньше. Убрать все значки можно, очистив ключ IconsFolder.

Из карты прямо в тайл

Двойной щелчок по клетке карты открывает тайл, которым она нарисована:

  • под курсором житель — откроется его собственный тайл, npc_elder.png;
  • точка появления врага — его, mob_rat.png;
  • другой объект — тайл его вида;
  • пусто — тайл самой местности.

Если файла ещё нет, редактор предложит завести его сразу с нужным именем, и Сохранить положит тайл туда, куда смотрит игра.

Второй щелчок пары обычного дела инструмента не делает: иначе двойной щелчок инструментом объектов ставил бы два объекта разом.

Индексная палитра

Клавиша I связывает пиксели тайла с ячейками палитры того же цвета. После этого правка ячейки левой кнопкой перекрашивает все связанные с ней пиксели: набор тайлов перекрашивается сменой палитры, а не перерисовкой.

Включённый режим виден по рамке палитры цветом выделения, а ячейка, из которой взят первый цвет, обведена ею же. Правка ячейки и перекраска тайла отменяются вместе, одним Z.

Привязка — подсказка, а не источник истины: цвет пикселя по-прежнему хранится в самом тайле, и перед перекраской сверяется с прежним цветом ячейки. Пиксель, который с тех пор перекрасили иначе, остаётся на месте. Поэтому устаревшая привязка не может испортить картинку — она лишь не сработает.

Пиксель, не совпавший ни с одной ячейкой, остаётся свободным. Чтобы связать весь тайл, сведите его к цветам палитры в операциях с цветом: после этого палитра управляет каждым пикселем. Цвет, набранный ползунками, связи не имеет, пока не совпадёт с какой-нибудь ячейкой; пипетка берёт цвет вместе с его связью.

Бесшовные тайлы

B включает бесшовный предпросмотр: холст рисуется повторяющимся тайлом, соседние копии слегка притушены, сам тайл обведён рамкой. Швы видно прямо во время работы.

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

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

Картинка собирается ближайшим соседом: пиксель-арт нельзя сглаживать, иначе при увеличении выйдет мыло вместо пикселей.

Карты локаций

Режим карты работает с форматом Andors-Love напрямую, без промежуточных файлов. Разбор проверен на всех 50 картах игры: чтение и обратная запись дают файл байт в байт.

name Дрейфующий луг
size 48 18
grid
################################################
#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#
... ровно 18 строк ровно по 48 символов ...
objects
sign 24 10 Облака идут в одну сторону, тени от них — в другую.
exit 24 15 node3 24 5
end

Сетка хранит только геометрию:

Символ Клетка Проходима
. пол да
, трава да
= дорога да
: стоячая вода да
# стена нет
~ вода нет
T дерево нет

Всё остальное описано объектами: npc, item, exit, spawn, chest, note, bed, sign. Редактор разбирает у объекта только вид и координаты, а хвост строки хранит как есть и пишет обратно без изменений. Поэтому условия перехода, содержимое сундуков и тексты табличек не теряются, даже если редактор не умеет их показывать; править хвост можно вручную средней кнопкой по объекту.

Пункт «Свойства и проверка локации» повторяет проверки tools/gen_maps.py из игры: объекты должны стоять на проходимых клетках, а проходимая часть локации — быть связной.

После правки карт в игре:

python3 tools/gen_maps.py && make embed && make

Настройки

Все параметры хранятся в Config.txt в кодировке UTF-8, по строке на параметр в виде ключ = значение. Порядок строк значения не имеет, неизвестные ключи игнорируются, а испорченный или отсутствующий файл не мешает запуску. Файл можно править вручную или через пункт Настройки в меню.

Ключ Значение
ShowHelpOnStart показывать справку при запуске
ShowMenuOnStart показывать главное меню при запуске
DefaultTileWidth, DefaultTileHeight размер нового тайла, 4..512
ShowGrid сетка между пикселями
ShowChecker шахматка под полупрозрачными пикселями
ShowSeamless бесшовный предпросмотр
StartInMapMode запускаться сразу в режиме карты
DefaultMapWidth, DefaultMapHeight размер новой карты, 4..256
MapsFolder папка карт локаций для диалогов
TilesFolder папка набора тайлов, например data/tiles игры
IconsFolder папка значков кнопок; пусто — кнопки с подписями
StartupImage картинка, открываемая при запуске; пусто — не открывать
AutoLoadLastFile открывать последний файл вместо стартовой картинки
PaletteFile палитра 8×8, загружаемая при запуске
LastFile, LastMapFile, LastFolder заполняются программой

При запуске программа пробует открыть стартовое изображение, и размер тайла берётся из него. Размер из настроек нужен только тогда, когда открыть картинку не удалось: тогда создаётся пустой тайл заданного размера.

Лицензия

GNU General Public License версии 3, см. файл LICENSE.

Благодарности

Автор — dpsmpx, vk.com/dpsmpx.

Команде PascalABC.NET за язык, среду разработки и библиотеку GraphABC, на которой построен весь интерфейс редактора.

Игре Andors-Love за формат карт, ради которого сделан режим локаций.

Группе vk.com/programmer_ne_lamer за сообщество и поддержку.

Активно использовался Claude Code Ultracode

About

My own pixelart editor

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages