Сайт Anivisual.net закрыт

Он продолжит функционировать в виде архива. Новые материалы добавлять нельзя.

Учим Kirikiri переносить текст в окне диалога

Учим Kirikiri переносить текст в окне диалога

Как вы знаете, японцам перенос на новую строку по пробелу по барабану, как следствие практически во всех японских ВНках на Kirikiri перенос осуществляется побуквенно.

Сегодня я расскажу, как перестать расставлять переносы руками в переводе и начать жить :)

И, прежде чем мы начнём, давайте поблагодарим товарища Nagato, написавшего первоначальный код этой процедуры.

Итак, что нам понадобится.
Прежде всего, это водка полный текст строки. Думаете, это не проблема? Увы, бывает всё не так просто, и в разных играх он может добываться разными методами. Сегодня речь пойдёт о том, как это сделано в игре Tsugihagi Make Peace — Pretending x Friendship.

Приступим.

Открываем в редакторе файл MainWindow.tjs (надеюсь, распаковка скриптов у вас вопросов не вызвала) и добавляем в самом начале, туда, где определяются переменные:

Код
  var textLine = void; // автоперенос: переменная для хранения полного текста текущего фрагмента
  var wrapNum = 0; // автоперенос: переменная для хранения количества пробелов
  var wrapPos = 0; // автоперенос: переменная для хранения позиции переноса
  var oldLine = void; // автоперенос: переменная для хранения предыдущей строки
  var splitLine = void; // автоперенос: переменная для хранения массива слов
  var canWrap = true; // автоперенос: признак возможности переноса строки (есть ли в строке пробелы и дефисы)
  var newPage = false; // автоперенос: признак перехода на новый экран при превышении количества строк, помещающихся на экране
  var mustReline = false; // автоперенос: признак необходимости переноса на новую строку


Отлично. Далее находим функцию, отвечающую за вывод имени персонажа. И пусть вас не смущает, что есть фрагменты, в которых имя не используется, — функция всё равно будет вызвана.
Код
dispname : function(elm)

И первой же строчкой (после открывающей фигурной скобки) пишем:
Код
textLine = getCurrentInfo().lineStr; // автоперенос: получаем строку, которая будет выводиться в окне диалога


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

Ах да! Полезный хинт! Хотите вывести окно со значением той или иной переменной? Нет проблем! Используйте для этого следующую функцию:
Код
System.inform(textLine);

где вместо textLine можно вписать значение любой переменной или текст.

С этим разобрались. Осталось немного.
Ищем функцию, отвечающую за вывод очередного символа:
Код
ch : function(elm)

и в ней после проверки на включённость режима пропуска
Код
if (skipNoDisp) { return 0;}

добавляем следующий код:

Код

