移除 Color._val 讨论

问题描述

Color 类通过 _val(number 类型)存储 RGBA 数据(ABGR) 的顺序),每次对 RGBA 的修改都需要进行位移操作拼接出正确的数据。增加不必要的运算且容易出错。

当修复 Tween 接口时,无法通过通用的方式去修改 Color 值,需要进行 hack 操作来修复:https://github.com/cocos/cocos-engine/pull/16977。

我猜想最开始的设计是为了节省内存空间,每个 Color 可以节省 3 个 number,因为 number 比较小,用 32 位存储,所以大概可以节省 12 个字节。但是相对于逻辑的复杂和不统一,这点内存我觉得是没必要省的。

我看了 three.js 和 babylon.js 也都是直接存储 r, g, b, a 的值。

解决方案

Color 直接存储 r、g、b、a,移除 _val。这样定义很清晰,没有隐晦的格式。

受影响范围

对于直接使用 Color._val 数据的人会受影响。理论上,上层代码不应该直接使用这个数据,因为它是 ARGB 的格式,上层要使用的话还得自己分离出各颜色通道数据。要修改的话,还得知道这个顺序,而且需要进行正确的位移操作。

另外,这个属性在 3.5 就已经 deprecated 了。

我觉得没啥讨论的,直接 rgba,引擎升级说明里标注一下就行。

3赞

既然 three.js 和 babylon.js 都是这么做的,那么就改吧。

嗯嗯,还是要说一下。如果改的话,升级是会说明的。

改,一般设置color也不用用到_val

改吧。升级说明一下。
不用的人不会看文档,用的人会去看源码。

1赞

是的,这个改一下,不然tween动画一直不对

我从2年前用3d就遇到了tween无法修改color的问题,这问题居然还能存在整整2年吗 :2:
我觉得这个怎么样也要改的吧,毕竟比起_val,怎么样也是tween的问题更重要啊

这个太影响用户使用体验的问题,拖到现在的确有点久。

最近我在整理完善 Tween,我也会查看论坛中所有 Tween 的历史问题。
所以有关于 Tween 的任何新问题,也可以都给我们反馈,我们尽量在 3.8.5 中把这个功能完善好。

举4个蹄赞成,现在的手机内存这点损耗可以忽略,简单易上手更重要
但是2.x的tween好像渐变color没有问题啊

特地看了一下,原来 2.x 这里有个隐藏的调用 lerp 的逻辑,要求所有支持 tween 的对象需要有实现 lerp 函数。 而在 3.x 中的逻辑是遍历对象中的所有属性,如果是 Color 类型,因为他只存储了 _val ,所以就直接怼 _val 进行差值了,肯定就出问题了。

            if (typeof start === 'number') {
                prop.current = interpolation(start, end, prop.current, time);
            } else if (typeof start === 'object') {
                // const value = prop.value;
                for (const k in start) {
                    prop.current[k] = interpolation(start[k], end[k], prop.current[k], time);
                }
            }

i am giao ing

https://mp.weixin.qq.com/s/iDxKNgtBqXPNIhGrAL6Jmg

1赞

嗯~2.x的做法挺聪明
不过现在看来最好的设计还是改color结构 :grinning:

是的,但是 2.x 这种要求要缓动的对象类型默认实现了 lerp, 如果要用 by,还得实现 add, mul 等。如果没有实现,start tween 的时候会给一条警告日志。

3.x 会更通用,但是也暴露出 Color._var 的问题。

对对,目前为止改color是最优解

这样对color的话,tween能直接用肯定是好很多了,之前tween起来五颜六色的 :joy:,现在我都忘了当时是怎么解决的了。。。

+1,我当时好像只是想做个渐变而已,直接给我来了一记彩色重拳,人都给闪蒙圈了 :rofl:

已提交修改 https://github.com/cocos/cocos-engine/pull/17021 。 本来想把 r, g, b, a 作为 public 属性的,结果因为需要限制值为[0, 255] 的整数,没办法,只得改用 getter/setter。因为使用 private 属性,发现之前其他类返回 Color 的类型不一致,有些返回 Readonly<Color>, 有些返回 Color,而 Readonly<Color> 没法传给 Color,又不想修改 getter 的返回值类型都变成 Readonly(否则又破坏兼容性了),就有了许多 as Color 的操作。

本来 Color 内部应该是不需要使用 getter/setter 的,但是不少静态方法的参数是 IColorLike,而 IColorLike 是没有 _r, _g, _b, _a 属性的,所以没办法,只能通过 getter/setter 了。