Cocos Creator设计方便维护的面向对象结构的一种方式
2018-08-15 本文已影响0人
gz008
1.通常的写一个类的方式
cc.Class({
extends: cc.Component,
properties: {
label: {
default: null,
type: cc.Label
},
// defaults, set visually when attaching this script to the Canvas
text: 'Hello, World!'
},
// use this for initialization
onLoad: function () {
this.label.string = this.text;
},
// called every frame
update: function (dt) {
},
//设置UI相关函数
showHello() {
},
//触摸事件相关函数
onTouchHello() {
},
//网络消息相关函数
onMsgHello() {
},
});
缺陷:
通常来说,一个类里面会包含不止一个showXXX(),onTouchXXX(),onMsgXXX(),这样会导致这个类文件过于庞大,可能一个类会包含几千行代码,找某个东西的时候不是很清晰,那么如何解决这个问题?
2.C++里面一般会如何维护一个庞大的类
HelloWorld.png//HelloWorld.h
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#include "cocos2d.h"
class HelloWorld : public cocos2d::Scene
{
public:
static cocos2d::Scene* scene();
...
//
void showHello();
//
void onTouchHello(Ref* sender);
//
void onMsgHello();
};
#endif // __HELLOWORLD_SCENE_H__
//HelloWorld.cpp
#include "HelloWorld.h"
Scene* HelloWorld::scene()
{
return HelloWorld::create();
}
//HelloWorldShowUI.cpp
#include "HelloWorld.h"
void HelloWorld::showHello()
{
}
//HelloWorldTouchEvent.cpp
#include "HelloWorld.h"
void HelloWorld::onTouchHello(Ref* sender)
{
}
//HelloWorldMsgCallfunc.cpp
#include "HelloWorld.h"
void HelloWorld::onMsgHello()
{
}
如上所示,我们可以把一个类分成多个文件,不同的文件对应不同种类的相关函数,这样的话,寻找相应的函数就会方便很多。那么,如何用JS实现这种多文件描述同一个类结构?
3.JS设计一种多文件描述同一个类的方式
关键点
- JS的实例可以获取成员的定义
Object.getOwnPropertyDescriptor(obj, prop)
- JS的实例可以动态增加成员
Object.defineProperty(obj, prop, descriptor)
想法
- HelloWorld的每个种类(showXXX、onTouchXXX、onMsgXXX)的函数的集合分别组成一个类
- HelloWorld构造函数里面,获取其他文件中的函数属性并定义到自身原型链中
实现
-
脚本的文件结构
脚本文件结构
//HelloWorld.js
cc.Class({
extends: cc.Component,
properties: {
label: {
default: null,
type: cc.Label
},
// defaults, set visually when attaching this script to the Canvas
text: 'Hello, World!'
},
// use this for initialization
onLoad: function () {
this.showHello()
},
// called every frame
update: function (dt) {
},
});
//HelloWorldShowUI.js
cc.Class({
extends: cc.Component,
properties: {
},
showHello() {
this.label.string = this.text;
},
});
//HelloWorldTouchEvent.js
cc.Class({
extends: cc.Component,
properties: {
},
onTouchHello() {
},
});
//HelloWorldMsgCallfunc.js
cc.Class({
extends: cc.Component,
properties: {
},
onMsgHello() {
},
});
- HelloWorld构造函数或onLoad里面导入其他文件
cc.Class({
extends: cc.Component,
properties: {
label: {
default: null,
type: cc.Label
},
// defaults, set visually when attaching this script to the Canvas
text: 'Hello, World!'
},
// use this for initialization
onLoad: function () {
//提取其他文件中的函数到当前对象
let scripts = [
'HelloWorldShowUI',
'HelloWorldMsgCallfunc',
'HelloWorldTouchEvent',
]
for (let i = 0; i < scripts.length; i++) {
let script = scripts[i]
let cls = require(script)
let instance = new cls()
this.transferProto2Object(this, instance)
}
this.showHello()
},
// called every frame
update: function (dt) {
},
//导入其他类中的属性到当前实例
//每个类都支持继承,且最终必须继承自cc.Component,把cc.Component当成探索终点
transferProto2Object: function (obj, instance) {
let regex3 = new RegExp('__\\w+__')
let proto = instance.__proto__
//最大搜索深度3,即当前只能继承一次
let afterfilter = []
let inherit = 3
for (let i = 0; i < inherit; i++) {
if (proto.__classname__ != 'cc.Component') {
//过滤系统函数
let notsystem = Object.keys(proto)
// cc.log("notsystem = ", notsystem)
for (let i =0; i < notsystem.length; i++) {
let test = regex3.test(notsystem[i])
if (!test) {
let descriptor = Object.getOwnPropertyDescriptor(proto, notsystem[i])
afterfilter.push({
name: notsystem[i],
descriptor: descriptor,
})
}
}
proto = proto.__proto__
} else {
break
}
}
//定义到当前类对象
for (;;) {
if (afterfilter.length == 0) {
break
}
let element = afterfilter.pop()
Object.defineProperty(obj.__proto__, element.name, element.descriptor)
}
},
});
缺陷
节点的触摸事件必须使用代码注册,无法使用拖拽方式