Всем привет!
С вами опять я (Mur), и мои очумелые ручки вновь не дают мне покоя. Ну и собственно по этой причине я спешу поделиться с вами своим новыми изысканиями.
Изыскивать мы сегодня будем как с помощью нескольких изменений, вывести на экран большие аватарки. На подобии «
Message busts» от Galv. Стой лишь разницей, что у него скрипт написан для
VX Ace, ну а мы соответственно будем изыскивать для
RPG Maker MV.
Для начала общая идея, как я себе это представляю:
В обычном редакторе текстовых диалогов, мы выбираем файл с группой аватаров, выбираем один из них и задаём текст сообщения. Всё как обычно.
Затем, находим место где выводится на экран аватарка. Изменяем скрипт на то что нам нужно, а именно выбрать картинку из папки img\bigfaces\ загрузить её вместо стандартной и вуаля, всё готово. На практике оказалось не всё так просто. Дело в том, что размеры окна (в данном случае с текстом сообщения) жестко задают границы и если попробовать загрузить другую (большую) картинку, то всё что попадает за пределы окна попросту обрезается.
Довольно неожиданно, но мысль не давала мне покоя. Ну хорошо, а что если нам сделать новое своё окошко, убрать к примеру все декорации, и загрузить в него нашу большую картинку. Отличная идея, как мне тогда казалось, но не совсем,… Да, новое большое окно у меня получилось вывести, но тут меня ждало разочарование. Дело в том, что как только новое окно перекрыло часть окна с сообщением, всё что находилось под ним попросту исчезло.
Мдяя,… как говорится, а праздник был близко. Ну что ж, мы не отчаиваемся и самое время перестать маяться дурью и наконец посмотреть, а как же эту проблему решает
Galv в своём скрипте? Всё оказалось просто. Скрипт который выводит обычную аватарку убирается, а вместо него с помощью Sprite спокойно отображается картинка поверх всех окошек. Алллилуйя! Вот оно!
Итак идея ясна, осталось только всё сделать.
Начнём мы как и в прошлый раз с описания нашего скрипта. На деталях я останавливаться уже не стану, скажу только что нам понадобится одна переменная в настройках, а именно сколько отступить тексту с левого края. Картинки у нас большие и если оставить настройки по умолчанию, то текст будет накладываться поверх персонажа, что не всегда хорошо читается. Впрочем кто-то может в этом узреть особенность дизайна
Начало нашего скрипта:
//=============================================================================
// BigAvatar.js
//=============================================================================
/*:
* @plugindesc Показывает большую аватарку
* @author Mur
*
* @param avatarWidth
* @desc padding for text
* @default 320
*
*/
(function() {
var parameters = PluginManager.parameters('BigAvatar');
var avatarWidth = Number(parameters['avatarWidth']);
Прочитаем в переменную avatarWidth ширину нашей большой картинки, или точнее сколько нам отступать.
var spr = new Sprite();
var bitmap;
var sprPosX;
Далее подготовим несколько переменных. spr это собственно наш спрайт с которым мы будем работать дальше. bitmap — сюда мы будем загружать нашу большую картинку и затем копировать в спрайт. А sprPosX это положение нашего спрайта на экране. Забегая немного вперёд скажу, что мне захотелось не просто вывести картинку на экран — БАМЦ! а что бы она плавно выезжала из-за края экрана. Но обо всём по порядку.
Window_Message.prototype.newLineX = function() {
return $gameMessage.faceName() === '' ? 0 : avatarWidth;
};
Здесь мы указываем наш отступ для текста, если аватар не указан, то отступ равен 0. В противном случает отступ для текста устанавливается из нашей переменной avatarWidth.
Window_Base.prototype.drawFace = function(faceName, faceIndex, x, y, width, height) {
Далее собственно то место, где рисуется аватарка персонажа, который говорит наш текст.
Проверяем, а задано ли название аватара, который нам нужно отобразить. Уж не знаю или моя ошибка или где-то кто-то что-то пропустил, но мы сюда иногда попадаем с пустым именем. В результате чего ошибка на экране и «поезд дальше никуда уже не идёт».
Если имя не задано, то просто ничего не делаем.
if (spr.bitmap) {
this.removeChild(spr);
}
Вот тут очень важный и интересный момент. Если у нас уже была загружена картинка (мы сюда попали не первый раз), то нужно убрать старый спрайт с экрана. Поскольку если этого не сделать на экране будет каша, все наши картинки начнут накладываться одна на другую.
bitmap = ImageManager.loadBitmap('img/bigfaces/' + faceName + '/', faceIndex+1, null, true);
Далее мы загружаем картинку. 'img/bigfaces/' — место где лежат наши большие аватарки. faceName это название файла с 8ю маленькими аватарками, который мы использовали при составлении текста. Но в данном случае это будет ещё одна папка, где будут лежать наши 8 больших картинок с номерами от 1 до 8. faceIndex+1 это собственно уже название нашей картинки которую мы хотим загрузить. +1 потому что счёт у них не с 1, а 0. и ".png" не нужно добавлять, так как система сама это сделает за нас.
Как видно из рисунка, «Тест» название нашего проекта «img\bigfaces» это где хранятся наши картинки «Package1» одноимённое название файла с аватарами и дальше собственно от 1 до 8 картинки.
Об этом чуть ниже.
bitmap.addLoadListener(function() {
Далее очень важный момент. Поскольку картинка не может загрузится мгновенно, нам нужно написать специальную нашу функцию которая будет вызвана после того, как картинка будет загружена. Если этого не сделать на экране мы в лучшем случае не получим ничего, а в худшем случае ошибку.
spr.bitmap = new Bitmap(bitmap.width, bitmap.height);
После того, как картинка загружена, нам нужно её скопировать в спрайт. Для этого создадим пустую картинку в спрайте точно такими же размерами, как у вновь загруженной картинки.
spr.bitmap.blt(bitmap, 0, 0, bitmap.width, bitmap.height, 0, 0);
Затем копируем загруженную картинку bitmap в спрайт spr. Первые два числа (0,0) это координаты в нашей картинке, например если мы хотим скопировать не всю, а только часть. Далее два числа (bitmap.width, bitmap.height) это собственно размер нашей копируемой картинки. Ну и последние два нуля это место куда мы хотим вставить нашу картинку в спрайт.
sprPosX = -(bitmap.width);
spr.x = sprPosX;
Здесь мы указываем начальную координату X для нашего спрайта. Как уже сказано выше, у меня есть задумка сделать так, что бы спрайт появлялся не сразу на экране, а выезжал из-за границы экрана. Поэтому тут отрицательное число равное ширине нашей загруженной картинки.
spr.y = -(bitmap.height - face.height);
Здесь задаётся вертикальное положение на экране, координата Y. Координата 0, как может показаться это не верхний левый угол экрана, а координата относительно нашего окна с текстом. Поэтому для того, что бы «выскочить» за его границы нам так же нужно задать отрицательное число. Для этого берём высоту нашей картинки, уменьшаем её на высоту обычной аватарки и зададим координату Y.
face.addChildToBack(spr);
Ну и теперь главный момент. Собственно надо «прикрепить» наш спрайт к окну с сообщением. Возможно есть способ лучше, и EvilCat меня поправит, но ничено лучше мне не пришло в голову. По идеи здесь должно быть написано было this.addChildToBack, но поскольку this у нас внутри нашей функции уже указывает на bitmap, то мы получим ошибку. Поэтому тут как бы такая вот странная конструкция, мы сохраняем в face наш стрый this на окошко, а затем просим систему добавить к нему спрайт.
Заканчивается загрузка картинки такой вот странной конструкцией. С радостью послушаю EvilCat для чего оно нужно, но скажу одно этот момент у меня очень много крови попил и заставил вчера просидеть аж почти до 4х утра. Пока не попался другой пример, с таким вот «хвостом». Уже отчаявшись, копирую этот кусочек и о чудо! Загрузка картинок заработала, иначе получались пустые файлы.
Закрываем нашу проверку пустого имени и собственно всей функции.
var _Window_Base_close = Window_Base.prototype.close;
Window_Base.prototype.close = function() {
_Window_Base_close.call(this);
this.removeChild(spr);
};
Этот кусочек не менее важен чем другие и отнял у меня тоже достаточно много времени. Дело в том, что когда мы загружаем картинки постепенно по мере открытия новых диалогов, всё красиво и прекрасно. Но если обратится к НПЦ ещё раз, на доли секунды на экране появляется старая (последняя) картинка, прежде чем успевает загрузится новая. Это не очень красиво, и логично было бы удалять наш спрайт с экрана, после закрытия окна с текстом.
Думаю комментарии тут излишни. Так же как и в первом уроке мы «дублируем» основную функцию системы Window_Base.prototype.close и добавляем после всех основных команд системы, команду удалить наш спрайт с экрана this.removeChild(spr).
var _Window_Base_update = Window_Base.prototype.update;
Window_Base.prototype.update = function() {
_Window_Base_update.call(this);
if (sprPosX <0) {
sprPosX += 5;
spr.x = sprPosX;
}
};
Ну и осталась ещё одна функция, которая будет двигать наш спрайт из-за экрана до тех пор пока координата X не будет равна 0.
Так же как и с предыдущей функцией, мы делаем «дубликат» системной функции Window_Base.prototype.update. После того как отработает система, мы проверяем координату X нашего спрайта, и если она меньше 0, то увеличиваем её на 5 точек. Никаких дополнительных действий для загрузки изображения не требуется, достаточно обновить координату спрайта spr.x и оно сместиться на новое место автоматически.
На этом всё, закрываем основную функцию нашего плагина и отправляемся тестировать .
Стоит обратить внимание, что получившийся у нас плагин это всего лишь маленькая не законченная часть. Вывод аватара используется в совершенно неожиданных местах. И если например при отображении результатов битвы или списка персонажей в меню, это ещё не так фатально выглядит:
то при выборе, например экипировки:
уже выглядит не столь оптимистично.
Понятно, что все эти нюансы ещё стоит учесть. Но минимальную задачу мы на сегодня выполнили. Разобрались как устроен вывод аватарок. Как загрузить свою картинку в спрайт и вывести на экран. И собственно как сделать минимальную анимацию (выезд картинки из-за края экрана).
На этом всё. Всем спасибо за внимание и до новых встреч. В следующий раз думаю мы ещё что-нибудь интересное расковыряем
Удачи!