共计 2535 个字符,预计需要花费 7 分钟才能阅读完成。
在近期使用 CocosCreator(以下简称 CC)开发 HTML5 游戏的工作中,发现公司许多游戏都有着相同的元素,比如倒计时条、结算页面等等。在早期的开发中,我们并没有摸索到复用的办法,只能在不同的游戏项目中从头开始写。随着需求越来越多,重复造轮子肯定不是一个好办法,那么对于 CC 项目来说,能不能把这些可复用的游戏元素作为组件封装抽离出来呢?经过一番探索,终于找到了解决的办法。
什么是 CC 组件
以我们在手 Q 上的“太鼓达人”小游戏为例子,它的倒计时条和结算页面,在其他的小游戏里面也是存在的,仅仅是外观上有所不同,但当中的逻辑处理是一致的。这里的倒计时条和结算页面,都可以理解为组件。
两个组件的逻辑如下:
倒计时条可以设置游戏时间,在游戏时间内其填充长度不断缩减;倒计时条右侧会显示所剩时间;在倒计时结束后会执行回调动作。
结算页面可以设置等级分值,达到或超过具体的等级分值可以获得星星;星星会按照动画逻辑展示;下方会从 0 开始对分数进行结算;结算完成后会执行回调动作。
通过这个例子不难理解,一个所谓的 CC 组件,就是一个包含了逻辑、图片、动画、音频等不同资源的游戏节点。在 CC 里面,一个节点它长这个样子:
可以看到,编辑器左侧定义了它的结构,中间是它的具体体现,右侧是它的相关属性。
如果我想在其他的项目中复用这个已经定义好的节点,应该怎么做呢?
转化成预制资源
在 CC 里面,预制资源是非常重要部分,可以把它理解为节点的模板。如果要将一个已经做好的节点抽象成组件,把它变成预制资源会是一个最合适的办法。
当我们在 CC 编辑器定义好一个节点,给它关联逻辑脚本、静态资源以后,直接把它从编辑器的层级管理器拖到资源管理器就可以把它转化为预制资源。但是由于 CC 内资源的关联是基于资源路径的,所以在抽象一个 CC 组件出来之前,我们有必要把该组件所有用到的资源都放在一起,以方便以后的复用,否则很可能在其他工程复用的时候会报找不到资源的错误。
新建一个 CC 工程,清空 assets/ 目录,然后在里面建立 Components/ 目录,作为我们存放 CC 组件的目录。以游戏结果页 Result 为例,按照如下目录结构进行初始化,放入必要的资源:
.
├── Resources # 组件静态资源
│ ├── score.png
│ └── star.png
└── Result.ts # 组件脚本
然后在 CC 编辑器中,通过拖拽的方式给子节点添加图片,最后绑上逻辑脚本 Result.ts:
完成以后,把它拖到资源管理器的 assets/Components/Result 目录下成为一个预制资源。
为了让其他用户能够方便地使用这个组件,所以可以为其添加一个 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 游戏,我们可以在这个游戏里面添加组件菜单,点击菜单就可以加载对应组件的场景,实时预览组件的效果。这个想法也会在之后付诸实践,争取早日开源出来。