/*
Wordwrapping code
Nagato ([email protected])
Last update: 2009/10/07
*/
/* Важные замечания от DOOMer'а:
- в elm.text хранится текущий выводящийся символ, не весь текст фрагмента, как можно было бы подумать
- переменная textLine присвоена в функции dispname
*/
  if (textLine.indexOf(" ") != -1 || textLine.indexOf("-") != -1) // если в строке нет пробелов и дефисов, то идём дальше
  {
  if (oldLine != textLine) // если эта строка отличается от уже обработанной, то переопределяем переменные
  {
  var tempStr = void; // автоперенос: переменная, которая будет содержать неразбитую исходную строку без символов экранирования
  oldLine = textLine; // переменная, хранящая в себе исходную строку
  wrapNum = 0; // количество мест переносов
  for (var i = 0; i < oldLine.length; i++) // проходим циклом по всем буквам строки
  {
  if (oldLine[i] != '\\') // тут удаляются все символы экранирования "\"
  tempStr = "%s%c" . sprintf(tempStr, oldLine[i]);
  }
  if (tempStr === void || (tempStr.indexOf(" ") == -1 && tempStr.indexOf("-") == -1)) // если строка пустая или пробелов с дефисами нет, то переносы не требуются
  canWrap = false; // переносы не нужны
  else
  {
  canWrap = true; // переносы возможны
  splitLine = tempStr.split("/ |-/"); // разбиваем строку по пробелам и дефисам, получаем массив слов
  }
  wrapPos = current.x;
  }

  if (canWrap) // если переносы возможны
  {
  if (elm.text == " " || elm.text == "-") // если текущий символ пробел или дефис
  {
  wrapNum++; // увеличиваем счётчик возможных переносов
  wrapPos = current.x;
  }
  if (wrapPos + current.lineLayer.font.getTextWidth(splitLine[wrapNum]) > current.relinexpos) // если позиция переноса + ширина оставшегося текста (с учётом действующего шрифта) выходит за правую границу окна сообщений
  {
  if (current.lineLayer.font.getTextWidth(splitLine[wrapNum]) <= current.relinexpos) // если ширина строки меньше отведённого под неё окна, то ничего не переносим
  {
  if (elm.text == " ") // если перенос по пробелу
  {
  elm.text = ""; // выпиливаем символ пробела - он не нужен
  mustReline = true; // устанавливаем признак необходимости перехода на новую строку
  }
  if (mustReline) // если установлен признак перехода на новую строку, то...
  {
  mustReline = false; // ...сбрасываем признак перехода на новую строку
  historyLayer.reline(); // ...переходим на новую строку в истории
  if (current.processReturn()) // ...переносим на новую строку в окне сообщений; если больше нет места для новых строк, то переходим на новый экран
  {
  newPage = true; // устанавливаем признак перехода на новый экран
  return showPageBreakAndClear(); // выводим новый экран
  }
  }
  if (elm.text == "-") // если перенос по дефису (например, в "ёк-макарёк"), то выпиливать символ дефиса не нужно, мало того перенос должен произойти после вывода дефиса, перед выводом следующего символа...
  mustReline = true; // ...поэтому устанавливаем признак необходимости перехода на новую строку только здесь, уже после кода перехода на новую строку
  }
  wrapPos = current.x;
  }
  }
  }

  if (newPage) // если произошёл переход на новый экран, то сбрасываем переменные
  {
  elm.text = ""; // сбрасываем значение текущего символа
  newPage = false; // сбрасываем признак перехода на новый экран
  }
}


Вот и всё.
Поздравляю. Мы это сделали. Возможно, у нас даже всё заработает.
По аналогичному алгоритму работает автоперенос в Ushinawareta Mirai o Motomete, и вроде нареканий нет.

Напоминаю! Не поленитесь заглянуть после всего этого колдунства в окно истории и посмотреть, как там всё отображается. Если как-то не очень, то лезем в Config.tjs и там в разделе HistoryLayer_config и глумимся над отступами и размерами символов.

Удачи всем коллегам по цеху в нашем нелёгком деле! :)

UPD 08-10-2017: Изменил код и комментарии, в частности:

  • Изменены названия некоторых переменных на более понятные, местами переписан код, почти полностью переписаны комментарии
  • Убран лишний пробел, добавлявшийся в процессе
  • Добавлен автоперенос по дефису в сложносоставных словах типа "ёк-макарёк"
  • Убрана поддержка вертикального письма - зачем оно нам? :)
18
Декабрь
6
3.4
4491
Добавлять комментарии могут только зарегистрированные пользователи.

Комментарии к записи: 6

avatar
#1 DOOMer
66
в 01:11 (07/Окт/2017)
1
Тут про ещё один вариант, где можно раздобыть полный текст фрагмента:
https://vk.com/wall198054534_8680
avatar
#2 DOOMer
66
в 19:31 (28/Окт/2017)
1
И ещё один вариант:
https://vk.com/wall198054534_8919
avatar
#3 DOOMer
66
в 00:03 (21/Янв/2018)
1
avatar
#4 DOOMer
66
в 21:59 (06/Фев/2018)
1
avatar
#5 DOOMer
66
в 22:56 (15/Фев/2018)
1
avatar
#6 DOOMer
66
в 23:36 (31/Мар/2018)
1
[Lilith] Mizugi no Shimobe-kun ~Shojo ni Osowareru Umi no Ie~
https://vk.com/wall198054534_10450

Блин, какая-то тут хрень с "неправильный код безопасности" :( Упарился коммент отправлять.