浅语
RPG Maker MV中已经有很多大佬实现了各种华丽或美观的效果,其中有自制插件的,有使用集成公共插件(国外收费)的,当然我想实现的效果这些插件都能实现,这次就是仿照RPG Maker MV自带的AltMenuScreen插件做出整体的效果。
原始游戏菜单
这个原始菜单中主要是一个场景中分三个部分,即三个菜单。分别是:
- 命令选择菜单(Window_MenuCommand)作用是操作对应的按键命令
- 人物状态菜单(Window_MenuStatus)作用是查看队伍中人物的名称、等级及状态和操作选择对应人物执行对应操作如:物品使用、查看具体状态、选择人物进行装备、整队等,和命令菜单关联性强
- 金钱菜单(Window_Gold)作用是显示队伍中的资金
名称中的Window表示了每个菜单都是一个窗口,从图中可以看到带有白色边框和黑色透明背景的就是了,里面显示了对应的内容。
自带插件菜单
自带插件的菜单,除了UI部分显示外,操作并没有变化:
显示的内容还是那些内容,只不过位置进行了改变了,那在代码中是有什么变化呢?
首先是命令菜单和状态菜单中行列进行了变化
Window_MenuCommand.prototype.maxCols = function() {
return 4;
};
Window_MenuCommand.prototype.numVisibleRows = function() {
return 2;
};
Window_MenuStatus.prototype.maxCols = function() {
return 4;
};
Window_MenuStatus.prototype.numVisibleRows = function() {
return 1;
};
原来的命令菜单是8行1列,现在变成了2行4列,状态菜单行列数量发生了倒转;宽高部分就自然不用多说了。其他UI部分代码后面再说。
仿仙剑菜单
又到了大头部分了,是的就是仿仙剑的菜单,谁叫我也算半个仙剑迷呢!主打喜欢仙剑1及赵李的恋爱,李林自然也喜欢,但总有个先后嘛!加上第一次这个意识总是有的,所以就这样了。
原仙剑菜单
字体问题是挺难解决的,就将就着看吧!
MV中的仙剑菜单
可以看到整个菜单包括内容都大差不差了,之前的命令和金钱在踩坑中展示了,这个开发中有没有遇到困难呢?
也是有的,但没有困扰我太久因此就不叫踩坑专题了。
遇到了什么的问题呢?
- 渲染人物头像的位置 —— 最初实现了头像HP/MP,及状态的显示(纵向的),改成横向后各种适配问题接种而至
- 渲染字体及状态 —— 由于改变了横纵向,因此字体位置就偏离到很远的地方去了(原来的位置上)
- 原仙剑人物状态排列 —— 这单独拿出来确实是想了很久,直接倒序渲染,显示的顺序就不一致了,至少我感觉变扭
现在看到的就是需要呈现的效果了,看到窗口是因为要做布局调整和后面要做的显示选中的效果,现在默认效果还是原来的位置上的;后面人物状态也不会进行显示了(要是从战斗菜单中进入主菜单的状态显示可能会进行人物状态显示,包括头像状态的变化)。
代码展示
暂时不用的或原RPG Maker MV中自己的显示就不会放出了。大佬懂得都懂,萌新看下AltMenuScreen.js的内容就全都可以明白了!
//绘制人物
Window_MenuStatus.prototype.drawItem = function(index) {
this.drawItemImage(index);
this.drawItemStatus(index);
};
//绘制人物图像
Window_MenuStatus.prototype.drawItemImage = function(index) {
var actors = $gameParty.members();//获取人物列表
var actor=actors[index];//获取第几个人物
var rect = this.itemRect(index);//获取绘制的矩形区域
this.changePaintOpacity(actor.isBattleMember());//更改绘制不透明度
this.drawActorFace(actor, rect.x + 1, rect.y + 1, Window_MenuStatus._faceWidth, Window_MenuStatus._faceHeight);
this.changePaintOpacity(true);
};
//绘制演员头像
Window_MenuStatus.prototype.drawActorFace = function(actor, x, y, width, height) {
this.drawFace(actor.faceName(), actor.faceIndex(), x, y, width, height);
};
//绘制头像
Window_MenuStatus.prototype.drawFace = function(faceName, faceIndex, x, y, width, height) {
var actors=$gameParty.members();
var wx=0;
switch(actors.length){
case 1:
wx=616-154;
break;
case 2:
wx=616-154*2;
break;
default:
break;
}
//---------------------------
//分割线以上的区域是设置绘制的人物的位置,根据人物数量来,下面的是具体的位置及需要绘制的图片内容区域
//要是有大佬能有其他的好的修改方法或建议也请提出指正
width = width || Window_MenuStatus._faceWidth;
height = height || Window_MenuStatus._faceHeight;
var bitmap = ImageManager.loadFace(faceName);
var pw = Window_MenuStatus._faceWidth;
var ph = Window_MenuStatus._faceHeight;
var sw = Math.min(width, pw);
var sh = Math.min(height, ph);
var dx = Math.floor(x + Math.max(width - pw, 0) / 2);
var dy = Math.floor(y + Math.max(height - ph, 0) / 2);
var sx = faceIndex % 6 * pw + (pw - sw) / 2;
var sy = Math.floor(faceIndex / 6) * ph + (ph - sh) / 2;
this.contents.blt(bitmap, sx, sy, sw, sh, dx+wx-5, dy);
};
//绘制人物状态
Window_MenuStatus.prototype.drawItemStatus = function(index) {
var actor = $gameParty.members()[index];
var rect = this.itemRect(index);
var x = rect.x;
var y = rect.y+ rect.height / 2 - this.lineHeight() * 1.5
var width = rect.width;
this.drawActorSimpleStatus(actor, x, y+12, width);
};
//绘制演员简单状态
Window_MenuStatus.prototype.drawActorSimpleStatus = function(actor, x, y, width) {
var lineHeight = this.lineHeight();
var x2 = x;
var width2 = Math.min(200, width - this.textPadding());
//this.drawActorIcons(actor, x+71, y+14);// 人物状态图标
this.drawActorHp(actor, x2, y + lineHeight * 1-2, width2);
this.drawActorMp(actor, x2-5, y + lineHeight*1.45, width2);
};
//绘制演员HP
Window_MenuStatus.prototype.drawActorHp = function(actor, x, y, width) {
width = width || 180;
var color1 = this.textColor(10);//设置字体颜色值
var color2 = this.textColor(15);
this.drawCurrentAndMax(actor.hp, actor.mhp, x, y, width,color1, color2);
};
//绘制现在和最大值
Window_MenuStatus.prototype.drawCurrentAndMax = function(current, max, x, y,
width, color1, color2) {
var actors=$gameParty.members();
var wx=0;
switch(actors.length){
case 1:
wx=616-153;
break;
case 2:
wx=616-153*2;
break;
default:
break;
}
x=x+wx;
var labelWidth = this.textWidth('HP');
var valueWidth = this.textWidth('0000');
var slashWidth = this.textWidth('/');
var x1 = x + width - valueWidth;
var x2 = x1 - slashWidth;
var x3 = x2 - valueWidth;
this.contents.fontSize=14;//设置字体大小
if (x3 >= x + labelWidth) {
this.changeTextColor(color1);
this.contents.outlineColor=color1;
this.contents.outlineWidth = 0;
this.drawText(current, x3, y, valueWidth, 'right');
this.changeTextColor(color2);
this.contents.outlineColor=color2;
this.contents.outlineWidth = 0;
this.drawText('/', x2, y, slashWidth, 'center');
this.changeTextColor(color1);
this.contents.outlineColor=color1;//轮廓颜色
this.contents.outlineWidth = 0;//轮廓宽度
this.drawText(max, x1, y, valueWidth, 'left');
} else {
this.contents.outlineColor=color1;
this.contents.outlineWidth = 0;
this.changeTextColor(color1);
this.drawText(current, x1, y, valueWidth, 'left');
}
};
//绘制文本
Window_MenuStatus.prototype.drawText = function(text, x, y, maxWidth, align) {
this.contents.drawText(text, x, y, maxWidth, this.lineHeight(), align);
};
这里面更底层的实现由于没有进行修改因此就不用放出来了,大家若是对比了AltMenuScreen插件就会发现我这多了一些方法,我这里重写Window_MenuStatus 的父类Window_Base的方法方便进行更快速的定制化,后面若是要进行优化,可能会直接用更底部的子类吧! 也算是对面向对象的一个体现运用。
总结
JS的是个易学难精的语言,但在浏览器中魅力也是无穷的(虽然开发调整时一团糟,看不懂调用是什么鬼)。对于RPG Maker 来说,MV和MZ均使用了JS也算是一种流行的趋势了,网页端的量会激增。(不知道我写的这段狗屁不是的是为啥,就是想写)
通过浏览器不断地调试和查看MV中使用的脚本源码,学会了不少的东西,也领悟了不少的操作思路,比如截取某数量,某位置的图片的内容,然后显示出来,若是我自己写也会实现(需要想很久),但代码量复杂度也会上来了,这不一定是一个好结果(我挺懒的),不一定会进行对应的优化。
对于某些不懂或忘记的JS原生内容也通过这个重新学习掌握了起来,相信其他不少的语言也有类似的情况;从中学会来原型来创建操作对象,也是我学到的比较好的操作,毕竟之前重来没有见过(可能某些脚本中有,但是没有遇见过,阅读过),这次算是正式的见到并学习到了。
大家若是觉得好的要点赞哦!我这砖也算是抛出来了,大佬们要是有更好的优化代码、计算的方案不妨也引下玉能够讨论下!!!