使用Grunt实现资源自动化同步

栏目: 编程工具 · 发布时间: 5年前

内容简介:同步美术、策划资源是日常开发中极为频繁的事情,shawn借用Web前端的一些思想和工具,将Grunt自动化框架引入Cocos Creator项目,可以实现相对高效地将图片、动画、配置、音效等游戏资源导入到客户端工程中。在开始之前先用简单介绍一下Grunt是什么:

同步美术、策划资源是日常开发中极为频繁的事情,shawn借用Web前端的一些思想和工具,将Grunt自动化框架引入Cocos Creator项目,可以实现相对高效地将图片、动画、配置、音效等游戏资源导入到客户端工程中。

grunt介绍

在开始之前先用简单介绍一下Grunt是什么:

使用Grunt实现资源自动化同步

为什么选择使用Grunt做自动化工具,我简单总结下面几点:

1. 使用JavaScript语言,与Cocos Creator开发使用相同的语言,减少学习成本

2. 插件丰富,6000+(本篇文章只介绍两个grunt-sync和grunt-shell)

3. 使用json配置插件完成任务,没有太多逻辑条件,使用简单容易上手,当配置好一个模块后,其它模块可以依葫芦画瓢,策划人员也可以上手配置

4. Grunt基于Nodejs,可以借用大量插件与npm模块实现各种复杂需求

5. 跨平台

安装grunt与插件

首先,使用npm安装全局grunt-cli工具:

>npm install grunt-cli -g

然后在Cocos Creator项目根目录初始化npm的包管理文件package.json:

>npm init

输入npm init后一路回车,然后在项目中安装grunt npm模块:

>npm install grunt --save-dev

grunt只是一个自动化框架,我们这里还需要安装上面说的两个插件

>npm install grunt-sync --save-dev   //文件同步插件
>npm install grunt-shell --save-dev  //shell插件

Grunt任务模块目录结构

安装好Grunt的命令行、插件后,在项目根目录创建Gruntfile.js文件,这是Grunt自动任务的入口文件。同时在根项目新建一个tools目录,用于存放各种与项目有关的 工具 或脚本,再添加一个grunt-task目录,用于存放具体的grunt任务配置脚本,请看下图:

使用Grunt实现资源自动化同步

上图中xxx-task.js就是各子模块的自动化任务。

Gruntfile

shawn在早期使用Grunt时,是将所有任务都编写在Gruntfile.js文件,当模块越来越多,维护起来越来越困难,因此将不同模块的自动化任务独立开来,在Gruntfile.js进行统一加载和任务注册,下面看下Gruntfile文件的内容:

//引入rd模块读取文件
let rd = require('rd');
//获./tools/grunt-task目录下取所有文件
let taskScripts = rd.readFileSync('./tools/grunt-task');

module.exports = (grunt) => {
    //我们这里使用了grunt-shel&grunt-sync插件
    //下面 shell 与sync对象分别用于收集两种任务配置
    let shell = {};
    let sync = {};

    //将grunt设置为全局变量
    global.grunt = grunt;

    //require所有任务模块,放入tasks数组
    let tasks = [];
    taskScripts.forEach((script) => {
        let task = require(script);
        if (task.init) {
            //让task对象自己填充sync和shell内容
            task.init(sync, shell);
            tasks.push(task);
        }
    });
    //配置sync、shell两大任务
    grunt.initConfig({
        sync,
        shell,
    });

    //注册grunt-shell插件,用于执行外部shell命令
    grunt.loadNpmTasks('grunt-shell');
    //注册grunt-sync插件,用于本地文件同步
    grunt.loadNpmTasks('grunt-sync');

    //注册自定义的grunt任务
    tasks.forEach(task => task.registerTask());
};

对上面代码简单说明:

1. 加载tools/grunt-task下所有任务脚本

2. 为每个任务对象传入sync、shell两个任务集合对象,各任务模块在sync、shell对象中配置自己的任务内容。

3. 使用了两个grunt插件:grunt-shell、grunt-sync

4. 最后调用所有task.registerTask()将命令注册到grunt命令行

在命令控制台上执行grunt –help会看到我们所编写的自动化任务,下图是shawn曾经项目中创建的Grunt任务:

使用Grunt实现资源自动化同步

文件同步任务

