| 赞 | 0 |
| VIP | |
| 好人卡 | |
| 积分 | 1 |
| 经验 | |
| 最后登录 | 2016-4-27 |
| 在线时间 | 19 小时 |
- 梦石
- 0
- 星屑
- 50
- 在线时间
- 19 小时
- 注册时间
- 2016-3-30
- 回帖
- 12
|
楼主 |
发表于 2016-4-11 18:10:17
|
显示全部楼层
有几天没来更新了,在做其它的事儿
这会有空了,马上来把我的tip插件来完成了
上次完成一个测试版的之后,发现了一个很大问题,第一,显示出的tip框是直接就出现了,第二,关闭tip的时候没法回车去关闭,而且还强制改写了Scene_Map的update来实现的关闭,相当难看,第三,打开tip的事件角色只转身一下就又转回去了。
说白了,是相当的失败,于是又花了两天时间仔细研究了一下Window_Message的实现,有一些小的收获,这里先大致讲解一下实现的思路
首先我目标中的tip,是在Scene_Map中弹出来,跟对话的消息是一样的,如果新建一个Scene来显示的话,后面是的画面是不会动的,所以这里照着跟Window_Message一样,仅新建一个Window来在Scene_Map中显示
这里提下关于打开tip(Message也是一样)的关键所在,update,刷新帧,Window_Base自带有的一个方法,所以每个继承至Window_Base的都会有这个方法,当创建Scene之后,然后往Scene里添加Window,这些Window都会一直调用这个方法,通过这个方法来检测某些变量或者函数返回值来做出动作
拿Window_Message来举例(Window_Message里面包涵了除了显示消息以外的好几个东西,这里就简单拿显示消息来做例子),Window_Message的update实现是在非打开中和非关闭中的时候,去判断是否要显示消息框,其中当消息(就是我们调用的时候传入的那些字符信息)存在的时候打开了消息框,同时字符会在里面打印的同时并把它们都消费掉,当字符未被消费完,同时达到窗口容纳字符的最大值的时候,先暂停,然后当触发按键的时候打开下一页。看到那几个简单的字眼估计就明白了,比如newLine啊newPage啊什么的。
我们做的这个tip没这么复杂,至少我不想去每个字符慢悠悠的打出来,所以消费字符这一步我这里直接是全部拿出去了
然后再提出几个关键点
第一,就是当打开消息框的时候,按esc,不会打开菜单,而是关闭掉消息框,同样我们的tip也需要这一个操作,但是这个动作我之前是用了一个比较笨的方法,就是菜单监听esc的事件里先判断是否打开tip,如果是,则先关闭tip,其实官方的方式是,设置菜单的可用性,于是这次我也沿用官方的做法,打开tip的时候,先设置菜单不可用,然后后面的esc就不会触发打开菜单
第二,打开的tip怎么出现的,之前也是用的错误的办法,直接设置tip窗口的visible,效果嘛,就一闪,直接打开了```感觉很突兀,而标题页和消息框的那些菜单都是展开的形式打开的,方法我也想过,无非刷新帧的时候去做个动画而已嘛,实际不用这么麻烦,直接调用本体的open函数就行了,他会每一帧增加一个opacity的值,每次增加32,8次就能达到大于255的极值了,在这个加值的过程,window的isOpening属性会是true,所以就不用担心他在原本的update函数里面捣乱(update函数里面实现的时候是要去判断非打开中和非关闭中的状态),用样close也是类似的动作,所以这一动作就作出了让我们看到的展开的形式(ps:其实这里我还是有点疑问,就是opacity该叫做透明度的,怎么动画效果会是展开呢。。。),这里注意一点,初始化tip窗口的时候,记得把this.openness = 0;,这是open函数操作的关键之一。
第三,事件触发的目标是人物的话,他不会朝向主角,这里是由于有一个等待模式的介入,大家在rpg_object里面找到command101看函数最后就明白了,他设置了一个消息的等待模式,除了消息,其它好几个需要等待的,都是这样处理的,当等待模式启动之后,触发事件的目标就会朝向主角,并且如果带动作效果的,他的动作也不会停,因为等待模式也是一种update刷新着呢
上代码
[pre lang="javascript"]
/*:
* @plugindesc 主场景小提示插件
* @author BenJ
*
*
*
* @param tipIconPadding
* @desc 如果带icon图标的话,文字与图标的间距
* @default 36
*
*
* @help
*
* Plugin Command:
*
* myTipWindow showTip msg #添加一条消息
* myTipWindow showTip msg iconId #添加一条带icon的消息
*
*
*/
var parameters = PluginManager.parameters('myTipWindow');
var tipIconPadding = Number(parameters['tipIconPadding'] || 36);
var _myGame_Interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand;
Game_Interpreter.prototype.pluginCommand = function(command,args){
_myGame_Interpreter_pluginCommand.call(this);
if(command == 'myTipWindow'){
$gameMap._showTip = true;//是否需要打开tip窗口
$gameMap._isShownTip = true;//tip窗口是否被打开
$gameMap._tip = {
msg : args[0] ,//tip的文本
icon : args[1] //tip的图标
//showed : false //是否已经显示过该信息 防止一直刷新
};
this.setWaitMode('tipMessage');
}
};
//修改Game_Map初始化,增加tip相关属性
var _jGame_Map_setup = Game_Map.prototype.setup;
Game_Map.prototype.setup = function(mapId) {
_jGame_Map_setup.call(this,mapId);
this._showTip = false;
this._isShownTip = false;
this._tip = {};
};
//重写Scene_Map初始化部分窗口函数
var _jScene_Map_createAllWindows = Scene_Map.prototype.createAllWindows;
Scene_Map.prototype.createAllWindows = function() {
_jScene_Map_createAllWindows.call(this);
this.createTipWindow();
};
//创建tipWindow加入到Scene_Map
Scene_Map.prototype.createTipWindow = function() {
this._tipWindow = new Window_JTip();
this.addWindow(this._tipWindow);
};
//todo 自定义提示窗体
function Window_JTip() {
this.initialize.apply(this, arguments);
}
Window_JTip.prototype = Object.create(Window_Base.prototype);
Window_JTip.prototype.constructor = Window_JTip;
Window_JTip.prototype.initialize = function() {
var width = this.windowWidth();
var height = this.windowHeight();
Window_Base.prototype.initialize.call(this, (Graphics.width - width)/2, 200, width, height);
this.openness = 0;//尝试了好多次,原来这就是关键点所在,初始化的时候,把openness设置为0的时候,调用open函数的时候,才会去刷新
};
//窗口宽度
Window_JTip.prototype.windowWidth = function() {
return Number(this.width || 240);
};
//窗口高度
Window_JTip.prototype.windowHeight = function() {
return this.fittingHeight(1);
};
//刷新tip窗口
Window_JTip.prototype.refresh = function(_tipArgs) {
this.contents.clear();
//this.visible = $gameMap.isTipWindowShow();
if(_tipArgs){
//this.resetTipWindow(_tipArgs);//这个函数里面执行过显示窗口函数核心Bitmap的resize,如果在后面resize,会清空内容栏,具体我也没看到哪里在清空,但是事实如此
//todo 绘制消息板
var _cnTest = /[\u4E00-\u9FA5]/;
var _msg = _tipArgs.msg.toString();
var _width = 0;
//通过文字计算窗口大小
for(var i=0 ; i<_msg.length ; i++){
//判断是否为中文,不是中文,只用字体大小的一半
if(_cnTest.test(_msg)){
_width += this.standardFontSize() ;
}else{
_width += this.standardFontSize() / 2 ;
}
}
//添加默认内容左右padding
_width += this.standardPadding() * 2;
//是否包含icon
if(_tipArgs.icon != undefined && _tipArgs.icon != 0){
_width += tipIconPadding;
}
this.width = _width;
this.x = (Graphics.width - _width)/2;
this.contents.resize(this.contentsWidth(),this.contentsHeight());//这里设置的内容的宽度,如果照官方的算法,这个宽度可能会显示不完我们的内容
//todo 绘制内容
//_tipArgs.showed = true; //显示过的信息改变此标示
if(_tipArgs.icon){
//显示带icon的信息
this.drawIcon(_tipArgs.icon,0,0);
this.drawText(_tipArgs.msg.toString(),tipIconPadding,0);
}else{
//显示普通信息
this.drawText(_tipArgs.msg.toString(),0,0);
}
}
};
Window_JTip.prototype.update = function(){
Window_Base.prototype.update.call(this);
//根据window_message的实现来看,弹出样式是打开和关闭的时候调用的updateOpen和updateClose
while(!this.isOpening() && !this.isClosing()){
//在非打开中和非关闭中,调用一遍所有需要执行的东西
//message处理的方式是检测文本信息是否已经消费完来启动
if(this.updateInput()){
return;
}else if(this.needShow()){
this.startTip();
}else{
return;
}
}
};
//启动tip窗口
Window_JTip.prototype.startTip = function() {
this.refresh($gameMap._tip);
this.open();
$gameSystem.disableMenu();
$gameMap._showTip = false;//启动了窗口就把是否启动tip关掉,否则update一直刷新启动造成死循环了
this.pause = true;//启动了窗口,并且刷新了窗口之后,设置暂停
};
Window_JTip.prototype.needShow = function() {
return $gameMap._showTip;
};
Window_JTip.prototype.isTriggered = function() {
return (Input.isRepeated('ok') || Input.isRepeated('cancel') || TouchInput.isRepeated());
};
//当窗口暂停,并且有按键触发,我们就关闭窗口
Window_JTip.prototype.updateInput = function() {
if(this.pause){
if(this.isTriggered()){
$gameSystem.enableMenu();
this.pause = false;
$gameMap._isShownTip = false;
this.close();
}
return true;
}else{
return false;
}
};
//这里由于官方内定了好几种等待模式,而且写得比较死,我就直接在官方的函数里拓展了,增加了tipMessage的标示
Game_Interpreter.prototype.updateWaitMode = function() {
var waiting = false;
switch (this._waitMode) {
case 'message':
waiting = $gameMessage.isBusy();
break;
case 'transfer':
waiting = $gamePlayer.isTransferring();
break;
case 'scroll':
waiting = $gameMap.isScrolling();
break;
case 'route':
waiting = this._character.isMoveRouteForcing();
break;
case 'animation':
waiting = this._character.isAnimationPlaying();
break;
case 'balloon':
waiting = this._character.isBalloonPlaying();
break;
case 'gather':
waiting = $gamePlayer.areFollowersGathering();
break;
case 'action':
waiting = BattleManager.isActionForced();
break;
case 'video':
waiting = Graphics.isVideoPlaying();
break;
case 'image':
waiting = !ImageManager.isReady();
break;
case 'tipMessage':
waiting = $gameMap._isShownTip;
break;
}
if (!waiting) {
this._waitMode = '';
}
return waiting;
};
[/pre]
关于插件的调用和设置就不多说了,下面看成果图
|
|