Creator插件系统初探:我是怎么实现gif转anim动画的

Creator插件系统初探:我是怎么实现gif转anim动画的

这里首先感谢一些插件小王子,写这个插件的过程中,小王子解惑了很多问题。包括插件开发如何调试,creator的渲染进程和主进程以及编辑器场景问题等。

学习插件开发,首先是通过官网的插件开发文档:http://docs.cocos.com/creator/manual/zh/extension/。

但是由于文档有点简陋,所以很难实现像样的功能。而且缺少整体的知识体系说明,容易摸不清头脑。

所以在参考了小王子的插件开发教程之后,决定自己搞一款插件试试水,了解一下插件开发的知识体系。

现在大致讲一下我对Creator编辑器以及插件开发的理解。

Creator编辑器Electron实现的,Electron有主进程和渲染进程。

主进程 - Main Process

*作为程序的入口点。

*可以使用和系统对接的Electron API - 创建菜单等。

*负责创建和管理渲染进程以及各种应用程序事件。

渲染进程 - Renderer Process

*可以有多个,每个对应一个窗口,每个都是单独的进程。

*支持Node.js和DOM API,相当于一个浏览器页面。

*可以使用一部分Electron提供的API。

*所有我们看到的都是渲染进程。

插件开发的package.json指定的main.js入口程序是在主进程中被调用的。我们可以在package.json中定义一些菜单,然后main.js去监听这些菜单的点击事件去创建编辑器面板等操作。

"main-menu": {
    "i18n:MAIN_MENU.package.title/i18n:gif-to-animation.title": {
        "message": "gif-to-animation:open-view"
    }
},

这里我在扩展菜单下定义了一个子菜单,对应的消息是"open-view"。用户点击菜单就会发送这个消息。然后在mian.js中监听这个’open-view’消息,触发打开面板操作。

messages: {
  'open-view' (event) {
    Editor.Panel.open('gif-to-animation.view');
  },
},

我们也可以在package.json中自定义编辑器面板,同时指定他的index.js,每一个编辑器面板是一个渲染进程,我么可以像写网页一样去实现这个面板。

"panel": {
    "main": "panel/index.js",
    "type": "dockable",
    "title": "Simple Panel",
    "width": 400,
    "height": 300
}

编辑器还有一个特殊的渲染进程,场景渲染进程,就是我们看到的场景编辑器界面。

image

我们可以定义一个场景脚本,在 package.json 里添加 scene-script 字段指定这个脚本。

{
    "name": "my-plugin-name",
    "scene-script": "scene-walker.js"
}

这个脚本会被场景渲染进程执行,然后我们就可以在脚本中用平时写游戏的方式去操作这个场景。什么cc.resources,node.x ,getChild,cc.find等引擎api都可以调用来操作。然后就可以用我们最熟悉的方式去写插件功能了。

怎么实现gif-to-animation插件

就gif转creator帧动画这个插件,要实现这个功能分三步。

1.要解析gif文件,把图片一帧一帧的存下来。

2.把这些图片资源导入到项目下,生成.meta文件,同时获取到图片的uuid。

3.根据这些uuid生成.anim动画文件。

解析gif文件

按照需求找轮子,首先找下有没有js版本的解析gif文件库。github上看看,果然有现成的轮子。只要移植就好了。轮子地址:https://github.com/buzzfeed/libgif-js。轮子本身是基于浏览器的。而编辑器渲染进程也支持浏览器环境。尝试移植,测试代码原封不动的拷贝,渲染进程index.js内是可以使用,下面是测试轮子的代码。

parseGif: function (gifFile, tmpDir, callback) {
    const gifImg = document.createElement('img');
    gifImg.setAttribute('rel:animated_src', URL.createObjectURL(gifFile));
    gifImg.setAttribute('rel:auto_play', '0');
    // Modified pictures must be added to the body
    document.body.appendChild(gifImg);
    // Construction example
    const SuperGif = Editor.require('packages://gif-to-animation/utils/libgif.js');
    var rub = new SuperGif({ gif: gifImg });
    rub.load((gif) => {
        let dalayTime = rub.get_delay();
        var img_list = [];
        var gif_name = gifFile.name.replace('.gif', '');
        for (let i = 1; i <= rub.get_length(); i++) {
            // Traversing through each frame of a GIF instance
            rub.move_to(i);
            // Converting each frame of canvas into a file object
            let filename = gif_name + `-${i}` + '.png';
            let fullFileName = path.join(tmpDir, filename);
            this.convertCanvasToImage(rub.get_canvas(), fullFileName);
            let item = {};
            item.fullpath = fullFileName;
            item.name = filename;
            img_list.push(item);

        }
        callback(null, gif_name, dalayTime, img_list);
    });
},

第一步就简单实现了。

把资源导入到项目

找了下官方文档,调用Editor.assetdb.import接口可以实现。官网代码:

