RPG Maker mv框架代码解析之窗口图片显示

1 窗口基类的图片描画接口

RPG Maker mv框架中的窗口基类(Window_Base)提供了两个用来在窗口上描画图片的接口:

  • drawFace
  • drawIcon

当我们设计出一个基于窗口基类的窗口类后,就可以使用这两个接口在我们新窗口上描画我们的图片。不过看名字也知道,这俩接口不是什么都能画的,一个是用来话头像的(drawFace),另一个是用来话图标的(drawIcon)。

我们先来看看什么是Face和Icon:

  • Face指的是存放与下面固定路径中的图片,图片中头像的大小,排列方式都是RPG Maker mv规定好的:

img\faces

来个Face图片的例子:
Face图片

  • Icon指的是存放在下面固定路径中特定的图片,图片中头像的大小,排列方式都是RPG Maker mv规定好的:

img\system\IconSet.png

Icon图片的内容如下:
Icon图片内容

如果想要随心所欲的画自己的图片,只能使用更底层的接口,这个后面再说。

1.1 Face描画接口

Window_Base.prototype.drawFace = function(faceName, faceIndex, x, y, width, height) {
    width = width || Window_Base._faceWidth;
    height = height || Window_Base._faceHeight;
    var bitmap = ImageManager.loadFace(faceName);
    var pw = Window_Base._faceWidth;
    var ph = Window_Base._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 % 4 * pw + (pw - sw) / 2;
    var sy = Math.floor(faceIndex / 4) * ph + (ph - sh) / 2;
    this.contents.blt(bitmap, sx, sy, sw, sh, dx, dy);
};
  • faceName Face所在图片的名称(去掉扩展名.png)
  • faceIndex Face所在位置,一般一张图片里有8张Face,编号从0~7
  • x 描画位置的x坐标,这里的位置是相对于窗口基类contents成员来说的,就是在contents成员上画的位置
  • y 描画位置的y坐标,这里的位置是相对于窗口基类contents成员来说的,就是在contents成员上画的位置
  • width Face图像的宽
  • height Face图像的高

下面来个例子:

//=============================================================================
// Window_Friendliness_List
//
// 友好度展示窗口
//=============================================================================
function Window_Friendliness_List() {
    this.initialize.apply(this, arguments);
};

Window_Friendliness_List.prototype = Object.create(Window_Selectable.prototype);
Window_Friendliness_List.prototype.constructor = Window_Friendliness_List;
  
Window_Friendliness_List.prototype.initialize = function(x, y) {
    var width = this.windowWidth();
    var height = this.windowHeight();
    Window_Selectable.prototype.initialize.call(this, x, y, width, height);
    this.NPCList = [
        {
            "faceName":"Actor2",
            "faceIndex":6,
            "name":"卡洛琳"
        },
        {
            "faceName":"Actor1",
            "faceIndex":2,
            "name":"斯洛特"
        },
        {
            "faceName":"People2",
            "faceIndex":7,
            "name":"希尔"
        },
        {
            "faceName":"伊莉莎(普通)",
            "faceIndex":0,
            "name":"伊莉莎"
        },
        {
            "faceName":"People4",
            "faceIndex":1,
            "name":"夏莉"
        },
        {
            "faceName":"Actor1",
            "faceIndex":4,
            "name":"沙兰特"
        }
    ];
};

Window_Friendliness_List.prototype.drawItem = function(index) {
    this.drawItemImage(index);
};

Window_Friendliness_List.prototype.drawItemImage = function(index) {
    var rect = this.itemRect(index);
    var faceName = this.NPCList[index]["faceName"];
    var faceIndex = this.NPCList[index]["faceIndex"];
    this.drawFace(faceName, faceIndex, rect.x + 1, rect.y + 1, Window_Base._faceWidth, Window_Base._faceHeight);
};

在上面的例子中,我们首先创建了一个友好度展示用的窗口函数Window_Friendliness_List,继承于Window_Selectable对象的。 Window_Selectable对象继承自Window_Base对象,因此我们的友好度展示窗口对象最终继承于Window_Base对象。

通过new方法创建Window_Friendliness_List窗口对象时,Window_Friendliness_List.prototype.initialize会被调用,通过Window_Friendliness_List.prototype.initialize方法完成友好度展示窗口对象的内部数据构造。可以看到Window_Friendliness_List对象内部维护了一个NPCList,其实是所展示列表中各NPC头像图片的信息。