你现在去执行 grunt --help 还是空的,还没有注册具体的任务,前面介绍过,Grunt是使用插件 + JSON配置的方式来创建任务,我们看一个子模块美术资源为例:

使用Grunt实现资源自动化同步

资源仓库与 客户端Assets 按上图所示建立对应关系,其中绿色箭头是文件同步操作,其中headIcon目录中的图片,在项目中是动态加载的,需要同步到assets/resources/game1/texture目录下,这些操作我们可以使用grunt-sycn来完成。

其中比较特别是atlas目录,里面是经过分类需要合并图集的图片,文件合并后放到客户端项目assets/game1/texture/atlas目录,这个操作shawn是借用TexturePacker命令行工具 + Nodejs脚本来完成。

UI资源同步

梳理好了资源目录结构,现在我们将上流程编写成grunt同步任务,创建一个game1-task.js的文件,内容如下:

let path = require('path');
//获取grunt参数,是否模拟执行,不真实复制文件
let pretend = grunt.option('pretend');
//获取资源根路径,资源路径是定义在单独的define.js文件
let { UI_ROOT_PATH,ANI_ROOT_PATH } = require('./define');
//定义模块名,也就是在assets下的目录名
const moduleName = 'game1';
//定义同步任务
const syncTask = {
    //同步UI任务:普通图片、背景图片
    'sync-ui': {
        files: [
            //同步UI图片
            {
                //设置过滤器,排除atlas、headIcon、svn、隐藏文件
                src: ['**', '!atlas/', '!headIcon/', '!**/.*', '!**/.svn', '!**/.svn/**'],  
                dest: `./assets/${moduleName}/texture/ui`,  //目标路径,将文件同步到此处
                cwd: path.join(UI_ROOT_PATH, moduleName, 'ui')  //美术UI资源目录
            },
            //同步headIcon
            {
                //排除 atlas 目录及下面的子目录、文件
                src: ['**', '!**/.*', '!**/.svn', '!**/.svn/**'], 
                //同步到resources/moduleName/texture目录下
                dest: `./assets/resources/${moduleName}/texture`, 
                cwd: path.join(UI_ROOT_PATH, moduleName, 'ui', 'headIcon')
            },
            //同步背景图片
            {
                src: ['**', '!**/.*', '!**/.svn', '!**/.svn/**'],
                dest: `./assets/${moduleName}/texture/bg`,
                cwd: path.join(UI_ROOT_PATH, moduleName, 'bg')
            }
        ],
        verbose: true, // 显示日志
        pretend: false, // 模拟输出
        updateAndDelete: true, // 删除dst冗余文件
        compareUsing: 'md5', // 可选'mtime/md5'
        ignoreInDest: ['**/*.meta', '**/*.pac', '**/.svn/**'],  // 不删除.meta文件
    },
}

上面代码中sync-ui就是一个同步任务,其中files数组中配置同步目录,每一个数组元素包含三个字段:

1. src: 文件过滤器

2. dest: 目标路径,同步到那里去,以当前Gruntfile文件为相对路径

3. cwd: 源路径,从那里去复制文件,同样以Gruntfile文件为相对路径

然后是同步选项:

1. verbose: 打印日志输出,这对我们检查路径是否正确非常有用,建议设置为true

2. pretend: 同步模拟,当值为真时,配合verbose使用只会显示要同步的文件,不会真实写入或删除文件目标文件

3. updateAndDelete:删除冗余文件,比如你动随意放入一个图片到客户端ui目录,当执行ui同步资源,这个文件并未在资源仓库中,它会被同步删除掉

4. compareUsing:文件比较策略,可选项”md5″与“mtime”,建议使用md5保证正确性

5. ignoreInDest:指定同步时不删除那些文件,这个选项非常有用,我们都知道Cocos Creator会为每个文件生成同名.meta文件,这里一定要注意,不能被同步掉了,除了meta文件外,还有自动图集、svn等文件。下面是执行grunt-shell命令的效果:

