Всем доброй ночи.

Изначально урок писался для светлой, но теперь думаю буду публиковать новые уроки сначала здесь.

Сегодня мой день был потрачен не зря, ибо мне удалось написать свой первый небольшой плагин для нового RPG Maker MV. Сразу скажу, что ни разу не профессионал, занимаюсь в свободное от кухни время и только-только разбираюсь во всём это безобразии

Хотя есть некоторый опыт скриптоковыряния VX Ace, что конечно же мне помог и тут. В любом случае спешу поделится своими изысканиями и надеюсь они будут ещё полезны кому-нибудь.

Начать мне хотелось бы с редактора. Как вы уже, наверное, заметили, в отличии от VX Ace в MV своего редактора нет. Скрипты лежат в открытом виде и можете спокойно их редактировать в любом текстовом редакторе. В одном из видеоуроков человек порекомендовал brackets. Опыта у меня не много в подобного рода редакторах, но мне понравился. Особенно очень удобно, когда начинаешь что-то писать, а тебе бац и сразу подсказки. Мелочь, а приятно. При желании можно выбрать удобную цветовую тему. Так что можете тоже попробовать совершенно бесплатно.

Для начала о том, что мы будем сегодня делать. Этот простой плагин рисует на экране небольшое окошко с иконкой и цифрой. Данные берутся из переменных (Variables) RPG Maker. А с помощью ключа (switch) можно включить или спрятать отображение данного окна. Теперь для чего? Например, NPC даёт герою задание, что нужно собрать 20 шишек. Понятно, что задание не сильно увеселительное, но можно игроку немного скрасить жизнь. Отображая, например, цифрами, сколько ему ещё осталось мучится. Выглядит это примерно так:

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

Итак, создадим новый файл ItemOnMap.js в папке нашего проекта, а именно js\plugins. Этого уже достаточно, чтобы он уже появился в списке доступных плагинов, однако всё же стоит добавить его описание:

//=============================================================================
// ItemOnMap.js
//=============================================================================

Здесь название нашего файла. Не могу сказать, что это нужно наверняка, но во всех плагинах под MV примерно такое-же оформление. Возможно система поэтому определяет, что это именно наш плагин, а ни чей-нибудь ещё.

/*:

Открываем комментарий и описываем различные параметры:

* @plugindesc отображает на экране количество предметов в ячейке
* @author Mur
*

Далее указывается описание плагина (@plugindesc) и собственно кто автор (@author)

* @param enableSwitchId
* @desc показать/скрыть (номер ключа)
* @default 1
*

Затем следуют перечисления параметров нашего плагина. Тут надо быть очень внимательными, ибо эти название затем используются в скрипте. И если что-то напутать, ничего не получится. Один параметр состоит из трёх частей, собственно его названия @param (на английском языке и честно не знаю, можно ли писать на русском), описание данного параметра @desc (не знаю почему, но описание на русском не отображается) и значение по умолчанию @default. Данный параметр указывает какой ключ (switch) будет разрешать или запрещать отображение данного окошка.

* @param itemVarId
* @desc Иконка предмета (номер переменной)
* @default 1
*

Здесь указывает номер переменной (Variable) в которой хранится номер предмета, который должен собирать наш главный герой. Иконка этого предмета и отображается в нашем окошке.

* @param countVarId
* @desc Количество предметов (номер переменной)
* @default 2

Ну и завершает это всё последний параметр, который так же указывает на номер переменной (Variable) в которой хранится количество собранных предметов.

*/

Закрываем комментарий и далее следует уже наш скрипт самого плагина.