Window_Selectable对象有个refresh()方法,这个方法会调用Window_Friendliness_List.prototype.drawItem,而Window_Friendliness_List.prototype.drawItem会调用Window_Friendliness_List.prototype.drawItemImage,在Window_Friendliness_List.prototype.drawItemImage中我们通过drawFace()接口完成头像的描画。
Window_Selectable对象的refresh()方法其实是在友好度展示场景对象中触发调用的,例子中没有展示上层场景对象的代码。

1.2 Icon描画接口

Window_Base.prototype.drawIcon = function(iconIndex, x, y) {
    var bitmap = ImageManager.loadSystem('IconSet');
    var pw = Window_Base._iconWidth;
    var ph = Window_Base._iconHeight;
    var sx = iconIndex % 16 * pw;
    var sy = Math.floor(iconIndex / 16) * ph;
    this.contents.blt(bitmap, sx, sy, pw, ph, x, y);
};
  • iconIndex Icon在IconSet.png图片中的位置索引,注意空白的部分也是要参与编号的
  • x 描画位置的x坐标,这里的位置是相对于窗口基类contents成员来说的,就是在contents成员上画的位置
  • y 描画位置的y坐标,这里的位置是相对于窗口基类contents成员来说的,就是在contents成员上画的位置

2 描画自定义图片

我们可以看到通过上面介绍的接口只能画RPG Maker mv框架规定好大小的图片(Face和Icon),当然我们也可以按照Face和Icon的大小要求自己创建图片放到指定的目录下使用,但是当我们需要按照自己的需要画其它大小内容的图片时就不行了。

那么到底有没有其他方法可以描画自定义图片呢?答案当然是有。

我们观察drawFace和drawIcon接口发现,最终描画时都调用了blt方法。这个blt方法属于this.contents,而contents所指向的就是Bitmap对象。到这里我们终于认识到这些图片都是描画在哪里的了。没错,就是在一个几乎占满窗口的大Bitmap对象上画的。
我们来看一下它的实现:

Bitmap.prototype.blt = function(source, sx, sy, sw, sh, dx, dy, dw, dh) {
    dw = dw || sw;
    dh = dh || sh;
    if (sx >= 0 && sy >= 0 && sw > 0 && sh > 0 && dw > 0 && dh > 0 &&
            sx + sw <= source.width && sy + sh <= source.height) {
        this._context.globalCompositeOperation = 'source-over';
        this._context.drawImage(source._canvas, sx, sy, sw, sh, dx, dy, dw, dh);
        this._setDirty();
    }
};
  • source 一个Bitmap对象,这个对象中包含所要描画图片数据。它一般是通过ImageManager全局对象的一系列load方法得到的:
    - loadSystem
    - loadFace
    - loadIcon
    - … …

  • sx 要描画的部分在图片中的位置的x坐标

  • sy 要描画的部分在图片中的位置的y坐标

  • sw 要描画的部分的宽

  • sh 要描画的部分的高

  • dx 目标位置的x坐标,相对于contents所指向的Bitmap对象来说

  • dy 目标位置的y坐标,相对于contents所指向的Bitmap对象来说

  • dw 目标的宽

  • dh 目标的高

我们可以通过Bitmap对象的blt方法来描画自定义图片,当然要描画的图片其实可以放在下面几个目录的任意一个中,那么在创建被描画Bitmap对象时就要调用对应位置的load方法:

图片位置load方法
img/animations/ImageManager.loadAnimation
img/battlebacks1/ImageManager.loadBattleback1
img/battlebacks2/ImageManager.loadBattleback2
img/enemies/ImageManager.loadEnemy
img/characters/ImageManager.loadCharacter
img/faces/ImageManager.loadFace
img/parallaxes/ImageManager.loadParallax
img/pictures/ImageManager.loadPicture
img/sv_actors/ImageManager.loadSvActor
img/sv_enemies/ImageManager.loadSvEnemy
img/system/ImageManager.loadSystem
img/tilesets/ImageManager.loadTileset
img/titles1/ImageManager.loadTitle1
img/titles2/ImageManager.loadTitle2

上面的文件路径其实根据具体的用处定义的,根据名称基本上能猜出来用来放置何种类型的图片的。
我们在放置自定义图片时可以按照框架赋予的含义来选择路径,这样也方便我们自己管理图片资源。

【实例教程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、付费专栏及课程。

余额充值