⮀ grunt up-hall --pretend
Running "sync:hall-ui" (sync) task
Copying ../../../hall/ui/hall_btn_jlb.png -> assets/hall/texture/ui/hall_btn_jlb.png
Copying ../../../hall/ui/hall_btn_kefu.png -> assets/hall/texture/ui/hall_btn_kefu.png
Copying ../../../hall/ui/hall_btn_mail.png -> assets/hall/texture/ui/hall_btn_mail.png
Copying ../../../hall/ui/hall_btn_set.png -> assets/hall/texture/ui/hall_btn_set.png
Copying ../../../hall/ui/hall_btn_share.png -> assets/hall/texture/ui/hall_btn_share.png
Copying ../../../hall/ui/hall_Btn_shop.png -> assets/hall/texture/ui/hall_Btn_shop.png
Copying ../../../hall/ui/hall_btn_yxsj.png -> assets/hall/texture/ui/hall_btn_yxsj.png
Copying ../../../hall/ui/hall_img_dianchi.png -> assets/hall/texture/ui/hall_img_dianchi.png
Copying ../../../hall/ui/hall_img_dianliang.png -> assets/hall/texture/ui/hall_img_dianliang.png
Copying ../../../hall/ui/hall_img_gold.png -> assets/hall/texture/ui/hall_img_gold.png
Copying ../../../hall/ui/hall_img_head_00.png -> assets/hall/texture/ui/hall_img_head_00.png
Copying ../../../hall/ui/hall_img_head_01.png -> assets/hall/texture/ui/hall_img_head_01.png
Copying ../../../hall/ui/hall_img_laba.png -> assets/hall/texture/ui/hall_img_laba.png
Copying ../../../hall/ui/hall_img_red.png -> assets/hall/texture/ui/hall_img_red.png
Copying ../../../hall/ui/hall_img_xinhao.png -> assets/hall/texture/ui/hall_img_xinhao.png
Copying ../../../hall/ui/hall_mask_bottom.png -> assets/hall/texture/ui/hall_mask_bottom.png
Unlinking assets/resources/hall/texture/headimg/default.png because it was removed from src.
Unlinking assets/resources/hall/texture/ui/ttz_bg_toast.png because it was removed from src.
Removing dir assets/resources/hall/texture/ui because not longer in src.

上面可以看到以Copying开头的是文件复制信息,使用verbose参数,它显示了从那儿复制文件那儿,Unlinking是删除文件,同样显示了被删除的文件路径。

动画资源同步

上面讲了UI资源的同步, 对于动画资源我们处理方式有些不同,因此需要单独创建一个同步任务:

const syncTask = {
    'sync-ui': { ... }
    'sync-ani': {
         files: [
            //同步UI
            {
                src: ['**', '**/!.DS_Store', '!**/.svn', '!**/.svn/**', '!**/.gitignore'], //过滤器
                dest: `./assets/{moduleName}/animations`,
                cwd: path.join(ANI_ROOT_PATH, moduleName, 'animations')
            },
          ],
          verbose: true, // 显示日志
          pretend: pretend || false, // 模拟输出
          updateAndDelete: true, // 删除dst冗余文件
          compareUsing: 'md5', // 可选'mtime/md5'
          ignoreInDest: ['**/.svn/**', '.DS_Store', '**/.gitignore'],  // 不删除.svn下文件
    },    
    }
}

动画同步与UI同步最大的差别在于,ignoreInDes同步选项不能忽略meta文件。在shawn的项目中,动画是由美术人员在独立的Cocos Creator工程中编辑的,美术人员可以在动画工程中使用Cocos Creator动画编辑器或Spine、DragonBones等动画资源,使用Prefab进行整合,客户端主要依赖美术提供的动画prefab文件以及动画名字,动画同步任务需要将所有动画资源全部同步到客户端项目中,其中包括所有的meta文件。

这里可能会有一个小小的风险,就是动画工程中的meta文件与客户端界面中的meta文件发生UUID冲突,这种冲突的可能性是完全存在的,但在shawn一年半十多个子模块的动画项目中暂时还未遇到过,冲突的概率非常低。

图集合并同步

在UI目录中有一个类特殊的图片,需要做成图集提高游戏渲染性能,在一个游戏项目初期由于UI风格不稳定或使用临时图片,让美术同学经常去合并图集是一个效率较低的事情。因此shawn将需要合并图集的文件放入atlas的子目录中,由程序调用TexturePacker的命令行工具,以atlas子目录为单位生成图集,直接存入客户端模块atlas目录。

图集合并并完全是动态的,shawn编写了一个Node脚本,用于遍历atlas下的子目录文件,生成图集文件,然后再使用grunt-shell插件进行整合,看下面代码:

