用Cocos做游戏一个月左右,原来是做Unity,为了搞微信小游戏开始用Cocos。
初打开Cocos感觉到很熟悉的样子,颇有几分Unity的感觉,加上TS和C#也有那么几分相似,所以使用的时候也是继承了搞Unity的经验,想当然地把套路用在Cocos上。
比如说,你想有一个 Color 属性,把他初值设为白色, Color.WHITE,在Unity 里你这么来:
public Color color = Color.white;
Cocos中你想当然这样用:
@property(Color)
public color:Color = Color.WHITE;
是不是看起来挺正常的?把这两行加到你的component 中,你会看到如同预想中的:
不错不错,就像Unity一样
诶?下面怎么有个报错?
这是啥?什么 “不能给只读属性赋值” ,我代码里没定义什么只读属性,一定是像有的 prefab 一样经常乱报错,我reload一下会好了。
Reload之后你会发现,更糟了:
编译失败?我哪里写错了?
于是你上下求索,百思不得解,
终于,你点进 Color.WHITE,
static WHITE: Readonly<Color>;
你明白了,这是个只读值,不能改。
你是幸运的,因为我是在一个非 component 里定义的 color,而我也没有脚本编译失败的提示,只是反复不断报错,而且还引发了其他连锁问题。
正确的做法是这样定义一个初始值:
color:Color = new Color(Color.WHITE);
由于JS 或者 TS 没有类似 struct 的东西,所以不是primtive的值都是对象引用,而
color = Color.white;
这种写法是把一个只读对象给了 color,所以后续对他的写都是禁止的。如果你在代码中对它进行赋值vscode就会帮你高亮出来,但是我在这里的用法是在编辑器中对它的dump值进行操作,所以发现不了问题,但是在加载(deserialize)的时候就会报错。
是我的不好,但是我想问:如果 Color.WHITE 就这么一个用法,还要它做什么?能起到简化代码的目的吗?难道大家的项目里都是这样繁琐地使用?
看看Unity 的 Color.White 的实现:
// Solid white. RGBA is (1, 1, 1, 1).
public static Color white
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return new Color(1f, 1f, 1f, 1f);
}
}
Cocos 在这里给一个 只读的 value,只是给引擎内部用的吗?
同样的问题还是 Vec3.ONE,也是一个只读值,这么让人混淆的使用,我实在是想不明白,于是在Github上找有几个项目使用了 Vec3.ONE,又是怎么使用的。可是我只看到 cocos engine内部对它的使用。
但是我却发现,在早期 3.0.0 以前的版本里,是有合理的版本的,从2.2.2 到 2.4.14(3.0.0之前最后一个版本),都有合理的常量定义,如:
tag : 2.2.2 vec3.js
/**
* !#en return a Vec3 object with x = 1, y = 1, z = 1.
* !#zh 新 Vec3 对象。
* @property ONE
* @type Vec3
* @static
*/
js.get(Vec3, 'ONE', function () {
return new Vec3(1.0, 1.0, 1.0);
});
tag: 2.4.14 vec3.ts
/**
* !#en return a Vec3 object with x = 1, y = 1, z = 1.
* !#zh 新 Vec3 对象。
* @property ONE
* @type Vec3
* @static
*/
static get ONE () { return new Vec3(1, 1, 1); }
static readonly ONE_R = Vec3.ONE;
在 2.4.14 这个版本里,合理给出了 ONE() get 属性 以及 ONE_R 只读变量。
可是到了 3.0.0 这么好的设计却没有了!
谁要用那个 只读变量 ONE! 要的是 get ONE()!
求求大大了,这个不是说 TS 的机制做不到,你哪怕要写成 ONE(),也比给个只读的量好吧!像 = Vec3.ONE, =Color.WHITE 的用法,该不是只有引擎内在用吧!