//renderer process
Editor.assetdb.import( [
    '/file/to/import/01.png',
    '/file/to/import/02.png',
    '/file/to/import/03.png',
], 'db://assets/foobar', callback);

这里吐槽一下,官网文档代码有问题,函数第三个参数是boolean值,第四个才是回调,可用代码是下面的。

Editor.assetdb.import(list, dest, true, function ( err, results) {
    if (err) {
        Editor.log(err);
    }
    self.makeAnimation(results, gif_name);
});

返回的results里有资源列表和对应的uuid。

根据这些uuid生成.anim动画文件

找了下官方文档,文档并没有提供动画编辑器相关的插件API。估计是目前没打算支持这块。但是没关系,由于我们只是试下帧动画,就是几个时间点去切换精灵的spriteFrame。这里新建一个.anim拖了几帧图片进去,看下生成的.anim文件。就是一个json文件,而且结构比较简单。

{
    "__type__": "cc.AnimationClip",
    "_name": "ani_test",
    "_objFlags": 0,
    "_native": "",
    "_duration": 0.8,
    "sample": 60,
    "speed": 1,
    "wrapMode": 2,
    "curveData": {
        "comps": {
            "cc.Sprite": {
                "spriteFrame": [
                    {
                        "frame": 0,
                        "value": {
                            "__uuid__": "9eebd21c-192a-4be6-8b4a-761b6d625649"
                        }
                    },
                ]
            }
        }
    },
    "events": []
}

spriteFrame字段的frame对应的是时间,value对应的是spriteFrame的uuid。

然后尝试去代码生成了一个json,放到编辑器中,ok可以使用。

//生成anim文件json数据
let animation = {};
animation['__type__'] = "cc.AnimationClip";
animation['_name'] = "ani_" + gif_name;
animation['_objFlags'] = 0;
animation['_native'] = "";
let frameCount = 3;
if (this._delayTime != 0) {
    frameCount = parseInt(60 / (1 / (this._delayTime * 0.01)));
}
let frameTime = 1 / 60 * frameCount;
animation['_duration'] = spriteFrameUuids.length * frameTime;    //动画时长
animation['sample'] = 60;                       //帧率
animation['speed'] = 1;                         //速度
animation['wrapMode'] = 2;                      //循环播放
animation['curveData'] = this.getFrameAnimationData(spriteFrameUuids, frameTime);
animation['events'] = [];
let str = JSON.stringify(animation, null, 4);
let anim_file_name = 'db://assets/resources/gif-to-animation/ani_' + gif_name + '.anim';

把写好的.anim文件导入编辑器。

Editor.assetdb.create(anim_file_name, str, function (err, results) {
    results.forEach(function ( result ) {
        // result.uuid
        // result.parentUuid
        // result.url
        // result.path
        // result.type
    });
});

所有的功能都实现了,只要弄个界面就可以了。

编写编辑器面板界面

关于编辑器面板的编写,请先阅读官网文档:

编写面板界面:http://docs.cocos.com/creator/manual/zh/extension/writing-your-panel.html

掌握 UI Kit:http://docs.cocos.com/creator/manual/zh/extension/using-ui-kit.html

Editor.Panel.extend({
  style: ``,

  template: ``,
});

我们可以指定面板index.js的style和template。style属性可以指定.css。template指定.html来完成页面的ui布局等。

style: fs.readFileSync(Editor.url('packages://gif-to-animation/panel/index.css'), 'utf-8'),
template: fs.readFileSync(Editor.url('packages://gif-to-animation/panel/index.html'), 'utf-8'),

这里用到了一个类型的标签去选择gif文件。以及Creator插件内置的 ui-editbox 和ui-button等。

整个面板编写流程都是web前端的技术栈。我这里也只是初步接触,就不在赘述。

这样整个插件开发就完成了。

最终效果视频可以关注公众号查看。

插件下载地址:https://store.cocos.com/#/resources/detail/2573

虽然是收费的,但是也开源了,您也可以自己下载源码自己参考学习。当然如果支持一下作者那肯定万分感谢。

源码地址:https://gitee.com/li_wenlong/gif-to-animation.git

如果文章对您有一些帮助,那么欢迎您关注公众号’creator小玉米‘。公众号会不定期发送一些编程经验。
image

20赞

小伙伴都休息了吗?没人回帖吗?都沉咯。做教程不易,望支持。

给你个赞!

mark 先赞后看

mark!

mark!

赞! 

支持一下!

厉害啊,少年,学习了

很棒呀!!

点赞!!!

新版本增加了去除背景颜色,和设置背景容积偏差的功能。需要的可以去商店下载最新的。

去除背景色那种半透明也可以吗

不可以的。gif不能设置透明度的把。。所以识别不出来的。。

暂时没用上这个功能,白嫖一波先。支持楼主

Nice~

mark!

mark~