//TexturePacker图集合并工具
let tpimg = require('../tpimage');
//shell任务
const shellTask = {
    //TexturePacker合并图片
    'tp-img': {
        command() {
            //工作路径,资源仓库atlas
            let cwd = path.join(UI_ROOT_PATH, `${moduleName}/ui/atlas`);
            //目标路径,图集文件保存到这里
            let dst = `./assets/${moduleName}/texture/ui/atlas`;
            //使用编写的Node脚本生成TexturePacker命令数组
            let commands = tpimg.tpdirs({ cwd, dst });

            //模拟输出命令
            if (pretend) {
                console.log(`cwd:${cwd}, dst:${dst}`);
                console.log(commands.join('\n'));
                return '';
            }
            //返回命令字符串,由grunt-shell插件执行
            return commands.join('&&');
        }
    },
}

下面是任务执行时的效果:

使用Grunt实现资源自动化同步 两次执行,每一次执行时生成了icon.png、icon.plist,马上再次执行,提示未发生改变没有再重新生成图集,这比我们手动打图或使用Cocos Creator的自动图集效率要高。

资源仓库更新

上面介绍了美术UI、动画、图集等资源的同步,但一个完整的模块资源同步,还需要涉及到对资源仓库的更新,具体操作就是用git或svn将资源仓库更新到最新状态,下面看使用grunt-shell命令更新资源仓库:

//svn更动画资源
'svn-ui': {
    command: [
        `svn up ${UI_ROOT_PATH}/${moduleName}/ui`,
        `svn up ${UI_ROOT_PATH}/${moduleName}/bg`
    ].json('&&')    
},

//svn更新动画资源
'svn-ani': {
    //如果使用nosvn参数,返回空字符串,跳过svn更新
    command: nosvn ? '' : `svn up ${ANI_ROOT_PATH}/${moduleName}/animation`,
}

有时会遇到svn暂时不可用,或有同学未安装svn命令行工具,会导致任务失败,可以shawn这里设置了一个nosvn的参数,用于控制是否跳过svn操作,直接返回了一个空字符串。

任务整合

一个子模块完整的资源同步任务大概需要经历下面几个步骤:

使用Grunt实现资源自动化同步

我们前面都建立的单个任务,使用grunt.registerTask可以将任意单个任务进行自由组合,看下图:

使用Grunt实现资源自动化同步

grunt.registerTask的参数包括:任务名、任务说明、子任务列表,子任务列表是一系列的任务或插件任务字符串的组合,上图中up-hall-svn任务,是由三个shell插件任务组成。

此时我们在项目根目录中,执行:

>grunt up-hall

即可享受到所有美术图片、动画、音效、配置等等资源的同步到我们的客户端hall模块。

我们经常会遇到这样一个场景:

美术同学:“xxx程序我增加了大厅商店道具张图片,你更新一下呢,我想看看效果”。

程序同学:“这几张图需要与策划配置文件配合才能生效,yyy策划你更新下商店配置”。

策划同学:“今天早上一来我就已经更好了,你直接取吧!”。

动画同学:“商店里几个动画特效我也更新了,你也取一下”。

程序同学打开终端,键入:grunt up-hall,屏幕一阵疯狂输闪,涌现出无数文字符号...

1、2、3、4、5 ....

五秒钟过去,点击Cocos Creator编译资源,观察控制台,一切ok!

程序同学:“你们使用我的IP:7456自己去看吧!”

美术策划同学,一脸惊讶地看着你,效率这么高…

曾经十几分钟都搞不定的事情,现在几秒就解决了,每天做50遍都不会觉得累!也不需要做50遍,将grunt任务与Cocos Creator插件结合,嵌入到Cocos Creator界面菜单,让 程序员 多休息一会儿吧!

欢迎关注「奎特尔星球」公众号, 欢迎大家投稿 ,来我们一起成长!

使用Grunt实现资源自动化同步

使用Grunt实现资源自动化同步


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Head First Design Patterns

Head First Design Patterns

Elisabeth Freeman、Eric Freeman、Bert Bates、Kathy Sierra、Elisabeth Robson / O'Reilly Media / 2004-11-1 / USD 49.99

You're not alone. At any given moment, somewhere in the world someone struggles with the same software design problems you have. You know you don't want to reinvent the wheel (or worse, a flat tire),......一起来看看 《Head First Design Patterns》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试