在近期使用CocosCreator(如下简称CC)开发HTML5游戏的工做中,发现公司许多游戏都有着相同的元素,好比倒计时条、结算页面等等。在早期的开发中,咱们并无摸索到复用的办法,只能在不一样的游戏项目中从头开始写。随着需求愈来愈多,重复造轮子确定不是一个好办法,那么对于CC项目来讲,能不能把这些可复用的游戏元素做为组件封装抽离出来呢?通过一番探索,终于找到了解决的办法。html
以咱们在手Q上的“太鼓达人”小游戏为例子,它的倒计时条和结算页面,在其余的小游戏里面也是存在的,仅仅是外观上有所不一样,但当中的逻辑处理是一致的。这里的倒计时条和结算页面,均可以理解为组件。git
两个组件的逻辑以下:typescript
经过这个例子不难理解,一个所谓的CC组件,就是一个包含了逻辑、图片、动画、音频等不一样资源的游戏节点。在CC里面,一个节点它长这个样子:shell
能够看到,编辑器左侧定义了它的结构,中间是它的具体体现,右侧是它的相关属性。
若是我想在其余的项目中复用这个已经定义好的节点,应该怎么作呢?bash
在CC里面,预制资源是很是重要部分,能够把它理解为节点的模板。若是要将一个已经作好的节点抽象成组件,把它变成预制资源会是一个最合适的办法。编辑器
当咱们在CC编辑器定义好一个节点,给它关联逻辑脚本、静态资源之后,直接把它从编辑器的层级管理器
拖到资源管理器
就能够把它转化为预制资源。可是因为CC内资源的关联是基于资源路径的,因此在抽象一个CC组件出来以前,咱们有必要把该组件全部用到的资源都放在一块儿,以方便之后的复用,不然极可能在其余工程复用的时候会报找不到资源的错误。优化
新建一个CC工程,清空assets/
目录,而后在里面创建Components/
目录,做为咱们存放CC组件的目录。以游戏结果页Result
为例,按照以下目录结构进行初始化,放入必要的资源:动画
. ├── Resources # 组件静态资源 │ ├── score.png │ └── star.png └── Result.ts # 组件脚本
而后在CC编辑器中,经过拖拽的方式给子节点添加图片,最后绑上逻辑脚本Result.ts
:this
完成之后,把它拖到资源管理器的assets/Components/Result
目录下成为一个预制资源。spa
为了让其余用户可以方便地使用这个组件,因此能够为其添加一个demo,里面放置着仅有这个组件的场景和场景所需的脚本。当用户须要了解这个组件时,只须要预览Demo场景便可,而组件的一些方法也能够在Demo脚本中看到。最终目录结构以下:
. ├── Demo # 组件使用Demo │ ├── Result.fire │ └── ResultDemo.ts ├── Resources # 组件静态资源 │ ├── score.png │ └── star.png ├── Result.prefab # 组件节点 └── Result.ts # 组件脚本
简单来讲,只要把组件库工程的Components/
目录整个复制到目标工程的assets/
目录下,而后把预制资源节点拖到层级管理器去就能够了。固然这样的手动操做不够优雅,因此咱们能够借助shell脚原本帮咱们简化这个步骤。
在目标工程的根目录下新建一个download.sh
脚本,写入以下内容:
#!/bin/bash # 先清理一下 echo "Clearing workbench..." rm -rf ./cocos-components rm -rf ./assets/Components # 直接clone组件库工程,取出Components目录,而后删掉组件库工程 echo "Cloning project..." git clone http://git.xxx.com/cocos-components.git cp -r ./cocos-components/assets/Components ./assets rm -rf ./cocos-components echo "Done!"
之后只须要执行./download.sh
就能够下载到最新的组件库了,很是方便。
组件的设计应该遵循“黑盒子”原则,它不依赖于其余组件,也不影响其余组件。组件的状态由组件自身保存,若是须要改变组件的状态或行为,应该经过它向外暴露可配置项或接口(经过Cocos Creator的属性检查器修改或者引入组件的脚本实例)。
以Progress
组件为例。
它向外提供了gameDuration
配置项,定义倒计时的时长。另外它也提供了一个setTimeoutCallback()
的方法,用于定义当倒计时结束后的行为。前者能够直接在Cocos Creator的属性检查器里面修改,后者则须要在游戏脚本中经过代码的方式去使用:
import Progress from '../Components/Progress/Progress' @ccclass export default class Game extends cc.Component { start () { Progress.instance.setTimeoutCallback(() => { console.log('Test progress timeout callback!') }) } }
在定义组件的脚本的时候,要注意为该脚本添加一个名为instance
的静态属性,以供脚本之间的调用:
export default class Progress extends cc.Component { static instance = null constructor () { super() Progress.instance = this } }
此外,搭建组件库必须注意命名规范,这样不论是开发方仍是调用方,均可以省去很多的烦恼。
CC组件库工程也是一个完整的CC游戏,咱们能够在这个游戏里面添加组件菜单,点击菜单就能够加载对应组件的场景,实时预览组件的效果。这个想法也会在以后付诸实践,争取早日开源出来。