(function() {

Такой строчкой начинаются почти все плагины, которая собственно и сообщает системе, что сейчас мы будет творить!

var parameters = PluginManager.parameters('ItemOnMap');

Для начала нам нужно добраться до настроек нашего плагина. Не знаю, как это всё связано, но обратите внимание, что наш файл, первый кусочек и здесь название плагина везде одинаковое, в данном случае это «ItemOnMap».

var enableSwitchId = Number(parameters['enableSwitchId']);
var itemVarId = Number(parameters['itemVarId']);
var countVarId = Number(parameters['countVarId']);

Здесь мы получаем значение наших параметров. Честно не знаю, зачем тут написано Number, но в других скриптах сделано так же, так что видимо так надо.

А так это выглядит, когда мы подключаем наш плагин:

//Обновление всех окон
var _Scene_Map_createAllWindows = Scene_Map.prototype.createAllWindows;
Scene_Map.prototype.createAllWindows = function() {
	_Scene_Map_createAllWindows.call(this);
	this._itemOnMap = new ItemOnMap(10,10, 120, 60);
	this.addWindow(this._itemOnMap);
};

Вот тут очень важный и сложный момент. Для того, чтобы наше окно постоянно отображалось. Нам нужно втиснутся в основную функцию создания всех окон (createAllWindows). Если вы писали скрипты (или хотя бы пытались что-то изменить в чужих, как я, например) под VX Ace, то наверняка заметили схожий приём. Когда главная функция системы подменялась на нашу, а потом вызывалась внутри с такими же параметрами. Ну не суть важно, я думаю если кому интересно он спросит у знатоков, а тут просто для пояснения.

Сначала создаём «копию» основной функции системы:

var _Scene_Map_createAllWindows = Scene_Map.prototype.createAllWindows;

Затем заменяем её уже своей функцией:

Scene_Map.prototype.createAllWindows = function() {

внутри которой вызываем настоящую, что бы ничего не поломалось:

	_Scene_Map_createAllWindows.call(this);

И затем уже добавляем создание нашего окошка:

	this._itemOnMap = new ItemOnMap(10,10, 120, 60);

Первые два числа — это координаты где на экране будет наше окно, а два другие его соответственно ширина и высота.

	this.addWindow(this._itemOnMap);
}

Затем это окно добавляется в систему и далее собственно уже функции нашего окна:

function ItemOnMap() {
	this.initialize.apply(this, arguments);
}

Честно скажу, назначение этого кусочка мне до конца не ясно. Однако сразу скажу, что без него не работает и кроме того опять же очень важно название — «ItemOnMap»!! Оно идёт везде одинаковое, ошибётесь на 1 букву будут ошибки.

ItemOnMap.prototype = Object.create(Window_Base.prototype);
ItemOnMap.prototype.constructor = ItemOnMap;

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

ItemOnMap.prototype.standardPadding = function() {
	return 0;
};

Например, вот, по умолчанию отступ у всех окон 18px. Для того что бы наш текст и иконка были видны его стоит задать равным 0.

ItemOnMap.prototype.initialize = function(x, y, width, height) {
Window_Base.prototype.initialize.call(this, x, y, width, height);
	this._id = 1;
};

Далее, как я понимаю идёт инициализация нашего окна, с такими же параметрами как у главного.

Ну и самое интересное. Окно появилось, и остаётся только вывести в него информацию:

ItemOnMap.prototype.update = function() {

Для этого необходимо в функции update написать то, что мы хотим вывести в нашем окне.

	this.contents.clear();

Для начала его надо очистить, если этого не сделать всё будет накладываться друг на дружку и в конце концов будет выглядеть ужасно.

	if ($gameSwitches.value(enableSwitchId)) {

Далее мы проверяем, разрешено ли показывать наше окно, если да, то:

		this.show();

Покажем окно

		this.resetTextColor();

Установим настройки (цвет, размер) текста по умолчанию

		var itemId = $gameVariables.value(itemVarId);

Берём номер предмета, который нужно отобразить:

		if (itemId == 0) {
			itemId = 1;
		}

Проверяем, что бы он не был равен 0, иначе будет ошибка.

		this.drawIcon($dataItems[itemId].iconIndex, 15, 15);

Рисуем нашу иконку. $dataItems[itemId].iconIndex номер иконки предмета, и две последующие цифры это координаты x,y внутри нашего окна.

		this.drawTextEx(":" + $gameVariables.value(countVarId), 52, 15);

Далее выводим наше число из переменной, и опять же два последующих числа это координаты x,y внутри нашего окна, но только уже для вывода текста.

	} else {

Если же показывать окно нельзя, то

		this.hide();

Скроем его и закончим данную функцию.

	}
}

Собственно, на этом всё, остаётся только не забыть закончить главную функцию плагина:

})();

Как видите ничего сложного почти нет. Хотя по правде говоря было очень непросто сходу разобраться со всем этим, и, если бы не потраченные дни предварительного разбирания и ковыряния VX Ace, мне бы не удалось это всё сделать так «быстро». Однако надо сказать огромное спасибо авторам, что так же как в VX Ace, RMMV название функций и переменных очень схожи, что конечно хоть и не сильно, но всё же упрощает написание плагинов под RMMV.

Если вдруг будут какие-то вопросы, постараюсь в меру своих сил ответить.

p.s. огромное спасибо всем, кто мне помогал и помогает разбираться с премудростями RPG Maker, как здесь на форуме, так и в нашем горячо любимом чатике. Как видите мои глупые вопросы наконец вылились во что-то если не серьёзное, так во что-то не плохое это точно.

 Небольшое дополнение:

Если необходимо, что бы окно так же отображалось во время боя, то для этого достаточно перед строчкой «function ItemOnMap() {»

Добавить, по аналогии с «_Scene_Map_createAllWindows»:

//Обновление окон во время битвы
var _Scene_Battle_createAllWindows = Scene_Battle.prototype.createAllWindows;
Scene_Battle.prototype.createAllWindows = function() {
	_Scene_Battle_createAllWindows.call(this);
	this._itemOnMap = new ItemOnMap(10,10, 120, 60);
	this.addWindow(this._itemOnMap);
};

Правда появятся небольшие проблемы:

Наше окошко будет перекрывать системные сообщения о битве. Поэтому нужно указать где-то другое место.

 Ссылки по теме: