Rmmv实现脸图索引显示对应角色名字插件
插件实现了以下功能:1-通过提前配置脸图对应角色姓名,在写对话的时候直接在名字窗口上面直接显示角色姓名;
2-通过插件实现区间内所有对话都使用插件指令获得的姓名
更多功能已经写现在插件里面了
对话框的换肤实现了保存到配置,可以使用插件指令搭配对话选项进行简单的对话框换肤
JAVASCRIPT 代码下载
/*:
* @plugindesc 简单增强对话框1.2.1
* @author OYS_codePlayerD(缘系列)
* @version 1.2.1
*
* @param TiMsgModel
* @text 开启脸图索引名字
* @desc 开启后通过脸图和索引设置对话e的角色名字
* @type boolean
* @default true
*
* @param PlayerFaceNames
* @text 指定特殊角色脸图文件名
* @desc 使用逗号分隔,用于从数据文件获得对应角色数据
* @default Actor1,Actor2
*
* @param setMsgNameColor
* @text 指定名字框文字颜色
* @desc 设置名字框文字初始颜色,数值:0-31
* @type number
* @min 0
* @max 31
* @default 2
*
* @param msgNameFontSize
* @text 名字框名字大小
* @desc 设置名字框名字大小
* @type number
* @default 28
*
* @param nameWindowHeight
* @text 名字框的最大高度
* @desc 设置名字框的最大高度
* @type number
* @default 100
*
* @param PositionTypeX
* @text 起始窗口位置
* @desc 起始时窗口位置,后续可通过插件指令更改
* @type select
* @option 左方
* @value 2
* @option 中间
* @value 1
* @option 方右
* @value 0
* @default 0
*
* @param defaultOffsetY
* @text 名字框相对窗口Y偏移
* @desc Y:以对话框为参照点,向上偏移的数值
* @type number
* @default 0
*
* @help
*插件功能:
* 1-增加对话角色名字框
* 2-实现了几种更换对话角色名字的功能
* 3-实现对话窗口相关换肤功能(支持保存到配置文件)
*名字相关插件命令:
* TiMsg original
* :0-原始模式(没有名字窗口那个)
* TiMsg selftName 我是名字
* :2-自定义名字
* TiMsg selfEid 1
* :3-通过Id获得这个id对应的名称
* TiMsg reset
* :1-重置,与上述3个指令组合成区间效果
* 举例:
* TiMsg selfEid 1
* |
* |区间内所有对话名字使用id=1这个事件的名称,以上其余同理
* |
* TiMsg reset
* TiMsg msgNameColor ColorId
* : 这里是切换对话角色名字的颜色
* - 示例 : TiMsg msgNameColor 2 :和\c一样,范围:0-31
*名字框插件相关指令:
* TiMsg wLeft :名字框靠左
* TiMsg wCenter :名字框居中
* TiMsg wRight:名字框靠右
*对话窗口皮肤相关插件指令:
* TiMsg Skin fileName
* 说明:实现切换小窗口的皮肤切换,可以再对话时添加指令
* 注意:请务必预加载皮肤,不然可能会使用默认皮肤或直接没有皮肤
* TiMsg saveIniSkin
* --保存对话皮肤配置
* 版权备注:
* 1-免费可商用,但请注明作者:OYS
*
*/
(function(){
const pluginName = 'OYS_TiMessage';
const parameters = PluginManager.parameters(pluginName);
const playerFaceNames = (parameters['PlayerFaceNames'] || '').split(',').map(name => name.trim());
// 窗口相关参数,这是为了时限对话角色名字
let defaultWidth = 200;
let defaultHeight = Number(parameters['nameWindowHeight'] || 100);
let defaultX = 50;
let defaultY = Number(parameters['defaultOffsetY'] || 0);
//=================分割========
let TiMsgModel = (parameters['TiMsgModel'] || true);
let MsgNameColorId = Number(parameters['setMsgNameColor'] || 2);
let currentMode = 1;
let selftName = "";
let currenEid = 0;
let WindowsPosition = 0;
// 引入NW.js的文件系统和路径模块,实现对话窗口换肤配置
const fs = require('fs');
const path = require('path');
// 在这里配置脸图对应的数据
function actorsDataGet(currentFaceName, faceIndex){
// 为每张图片绑定对应角色名
var actorsData = {
"Actor1": {
"0": getActorsName(1),
"1": getActorsName(2),
"2": getActorsName(3),
"3": getActorsName(4),
"4": getActorsName(1),
"5": "自定义",
"6": getActorsName(1),
"7": getActorsName(1),
},
"Actor2": {
"0": getActorsName(1),
"1": getActorsName(1),
"2": getActorsName(2),
"3": getActorsName(4),
"4": getActorsName(2),
"5": getActorsName(3),
"6": getActorsName(4),
"7": "自定义名字",
},
};
return actorsData;
}
// =================
// 配置所有可能用到的皮肤图片文件(文件必须存在)
// =========
const availableSkins = [
// 这个是窗口皮肤配置,要用的皮肤文件都写在这里
// 这是给名字窗口使用的皮肤
'Window',
'Window2',
];
availableSkins.forEach(skinName => {
// 预加载皮肤,如果不做预加载,小窗口皮肤无法使用哦
ImageManager.loadSystem(skinName);
});
// ========皮肤,从文件中加载============
// 因为不干扰存档文件,所以配置文件单开,
// 所以保存需要使用插件指令
// =============================
let currentSkin = loadWindowSkin(); // 打开游戏时就加载配置
let msgNameFontSize = Number(parameters['msgNameFontSize'] || 28);
const _Game_Interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand;
Game_Interpreter.prototype.pluginCommand = function(command, args){
_Game_Interpreter_pluginCommand.call(this, command, args);
if(command === 'TiMsg'){
switch(args){
case'original':
currentMode = 0;
break;
case'reset':
currentMode = 1;
break;
case'selftName':
currentMode = 2;
selftName = args;
break;
case'selfEid':
currentMode = 3;
currenEid = Number(args);
break;
case'wLeft':
WindowsPosition = 0;
break;
case'wCenter':
WindowsPosition = 1;
break;
case'wRight':
WindowsPosition = 2;
break;
case'msgNameColor':
MsgNameColorId = Number(args);
break;
case'Skin':
const newSkin = args;
currentSkin = availableSkins.includes(newSkin) ? newSkin : 'Window';
break;
case'saveIniSkin':
saveWindowSkin(currentSkin)
break;
}
}
};
// ============================
// 这里操作配置文件
// --实现 对话窗口皮肤 的配置
// --实现 选项窗口皮肤 的配置
// --可拓展 实现 菜单窗口皮肤 的配置
// =====================
// 获取配置文件
function getConfigFilePath(){
return path.join(process.cwd(), 'wini.json');
}
function doesConfigFileExist(){
try{
return fs.existsSync(getConfigFilePath()) &&
fs.statSync(getConfigFilePath()).isFile();
}catch(e){
returnfalse;
}
}
// 初始化配置文件(如果不存在则初始化配置)
function initializeConfigFile(){
if(!doesConfigFileExist()){
try{
const defaultConfig = {
windowSkin: 'Window',//窗口,给window_Base用
WindowMessageSkin: 'Window2',//对话窗口皮肤
lastSaved: new Date().toISOString()
};
fs.writeFileSync(
getConfigFilePath(),
JSON.stringify(defaultConfig, null, 2),
'utf8'
);
// 成功
returntrue;
}catch(e){
// 创建默认配置文件失败
returnfalse;
}
}
returntrue;
}
function saveWindowSkin(skinName){
// 确保配置文件存在
if(!initializeConfigFile()){returnfalse; }
try{
const currentConfig = JSON.parse(fs.readFileSync(getConfigFilePath(), 'utf8'));
const updatedConfig = {
...currentConfig,
WindowMessageSkin: skinName,
lastSaved: new Date().toISOString()
};
fs.writeFileSync(
getConfigFilePath(),
JSON.stringify(updatedConfig, null, 2),
'utf8'
);
// 已保存皮肤设置
returntrue;
}catch(e){
console.error('保存皮肤设置失败:', e);
returnfalse;
}
}
function loadWindowSkin(){
// 确保配置文件存在
if(!initializeConfigFile()){return'Window'; }
try{
const config = JSON.parse(fs.readFileSync(getConfigFilePath(), 'utf8'));
if(config && typeof config.WindowMessageSkin === 'string'){
return config.WindowMessageSkin;
}else{
// 配置文件格式不正确,使用默认皮肤
return'Window';
}
}catch(e){
// 加载皮肤设置失败
return'Window';
}
}
function getActorsName(id){
// 通过id获取角色数据库里的对应角色名
return $gameActors.actor(id) ? $gameActors.actor(id).name() : "未知角色数据";
}
// =========
// 实现设置姓名框的名字
// ===========================
const _Game_Message_allText = Game_Message.prototype.allText;
Game_Message.prototype.allText = function(){
const originalText = _Game_Message_allText.call(this);
if(!originalText)return originalText;
if(TiMsgModel){
const currentFaceName = this.faceName();
const faceIndex = this.faceIndex();
// 处理脸图加索引以及没有脸图
if(currentMode === 1){
if(currentFaceName.trim() === ''){
// 使用事件名作为名称
const currentEvent = $gameMap._interpreter._eventId ?
$gameMap.event($gameMap._interpreter._eventId) : null;
const eventName = currentEvent ? currentEvent.event().name : "未知事件";
setMsgNameTxt(eventName);
return originalText;
}
// 使用 脸图+索引 模式
const isActors = playerFaceNames.includes(currentFaceName);
if(isActors){
const msgName = actorsDataGet(currentFaceName, faceIndex);
setMsgNameTxt(msgName);
return originalText;
}else{
const currentEvent = $gameMap._interpreter._eventId ?
$gameMap.event($gameMap._interpreter._eventId) : null;
const eventName = currentEvent ? currentEvent.event().name : "未知事件";
setMsgNameTxt(eventName);
return originalText;
}
}
if(currentMode === 0){
// 原始的模式
setMsgNameTxt(selftName);
return originalText;
}
if(currentMode === 2){//自定义名字
setMsgNameTxt(selftName);
return originalText;
}
if(currentMode === 3){
// 事件名称
if(currenEid < 1){
const currentEvent = $gameMap._interpreter._eventId ?
$gameMap.event($gameMap._interpreter._eventId) : null;
const eventName = currentEvent ? currentEvent.event().name : "未知事件";
setMsgNameTxt(eventName);
return originalText;
}else{
const eventNameEid = $gameMap.event(currenEid).event().name;
setMsgNameTxt(eventNameEid);
return originalText;
}
}
}
return originalText;
};
function setMsgNameTxt(txt){
selftName = txt;
}
//===============
//名字窗口,原本想调用窗口来实现,但发现不符合预期
//=====================================
var _Window_Message_initialize = Window_Message.prototype.initialize;
Window_Message.prototype.initialize = function(){
_Window_Message_initialize.call(this);
this.createSkinWindow();
this.createMsgNameTxt();
this.windowskin = ImageManager.loadSystem(currentSkin)
};
Window_Message.prototype.createSkinWindow = function(){
//模拟实现窗口皮肤效果
this._MsgWindowSkin = new Sprite(new Bitmap(defaultWidth + 16, defaultHeight + 16));
this._MsgWindowSkin.x = defaultX;
this._MsgWindowSkin.y = (defaultY + defaultHeight + 16) * (-1);
this._MsgWindowSkin.visible = true;
this.addChild(this._MsgWindowSkin);
if(!this._MsgWindowSkin)return;
this.skin = ImageManager.loadSystem(currentSkin);
if(!this.skin.isReady()){// 加载失败则降级到默认皮肤
this.skin = ImageManager.loadSystem('Window');
}else{
const bitmap = this._MsgWindowSkin.bitmap;
const width = bitmap.width;
const height = bitmap.height;
bitmap.clear();
const padding = 3.7;
const w = width - padding * 2;
const h = height - padding * 2;
this.drawBackgroud(bitmap, this.skin, padding, 0, 0, w, h);
const mw = 8; // 边框宽度
this.drawBord(bitmap, this.skin, 1, 0, mw, width, height)
}
};
Window_Message.prototype.updateWindowSkin = function(txtWidth){
const getChangesta = txtWidth > defaultWidth;
let setSkinWinW = getChangesta ? txtWidth : defaultWidth;
this._MsgWindowSkin.bitmap = new Bitmap(setSkinWinW + 16 - 3.7, defaultHeight + 16);
const bitmap = this._MsgWindowSkin.bitmap;
const width = bitmap.width;
const height = bitmap.height;
bitmap.clear();
const nmaePadding = 8;
// 这里实现变换位置
if(WindowsPosition === 0){
this._MsgWindowSkin.x = 10 - nmaePadding;
}
if(WindowsPosition === 1){
this._MsgWindowSkin.x = (Graphics.boxWidth - setSkinWinW) / 2 - nmaePadding;
}
if(WindowsPosition === 2){
this._MsgWindowSkin.x = (Graphics.boxWidth - setSkinWinW) - nmaePadding;
}
// 这里实现更换皮肤
this.skin = ImageManager.loadSystem(currentSkin);
this.windowskin = ImageManager.loadSystem(currentSkin)
const padding = 3.7;
const w = width - padding * 2;
const h = height - padding * 2;
this.drawBackgroud(bitmap, this.skin, padding, 0, 0, w, h);
const mw = 8; // 边框宽度
this.drawBord(bitmap, this.skin, 1, 0, mw, width, height)
}
Window_Message.prototype.createMsgNameTxt = function(){
this._msgNameTxtSprite = new Sprite();
this._msgNameTxtSprite.bitmap = new Bitmap(defaultHeight, defaultHeight);
this._msgNameTxtSprite.bitmap.fontSize = Window_Base.prototype.standardFontSize();
// 这里初始计算是以对话窗口左上角为0,0,
// 在这里还是蛮好用的,刚好设置到窗口上方
this._msgNameTxtSprite.x = defaultX + 8;
this._msgNameTxtSprite.y = (defaultY + defaultHeight + 8) * (-1);
this._msgNameTxtSprite.visible = false;
this.z = 5;
this.addChild(this._msgNameTxtSprite);
};
Window_Message.prototype.updateMsgNameTxt = function(txtWidth){
const getTxtChangeSta = txtWidth > defaultWidth;
let TxtWidthSet = getTxtChangeSta ? txtWidth : defaultWidth;
this._msgNameTxtSprite.visible = true;
this._msgNameTxtSprite.bitmap = new Bitmap(TxtWidthSet - 4, defaultHeight);
this._msgNameTxtSprite.bitmap.clear();
// 这里实现变换位置
if(WindowsPosition === 0){
this._msgNameTxtSprite.x = 10;
}
if(WindowsPosition === 1){
this._msgNameTxtSprite.x = (Graphics.boxWidth - TxtWidthSet) / 2;
}
if(WindowsPosition === 2){
this._msgNameTxtSprite.x = (Graphics.boxWidth - TxtWidthSet);
}
// 更换字体大小
this._msgNameTxtSprite.bitmap.fontSize = msgNameFontSize;
this._msgNameTxtSprite.bitmap.textColor = this.textColor(MsgNameColorId);
this._msgNameTxtSprite.bitmap.drawText(selftName, 0, 0, TxtWidthSet - 4, defaultHeight, 'center');
}
Window_Message.prototype.updateCustomSprite = function(){
let txtWidth = this._msgNameFontSize * selftName.length;
if(this._MsgWindowSkin){
this._MsgWindowSkin.visible = false;
if(currentMode !== 0){
this._MsgWindowSkin.visible = true;
this.updateWindowSkin(txtWidth);
}
}
if(this._msgNameTxtSprite){
this._msgNameTxtSprite.visible = false;
if(currentMode !== 0){
this.updateMsgNameTxt(txtWidth);
}
}
}
var _Window_Message_prototype_update = Window_Message.prototype.update;
Window_Message.prototype.update = function(){
_Window_Message_prototype_update.call(this);
//留着作为特效拓展,暂时没想好
}
var _Window_Message_startMessage = Window_Message.prototype.startMessage;
Window_Message.prototype.startMessage = function(){
_Window_Message_startMessage.call(this);
this.updateCustomSprite();
};
var _Window_Message_terminateMessage = Window_Message.prototype.terminateMessage;
Window_Message.prototype.terminateMessage = function(){
_Window_Message_terminateMessage.call(this);
if(this._msgNameTxtSprite){
this._msgNameTxtSprite.visible = false;
}
if(this._MsgWindowSkin){
this._MsgWindowSkin.visible = false;
}
};
// =========
// 对话选项换皮肤
// ==================
var Window_ChoiceList_prototype_start = Window_ChoiceList.prototype.start;
Window_ChoiceList.prototype.start = function(){
Window_ChoiceList_prototype_start.call(this);
this.windowskin = ImageManager.loadSystem(currentSkin);
};
//=====================
// 这里是处理小窗口的绘制,基本保持不动就好了
// =======================================
Window_Message.prototype.drawBord = function(tempBitmapBorder, skin, cpX, cpY, mw, width, height){
//对比用,心累填数据: bitmap.blt(源图片, 源x, 源y, 源宽, 源高, 目标x, 目标y, 目标宽, 目标高);
// 左边两角
tempBitmapBorder.blt(skin, cpX * 96, 0, mw, mw, 0, 0, mw, mw); // 左上角
tempBitmapBorder.blt(skin, cpX * 96, 96 + 96 * cpY - mw, mw, mw, 0, height - mw, mw, mw); // 左下角
// 右边两角
tempBitmapBorder.blt(skin, 96 + cpX * 96 - mw, 0, mw, mw, width - mw, 0, mw, mw); // 右上角
tempBitmapBorder.blt(skin, 96 + cpX * 96 - mw, 96 + cpY * 96 - mw, mw, mw, width - mw, height - mw, mw, mw); // 右下角
// 上下边线
tempBitmapBorder.blt(skin, cpX * 96 + mw, 0, 96 - 2 * mw, mw, mw, 0, width - 2 * mw, mw); // 上边
tempBitmapBorder.blt(skin, cpX * 96 + mw, 96 - mw, 96 - 2 * mw, mw, mw, height - mw, width - 2 * mw, mw);
// 左右边线
tempBitmapBorder.blt(skin, cpX * 96, mw, mw, 96 - 2 * mw, 0, mw, mw, height - 2 * mw); // 左边
tempBitmapBorder.blt(skin, 96 + cpX * 96 - mw, mw, mw, 96 - 2 * mw, width - mw, mw, mw, height - 2 * mw);
};
Window_Message.prototype.drawBackgroud = function(drawBackgroudBitmap, skin, padding, cpX, cpY, w, h){
const mw = 96;
const backColor = this.contentsBackColor();
drawBackgroudBitmap.clear();
drawBackgroudBitmap.context.globalCompositeOperation = 'overlay';
drawBackgroudBitmap.context.globalAlpha = 0.75;
// 绘制窗口平铺花纹
const sx = 0;
const sy = 96;
const sw = mw - 0 * 2;
const sh = mw - 0 * 2;
for(let y = padding; y < h + padding; y += sh){
for(let x = padding; x < w + padding; x += sw){
const drawWidth = Math.min(sw, w + padding - x);
const drawHeight = Math.min(sh, h + padding - y);
drawBackgroudBitmap.blt(skin, sx, sy, sw, sh, x, y, drawWidth, drawHeight);
}
}
drawBackgroudBitmap.fillRect(padding, padding, w, h, backColor);
drawBackgroudBitmap.context.globalAlpha = 1;
drawBackgroudBitmap.context.globalCompositeOperation = 'source-over';
};
// 模拟RMMV的背景色获取
Window_Message.prototype.contentsBackColor = function(){
const tone = $gameSystem.windowTone();
return `rgba(${tone}, ${tone}, ${tone},0.75)`;
};
})();
本帖来自P1论坛作者codePlayerD,因Project1站服务器在国外有时候访问缓慢不方便作者交流学习,经联系P1站长fux2同意署名转载一起分享游戏制作经验,共同为国内独立游戏作者共同创造良好交流环境,原文地址:https://rpg.blue/forum.php?mod=viewthread&tid=498154若有侵权,发帖作者可联系底部站长QQ在线咨询功能删除,谢谢。
页:
[1]