RPG Maker - критика статей
Мои посты по разработке на RPG Maker набирают примерно столько же минусов, сколько и плюсов. Приглашаю всех поделиться критикой моих публикаций. Хочу повысить качество контента!
Мои посты по разработке на RPG Maker набирают примерно столько же минусов, сколько и плюсов. Приглашаю всех поделиться критикой моих публикаций. Хочу повысить качество контента!
Это можно сделать с помощью команды Выполнить скрипт в событии. Ниже скрипт для MZ с комментариями.
// Для красоты вынес перевод строки времени в кол-во секунд в отдельную функцию.
function convertStringToSeconds(time) {
const array = time.split(":");
return (parseInt(array[0], 10) * 60 * 60) + (parseInt(array[1], 10) * 60) + parseInt(array[2], 10)
}
// Устанавливаем номер переменной, в которую хотим записать значение.
const varId = 1;
// Фиксируем текущее игровое время.
const currentSeconds = $gameSystem.playtime();
// Проверяем, есть ли сохранения.
if (!DataManager.isAnySavefileExists()) {
$gameVariables.setValue(varId, currentSeconds);
} else {
// Определяем индекс последнего сохранения.
const lastSaveFileId = DataManager.latestSavefileId();
// Получаем данные об этом сохранении (нам даже не нужно грузить всё сохранение).
const saveInfo = DataManager._globalInfo[lastSaveFileId];
// Вычисляем, сколько секунд игры было в последнем сохранении.
const lastSeconds = convertStringToSeconds(saveInfo.playtime);
// Вычисляем разницу.
const deltaSeconds = currentSeconds - lastSeconds;
// Записываем в переменную.
$gameVariables.setValue(varId, deltaSeconds);
}
Учтите, что так мы можем получить отрицательное число. К примеру, если поиграем час, запишем сохранение, а потом начнём новую игру, текущее игровое время будет меньше времени в последнем сохранении.
Версия для MV:
function convertStringToSeconds(time) { const array = time.split(":"); return (parseInt(array[0], 10) * 60 * 60) + (parseInt(array[1], 10) * 60) + parseInt(array[2], 10) }
const varId = 1; const currentSeconds = $gameSystem.playtime();
if (!DataManager.isAnySavefileExists()) { $gameVariables.setValue(varId, currentSeconds); }
else {
const lastSaveFileId = DataManager.latestSavefileId();
const saveInfo = DataManager.loadGlobalInfo()[lastSaveFileId];
const lastSeconds = convertStringToSeconds(saveInfo.playtime);
const deltaSeconds = currentSeconds - lastSeconds;
$gameVariables.setValue(varId, deltaSeconds);
}
Если нужны какие-то данные, которых нет в информации о сохранении, придётся грузить файл сохранения. Это можно сделать так:
// Устанавливаем номер переменной, в которую хотим записать значение.
const varId = 1;
// Проверяем, есть ли сохранения.
if (!DataManager.isAnySavefileExists()) {
$gameVariables.setValue(varId, 0);
} else {
// Определяем индекс последнего сохранения.
const lastSaveFileId = DataManager.latestSavefileId();
// Получаем имя файла этого сохранения.
const saveName = DataManager.makeSavename(lastSaveFileId);
// Загружаем данные из файла.
StorageManager.loadObject(saveName).then(contents => {
// Данные в contents. Обрабатываем их, как нужно.
return 0;
});
}
На смежные и схожие вопросы могу ответить в этом треде.
Я разработал плагин для языковых локализаций, здесь описание поподробнее. Постепенно буду добавлять в него функционал. Если вам нужна какая-то конкретная функция, напишите идею в теме плагина. Также обращу внимание, что в плагине есть функционал по экспорту языковых данных в Excel-таблицу и импорту из неё.
Важный совет. Если вы допускаете, что в вашей игре будет более одного языка (возможно, не сразу, но в будущем), лучше сразу разрабатывать с учётом локализаций. То есть нигде в редакторе не используйте захардкоженный текст, только теги из файлов локализации. Сначала можно прописать только один язык, потом по надобности добавлять другие. Тогда вам не придётся мучаться с экспортом текста из игры.
Тем не менее, иногда может потребоваться внедрить локализации в уже готовую игру.
Как-то раз я выполнил такой заказ для игры на RPG Maker MV. Вероятно, решение прокатит и на MZ. Если не сработает, напишите в этой теме.
Экспортировать текст из игры в JSON.
Сконвертировать JSON в XLSX и отправить получившуюся таблицу переводчику.
Дождаться готового перевода в XLSX формате.
Конвертировать новую таблицу в JSON и внедрить новый язык в проект.
Формат JSON поддерживает произвольную структуру данных. Объекты, массивы, любой уровень вложенности. При этом переводчик с JSON работать не хотел, нужно было ему обеспечить таблицу. Поэтому я решил для хранения данных локализации использовать один JSON-файл с плоским объектом. То есть был только один объект в корне файла, и каждое его свойство было текстовым. Никаких вложенных объектов.
Сначала нужно экспортировать текст из проекта. Я написал скрипт, который находит все диалоги (команда "Показать сообщение"), извлекает из них текст и сразу генерирует JSON-файл с нужной структурой. Вот он.
Этот скрипт написан на JS. Чтобы его исполнить, можно установить Node.js и запустить скрипт командой node export-localization.js
Можно также переписать скрипт на python, bash или другой язык и исполнить удобными вам инструментами. В принципе, скрипт несложный (даже примитивный).
В результате мы получим файл с таким содержимым:
{
"<тег>": "<реплика>"
}
Теперь забиваем в поисковик: "json to xlsx". Берём любой понравившийся сервис. Например, этот.
Скорее всего, мы получим таблицу с 2 строками и большим количеством столбцов. Переводчику будет неудобно работать с такой. Он ожидает 2 столбца: в одном теги, в другой - текст, который нужно перевести (переводчик либо будет редактировать этот столбец, либо добавит новый).
Если у вас получилось так, то просто транспонируйте получившуюся таблицу. Это можно сделать и в Esxcel, и в LibreOffice, и в Google Sheets. Не знаете, как? Поищите в интернете, это несложно (конкретная кнопка зависит от инструмента, поэтому тут не пишу, но она точно есть).
Отправляем таблицу переводчику, ждём перевода.
Теперь новый XLSX нужно конвертировать в JSON. Сначала транспонируем таблицу, чтобы у нас было 2 строки и множество столбцов.
Вбиваем в поисковик: "xlsx to json". Опять берём любой подходящий сервис, вроде этого. Конвертируем, получаем новый json-файл.
Переименовываем новый JSON-файл, как нам нужно ("en.json", "ru.json" и т.д.).
Вставляем в проект, добавляем язык в параметры плагина локализации (здесь конкретные действия зависят от используемого плагина).
Возможно, это не лучший способ: придумывал его в спешке на коленке. Если у вас есть альтернативные идеи, прошу написать в этом треде.
Самое ценное в этой статье - скрипт на экспорт текста, обратите на него внимание. У DK есть инструмент, который извлекает весь текст из игры, но он не генерирует JSON-файл с нужной структурой и уникальными тегами (очень важно, чтобы теги были уникальными).
Надеюсь, мне удалось достаточно раскрыть тему, остались ли вопросы?
Иногда при разработке механик или мини-игр хочется нестандартно обрабатывать нажатия на клавиши клавиатуры или мыши. Например, совершать игровое действие по нажатию на произвольную клавишу (стрельба, прыжок, лечение), управлять интерфейсом (открывать игровую карту, ещё какое-то меню) и много что ещё.
Существует несколько способов это делать.
Возможно, вам достаточно будет назначить стандартные действие на нестандартные клавиши. Например, сделать ходьбу по WASD. Для подобного достаточно расширить словарь Input.keyMapper, об этом подробнее в другом гайде.
Небольшая справка: событие - это сообщение, которое возникает при выполнении определённых условий. Например, если пользователь пошевелил мышь или тыкнул по клавише - в системе происходит соответствующее событие.
С помощью функции document.addEventListener(<событие, <функция>) можно назначить функции-обработчики на различные события.
Можно обрабатывать нажатие на клавишу:
document.addEventListener("keydown", keyDownHandler);
function keyDownHandler(event) {
if (Input.keyMapper[event.keyCode] == "ok") {
// Ваш код
}
};
"keydown" - это название события нажатия на клавишу клавиатуры. Внутри функции обработчика мы проверяем, не помечена ли нажатая клавиша, как "ok" в Input.keyMapper.
Однако мы можем действовать свободнее и сверять напрямую с числовым кодом клавиши:
document.addEventListener("keydown", keyDownHandler);
function keyDownHandler(event) {
// 70 - это код клавиши F
if (event.keyCode == 70) {
// Ваш код
}
};
Существуют различные события, которые можно обрабатывать в играх. Вот некоторые:
// Нажатие на клавишу клавиатуры:
document.addEventListener("keydown", keyDownHandler);
// Нажатие на клавишу мыши:
document.addEventListener("click", mouseClickHandler);
// Двойное нажатие на клавишу мыши:
document.addEventListener("dblclick", mouseDoubleClickHandler);
// Игрок пошевелил мышкой:
document.addEventListener("mousemove", keyDownHandler);
Давайте немного подробнее про использование мыши. Возможно, вам хочется различать клавиши мыши (да, можно тело функции-обработчика писать прямо при добавлении слушателя событию).
document.body.addEventListener("mousedown", event => {
if (event.button == 0) {
// Нажата левая кнопка
}
else if (event.button == 2) {
// Правая кнопка
}
else {
// Другая кнопка
}
}
В коде движка есть функции, которые обрабатывают нажатия на клавиши мыши (сюда же относится обработка сенсорного интерфейса).
Во-первых, в rmmz_core.js можно найти функции, которые делают примерно то, о чём я писал выше:
TouchInput._setupEventHandlers = function() {
const pf = { passive: false };
document.addEventListener("mousedown", this._onMouseDown.bind(this));
document.addEventListener("mousemove", this._onMouseMove.bind(this));
document.addEventListener("mouseup", this._onMouseUp.bind(this));
document.addEventListener("wheel", this._onWheel.bind(this), pf);
document.addEventListener("touchstart", this._onTouchStart.bind(this), pf);
document.addEventListener("touchmove", this._onTouchMove.bind(this), pf);
document.addEventListener("touchend", this._onTouchEnd.bind(this));
document.addEventListener("touchcancel", this._onTouchCancel.bind(this));
window.addEventListener("blur", this._onLostFocus.bind(this));
};
TouchInput._onMouseDown = function(event) {
if (event.button === 0) {
this._onLeftButtonDown(event);
} else if (event.button === 1) {
this._onMiddleButtonDown(event);
} else if (event.button === 2) {
this._onRightButtonDown(event);
}
};
Во вторых, мы можем расширить функционал функций, которые обрабатывают различные события. Для примера возьмём событие отмены с помощью сенсорного интерфейса (сюда же относится нажатие на правую клавишу мыши, если у вас мышь для праворуких):
const Origin_TouchInput_onCancel = TouchInput._onCancel;
TouchInput._onCancel = function(x, y) {
// Ваш код
Origin_TouchInput_onCancel.apply(this, [x, y])
};
Сначала вы выполняем код, после (что важно!) вызываем оригинальный метод. Можно ваш код выполнять после кода движка. Но обязательно вызывайте Origin_TouchInput_onCancel, иначе стандартная обработка нажатия движком не выполнится.
Ещё момент. Напрямую это не относится к тему, но может быть полезно.
$gameTemp.reserveCommonEvent(N);
С помощью этой функции можно вызвать общее событие. N - номер события в Базе данных проекта. К примеру, вы можете по нажатию на какую-то клавишу вызывать общее событие, где и описана ваша уникальная игровая логика.
Вот здесь демо-проект с реализацией такой идеи.
После запуска новой игры попробуйте нажать на F и ПКМ мыши.
Буду дополнять этот гайд по необходимости, пишите ваши предложения и замечания.
Добавить поддержку клавиш W, A, S, D клавиатуры легко в MV и MZ.
Для этого достаточно добавить в проект такой код:
(function () {
var replacedKeyMapper = {
87: 'up',
65: 'left',
83: 'down',
68: 'right',
69: 'pagedown',
};
for (code in replacedKeyMapper) {
Input.keyMapper[code] = replacedKeyMapper[code];
}
})();
Здесь мы также "перекинули" стандартный функционал клавиши W на E.
Вы можете скачать файл тут и добавить его в проект, как плагин.
У каждой клавиши есть числовой код. Представим, что в движке они помечаются маркерами. Например, стрелка вверх помечена маркером 'up'. Если игрок нажимает на эту стрелку, движок видит срабатывание маркера 'up' и обрабатывает это событие.
Маркеры задаются через словарь. Эта структура данных состоит из пар ключ-значение. Здесь ключ - числовой код клавиши, а значение - маркер. Все ключи уникальные, они не могут повторятся. Значения - могут.
Таким образом, несколько клавиш могут быть помечены одинаковым маркером. Это позволяет нам одновременно поддерживать движение как по стрелкам, так и по WASD.
При желании, вы можете добавлять свои пары ключ-значение в объект replacedKeyMapper из кода выше.
Вот код из файла движка rmmz_core.js:
Input.keyMapper = {
9: "tab", // tab
13: "ok", // enter
16: "shift", // shift
17: "control", // control
18: "control", // alt
27: "escape", // escape
32: "ok", // space
33: "pageup", // pageup
34: "pagedown", // pagedown
37: "left", // left arrow
38: "up", // up arrow
39: "right", // right arrow
40: "down", // down arrow
45: "escape", // insert
81: "pageup", // Q
87: "pagedown", // W
88: "escape", // X
90: "ok", // Z
96: "escape", // numpad 0
98: "down", // numpad 2
100: "left", // numpad 4
102: "right", // numpad 6
104: "up", // numpad 8
120: "debug" // F9
};
Здесь вы можете увидеть все доступные по умолчанию маркеры. Это полезно знать, если вы хотите добавить какой-то клавише маркер.
Есть аналогичный словарь для геймпада:
Input.gamepadMapper = {
0: "ok", // A
1: "cancel", // B
2: "shift", // X
3: "menu", // Y
4: "pageup", // LB
5: "pagedown", // RB
12: "up", // D-pad up
13: "down", // D-pad down
14: "left", // D-pad left
15: "right" // D-pad right
};
Можно также создать обработчик нажатий на клавиатуру и там смотреть на непосредственно код нажатой клавиши. Полезно, если у движка нет подходящего стандартного маркера. Но это уже для продвинутых пользователей ;) Пишите, если нужен гайд по этому.
Коды клавиш легко находятся в интернете. Можно смотреть их, к примеру, тут. Нужны DEC-коды (то есть десятичные).
Ещё важный совет. Не меняйте код движка, не редактируйте стандартные файлы. Мало того, что это запрещено правообладателем, это также неудобно и небезопасно. Что, если вы ошибётесь или захотите откатить изменения? JavaScript позволяет переопределять всё, что удобно. Поэтому для изменения кода движка используйте плагины.
Пишите ваши вопросы в этом треде, если остались.
Представь, что ты играешь с игрушкой на столе. Если ты её просто положишь, она будет стоять на месте. Но если ты её толкнешь, она начнет двигаться. Вот в Unity есть такой "волшебный" компонент, который помогает твоему персонажу или объектам двигаться, падать, скользить или отскакивать от других объектов, как настоящие вещи в реальной жизни. Этот компонент называется Rigidbody.
Если у твоей игрушки нет Rigidbody, то ты сам будешь отвечать за её движение, к примеру, будешь говорить ей, куда идти и как быстро.
Если у игрушки есть Rigidbody, то она будет "думать" о том, как двигаться сама, используя законы физики: гравитация будет тянуть её вниз, и она будет сталкиваться с другими объектами, отскакивать или скользить, если ты её толкнешь.
Гравитация: если ты поставишь объект на землю, он будет падать вниз, если у него есть Rigidbody.
Столкновения: если два объекта с Rigidbody сталкиваются, они будут реагировать друг на друга, как настоящие вещи (например, отскакивать).
Движение: ты можешь двигать объект с Rigidbody, используя силу, как если бы ты толкал или тянул его.
В общем, Rigidbody — это как волшебная сила, которая добавляет физику в игру и заставляет объекты вести себя, как настоящие вещи в реальной жизни.
В свое время мне довелось много зубрить в школе: от стихов, английских слов до некоторых теорем и формул. Не было толковых советов и интернета, чтобы получить разное/доступное объяснение материала или способы легкого запоминания (пригодились бы со стихами, которые мне были "по барабану"). Довольно часто сначала материал выучивался, а потом уже самостоятельно понимался. Поскольку меня зубрежка каждый раз доканывала, теперь я категорически против любых повторений без понимания смысла.
Итак, на повестке встал вопрос изучения счета. Я уже много времени об этом думал, отсюда много букв.
Изучение счета – процесс не новый для человечества и должен быть уже отточен и должна уже быть отработанная эффективная методология. В конце концов, должна уже быть игровая форма для детей. Всем известно, что изучение чего-то в процессе игры – это хорошо, это должно обеспечить интерес, легкость понимания и закрепления материала.
Посмотрел я некоторое количество игр для детей (компьютерных и настольных), которые призваны помочь научиться считать. Если с физическими играми дела обстоят лучше (причем для меня карты, домино, кубики/кости и т.п. эффективнее и интереснее специальных игр), то в компьютерных я увидел тупо школьные примеры с теми же числами, только с руками, внутри ягодок/яблок, с кошечками, зайками, пингвинами и т.п. То есть вместо того, чтобы как-то помочь уложить в голове ребенка суть счета, разработчики игр просто подкладывают детям веселые картинки и продолжают требовать от детей знания математики. По сути они работают с формой и тупо продолжают тему повторов и зубрежки.
Грубо говоря, были числа в клеточках тетради - стали те же числа внутри яблок. Писали ручкой - стали нажимать кнопки. Или тупо делают тренажеры, где считают ошибки, ставят таймеры - как-будто детям в школе оценок и контроля не хватает. Вообще не понятно, в чем методика обучения и где реальная помощь компьютерных технологий.
А упор должен быть, по-моему на понимании:
того, что одно вытекает из другого: того, что из разных чисел (или чего-то вообще) можно сложить и получить новое число (или что-то) + любое число, в свою очередь, можно разбить на разные другие числа. И вообще, числами можно манипулировать по-разному, а не строго по таблицам и примерам из учебника, и не надо много запоминать;
принципа равенства (очень поможет при решении уравнений).
Быстрота счета (в школе любят делать упор на запоминание, а не на понимание и логику) принципиально не важна. В конце концов есть калькулятор и компьютер и соревноваться с ними бессмысленно.
ПОНЯВ эти два момента, ребенок сможет преобразовывать выражения, решать уравнения, понимать формулы. Это не правильно, но я часто в школе решал многие задачи по физике чисто формально, просто находя неизвестное через ряд формул (многие даже до этого не доходят и мучаются с тройками/двойками).
Если понять эту базу, то вся школьная математика будет ИГРОЙ, чем она и является. Я четко помню, что мне нравилось упрощать всякие сложные выражения, когда в конце вся груда "превращалась" в единицу или какое-нибудь "ровное" число. Сокращения же числителя и знаменателя (в т.ч. в дробях) на какое-то число было равносильно "сгоранию" клеточек в тетрисе или всяких современных играх. Даже если это для кого-то неинтересная/скучная игра, все равно это ИГРА и каждое задание можно и нужно воспринимать как загадку, а не наказание.
И взрослые вместо того, чтобы дать ребенку БАЗУ и понимание ИГРЫ (некоторые правила), вместе сидят до ночи и что-то там решают - делают из ИГРЫ каторжный труд.
Часто ребенок не может считать и разбивать числа, но от него требуют понимание дробей, решение и понимание задач и т.п. И чем дальше, тем более замысловаты для понимания формы, в которые "преобразуются" простые вычисления. А БАЗА - это главное. В школе 10-11 лет и этого вполне всем хватит, чтобы и догнать и перегнать учебный план.
Что делал я при изучении чисел и счета:
Вначале мы играли с деталями типа лего и строили из разных комбинаций блоков числа.
Дело в том, что сами числа есть абстракция, которая используется для описания количества чего-либо. И понять детям эту абстракцию вначале не так и легко. И поэтому ребенку не понятно, что из двух яблок/котят не будет построена новая единица, которая в свою очередь может дальше использоваться как строительный материал. А вот блоки можно соединять и "разбивать"/ломать. И это очень хорошо откладывается в мозгу детей. Тем более, что еще недавно они сами из этих же блоков играли-строили всякие конструкции.
Это интересно, но я встречал детей-школьников, которые вроде и умеют считать, но как разбивать числа и представлять их в виде различных комбинаций блоков не умеют. Может они механически выучивают/запоминают счет (тут надо бы с ними еще поболтать на эту тему).
2. Я сделал игру и уже на экране мы вместе думали и находили разные способы, которыми можно составлять числа (в игре можно ткнуть на ячейку и таким образом "задать свое число"). Потом была игра, где надо было сравнивать два числа и находить разницу (можно выбирать любое число, которое хочется "дотянуть" до другого).
Задумка с игрой была в следующем: счет до 10 можно и с кубиками отработать, но с компьютерной игрой я немного отрываю ребенка от физического материала к абстрактному/не осязаемому понятию числа. Плюс с числами более 10 удобнее и быстрее уже на экране работать. Первый вариант игры был, конечно, гораздо "беднее": счет до 10, до 100 и сравнение двух чисел.
Пока вроде бы нормально "дружим" с математикой. Приходится только доходчиво объяснять понятия/слова, определения и сами тексты задач.
Самое главное правило для взрослых - никогда не заставляйте изучать новый материал долго (в т.ч. на "уставшую голову") и имейте терпение, чтобы не требовать сиюминутных результатов. Исключение – проявление ребенком интереса, когда он сам сидит и делает что-то "в охотку".
Если вы что-то изучали новое сами (изучение иностранного языка или новой сферы деятельности вполне может быть аналогией), то должны понимать, что для усвоения нового материала/терминологии (построения новых нейронных связей) нужно время. И каждому надо свое время (возраст, генетика и условия развития у каждого разные). Не обязательно даже заставлять изучать материал каждый день и по часу. Это все просто бред, который навязывают продажники от обучения. Достаточно поработать вдумчиво 5-10 минут и даже не каждый день. НИКУДА наработанные связи в мозгу и знания не денутся даже через долгий период времени. НЕ БОЙТЕСЬ. Мозг легко "поднимает" качественно уложенный ранее материал. А вот, если материал зубрился, то все вылетит в трубу в любом случае - 11 лет школьного обучения и остаточные знания этому пример.
Если ребенок понял суть вычислений и вы это видите, то не надо его мучать дополнительными заданиями, тренажерами и играми (включая мою игру, которая объективно не "залипательна"). У детей и так хватает материала тренироваться на школьных примерах. Лучше поиграть в игры на развитие логики – они интереснее. Плюс в магазине и на даче всегда можно "поиграть" с числами (вычислениями и измерениями).
В игре я остановился на счете и думаю дальше уже смысла нет что-то мудрить и мучать детей. Так, например, зубрить таблицу умножения я не вижу смыла (может квадратам еще имеет смысл уделить отдельное внимание, т.к. они помогают облегчать счет). Я просто объясняю, что, если не помнишь, то всегда можно разбить числа и найти необходимый результат, еще и разными способами. Я например, сам не помню сходу 8*7. Я вообще такие числа в жизни не использую, как и вычисления с трехзначными числами или умножения двухзначных чисел. Но, зная, что 7 * 7=49 и, добавив еще одну 7, я получу 56. Или через 8 * 8 - 8 = 56.
Также думаю, что не стоит превращать игру с числами в какую-нибудь игру, где вычисления являются необходимым этапом для какого-то шага или где имеются яркие анимационные персонажи – теряется фокус на самих числах. Поэтому и этап с рисунком я "зарезал". Ребенок, по-моему, должен понять прикол – что числа можно "гонять" туда и сюда и получать необходимый результат разными способами. Манипуляция с числами интересна сама по себе.
Сама игра не есть форма школьных задачек и правильных решений. Этого и в школе предостаточно. Также нет строгих ограничений по способам достижения результата (если перебрал, то можно вычесть), нет таймеров и рекордов. Многие этапы по сути одно и тоже, только в другой обложке.
Не забываем про крутую бесплатную игрушку, которую мало используют – круглые часы со стрелками. Там вообще много что можно выучить и уложить в голове, да еще динамика присутствует.
P.S. Я заметил, что люди по-разному представляют шкалу чисел у себя в голове при счете. У меня, например, числа выстроены по вертикали (может от школьных вычислений в столбик), а вот у моего знакомого числа выстроены по горизонтали. Причем считает он быстрее меня. А как у вас выстроена шкала в голове при счете?
Всем привет, вернулся с видосиками, надеюсь, кому-то данное видео поможет разобраться с локализацией!