RPG Maker MV 简单角色菜单状态栏效果

文章介绍了如何在RPGMakerMV中仿制仙剑风格的菜单,包括原始游戏菜单、自带插件菜单和仿仙剑菜单的实现,重点讨论了代码变更,特别是窗口布局、人物状态和头像的绘制。作者通过调整窗口行列数、处理人物头像和状态的渲染问题,成功实现了仿仙剑的菜单效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

浅语

RPG Maker MV中已经有很多大佬实现了各种华丽或美观的效果,其中有自制插件的,有使用集成公共插件(国外收费)的,当然我想实现的效果这些插件都能实现,这次就是仿照RPG Maker MV自带的AltMenuScreen插件做出整体的效果。

原始游戏菜单

原始菜单
这个原始菜单中主要是一个场景中分三个部分,即三个菜单。分别是:

  • 命令选择菜单(Window_MenuCommand)作用是操作对应的按键命令
  • 人物状态菜单(Window_MenuStatus)作用是查看队伍中人物的名称、等级及状态和操作选择对应人物执行对应操作如:物品使用、查看具体状态、选择人物进行装备、整队等,和命令菜单关联性强
  • 金钱菜单(Window_Gold)作用是显示队伍中的资金

名称中的Window表示了每个菜单都是一个窗口,从图中可以看到带有白色边框和黑色透明背景的就是了,里面显示了对应的内容。

自带插件菜单

自带插件的菜单,除了UI部分显示外,操作并没有变化:
AltMenuScreen

显示的内容还是那些内容,只不过位置进行了改变了,那在代码中是有什么变化呢?
首先是命令菜单和状态菜单中行列进行了变化

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中的仙剑菜单

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原生内容也通过这个重新学习掌握了起来,相信其他不少的语言也有类似的情况;从中学会来原型来创建操作对象,也是我学到的比较好的操作,毕竟之前重来没有见过(可能某些脚本中有,但是没有遇见过,阅读过),这次算是正式的见到并学习到了。

大家若是觉得好的要点赞哦!我这砖也算是抛出来了,大佬们要是有更好的优化代码、计算的方案不妨也引下玉能够讨论下!!!

【实例教程1】怎样编写一个插件? 1. 插件的注释与定义参数 2. 读取插件参数 3. 插件指令的实现 【实例教程2】制作一个启动画面 1. 从哪里开始? 2. 创建启动画面的场景类 【实例教程3】玩转菜单初级篇 1. 给各个菜单界面添加背景 2. 让背景滚动起来 3. 在主菜单界面增加自定义菜单名 4. 在主菜单界面移除菜单命令 5. 在主菜单界面增加一个自定义窗口 【实例教程4】玩转标题画面 1. 美化游戏标题 2. 让背景动起来 3. 自定义标题菜单 4. 美化菜单 【实例教程5】制作小游戏:坦克大战(上) 1. 游戏结构及流程介绍 2. 相关素材资源的下载和使用 3. 基础知识:音效的播放 4. 基础知识:精灵表的切帧 5. 基础知识:使用MV中的动画 6. Scene_TankWarTitle类解析 7. Sprite_Bullet类解析 8. Sprite_Explode类解析 9. Sprite_Tank类解析 10. Sprite_Enemy类解析 11. Scene_TankWar类解析 12. Scene_TankWarGameOver类解析 【实例教程6】存档的加密解密与保护 1. 找出MV存档和读档的方式 2. 制作MV存档的修器 3. 如何保护存档? 4. 制作一个存档保护插件 【实例教程7】制作一个传送插件 1. 传送插件的主要功能 2. 将自定义数据保存到存档中 3. meta数据的使用 4. 使用地图备注登记传送点 5. 在插件中解析并记录传送点 6. 使用地图备注登记多个传送点并在插件中记录 7. 制作传送点选取窗口显示传送点数据 8. 将物品或技能标记为传送物品、传送技能 9. 显示传送动画实现传送功能 10. 禁止使用传送道具或传送技能 11. 实现插件命令
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值