Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add cc.tween #3660

Merged
merged 11 commits into from Feb 15, 2019
Merged

add cc.tween #3660

merged 11 commits into from Feb 15, 2019

Conversation

2youyou2
Copy link
Contributor

@2youyou2 2youyou2 commented Dec 20, 2018

Changes:

  • add cc.tween to simplify action creation

Use Cases

// run a sequence action

// node.scale === 1
var node = cc.find('Canvas/cocos');

cc.tween(node)
  .to(1, {scale: 2})      // node.scale === 2
  .call( () => { console.log('This is a callback.') } )
  .by(1, {scale: 2})      // node.scale === 4
  .start()
// run tween on a simple object
var obj = { a: 0 }
cc.tween(obj)
  .to(1, { a: 100 })
  .start()
// run tween on different target
var tween = cc.tween()
  .to(4, { 
    scale: 2
  })

tween.clone(cc.find('Canvas/cocos')).start()
tween.clone(cc.find('Canvas/cocos2')).start()
// easing

// builtin easing
cc.tween().to(1, { scale: 2 }, { easing: 'sineOutIn'})

// custom easing
cc.tween().to(1, { scale: 2 }, { easing: (t) => { return t*t; }})

// easing to single property
cc.tween().to(1, { scale: 2, position: { value: cc.v3(100, 100, 100), easing: 'sineOutIn' } })
// custom property progress
cc.tween().to(1, { scale: 2}, { 
  progress: (start, end, current, t) => { 
    return start + (end - start) * t; 
  }
})

// custom property progress to single property
cc.tween().to(1, { 
  scale: 2, 
  position: {
    value: cc.v3(),
    process: (start, end, current, t) => { 
      return start.lerp(end, t, current); 
    }
  }
})
// reuse 
let scale = cc.tween().to(1, { scale: 2 })
let angle = cc.tween().to(1, { angle: 90})
let position = cc.tween().to(1, { position: cc.v3(100, 100, 100)})

let sa = cc.tween().then(scale).then(angle)
let sp = cc.tween().then(scale).then(position)

@jareguo
Copy link
Contributor

jareguo commented Dec 20, 2018

干嘛不叫 tween,避免和 animation 以及将来可能的 animator 混淆。
另外建议可以在构造时指定 target 并且默认 run。

let action1 = cc.animate(node).to(4, {
    scale: 2
});
let action2 = action.clone(node);

另外 run 建议叫做 start,因为通常还需要有 stop,start 和 stop 比较好对应。

@jareguo
Copy link
Contributor

jareguo commented Dec 20, 2018

还有一种更简单的 tween 实现方式是,只给用户返回一个进度值( 0~1 ),由用户自行对那个值进行计算。如

let fromScale = node.scale;
let action = cc.tween(curveOrEase, progression => {
  this.scale = cc.lerp(fromScale, 2, progression);  // 相当于 to 2
  this.scale = fromScale * cc.lerp(1, 2, progression);  // 相当于 乘 2
  this.scale = fromScale + cc.lerp(0, 2, progression);  // 相当于 加 2
}, node);

curve 可以暴露到编辑器中在属性检查器里进行设置。也可以传入 ease 函数。如果省略,则默认是 linear。
action 最好继承自 AnimationState,这样就能让用户额外控制播放、暂停、wrapMode。
最后一个 node 参数可选,如果指定了,则 node 或组件销毁时动效也会跟着销毁。

* @param {Object} props - {scale: 2, position: cc.v3(100, 100, 100)}
* @param {Object} opts
*/
to (duration, props, opts) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

props 放在 duration 前面不是更好看吗?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

所有 action 都是以 duration 开始的

* @param {*} props - {scale: 2, position: cc.v3(100, 100, 100)}
* @param {*} opts
*/
by (duration, props, opts) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

支持乘法的话,也应该支持加法才对,要不然就都不要支持。

Copy link
Contributor Author

@2youyou2 2youyou2 Dec 20, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

by 的意思是 props 里指定的值是相对于 target 初始值来计算的,没有乘法加法的区分
比如 vec3 会用 vec3.add,而 quat 则应该用 quat.mul,更奇葩的就应该自己定义 progress 了

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这就有点 hack 了吧…… 这样的规则很难一眼看出来。而且如果我想要放大一倍的话,vec3 是需要乘法而不是加法的。

@2youyou2
Copy link
Contributor Author

2youyou2 commented Dec 20, 2018

默认 run。

这样只能处理第一个 action ,后面想再接 action 的时候就不知道要什么时候才应该结束了

处理不了这样的需求

cc.animate()
  .to(...)
  .to(...)
  .by(...)

只给用户返回一个进度值( 0~1 ),由用户自行对那个值进行计算

这个需求添加一个 action 或者用户自己实现就可以了,而且现在已经有提供了很方便的自定义方法了,你可以自定义 easing 或者 progress 方法

action 最好继承自 AnimationState

这个工程就太大了

@2youyou2
Copy link
Contributor Author

@pandamicro
这种多 properties 并行的处理应该是比之前更快才对。
之前需要创建多个 action,这样就会计算多次时间,而现在只需要计算一次时间,这个时间比判断 properties 消耗肯定要更大

@jareguo
Copy link
Contributor

jareguo commented Dec 21, 2018

image

这个没问题吧?所有 action 都应该是在 update 和 lateUpdate 之间触发的。所以不可能在用户的代码定义时就生效,而是异步的(等待半帧)

by 的意思是 props 里指定的值是相对于 target 初始值来计算的,没有乘法加法的区分
比如 vec3 会用 vec3.add,而 quat 则应该用 quat.mul,更奇葩的就应该自己定义 progress 了

// reuse
let scale = cc.animate().to(1, { scale: 2 })
let angle = cc.animate().to(1, { angle: 90})
let position = cc.animate().to(1, { position: cc.v3(100, 100, 100)})
let sa = cc.animate().add(scale).add(angle)
let sp = cc.animate().add(scale).add(position)

感觉 by 的含义还是要再澄清下。否则用户想要做加法的话,第一直觉就是调用 add ……,容易混淆。
建议把 by 就简化成 mul,乘法操作。add 就是加法。action 之间的串联,改成 .then

sp.clone().then(scaleTo).then(moveTo);

@2youyou2
Copy link
Contributor Author

这个没问题吧?所有 action 都应该是在 update 和 lateUpdate 之间触发的。所以不可能在用户的代码定义时

默认 run 的话,那如果我要 init 时创建一个 tween 缓存住,并不想现在就运行,而是每次 click 时再去执行这个 tween 要怎么做?

感觉 by 的含义还是要再澄清下。否则用户想要做加法的话,第一直觉就是调用 add ……,容易混淆。
建议把 by 就简化成 mul,乘法操作。add 就是加法。action 之间的串联,改成 .then

有点道理

@jareguo
Copy link
Contributor

jareguo commented Dec 22, 2018

默认 run 的话,那如果我要 init 时创建一个 tween 缓存住,并不想现在就运行,而是每次 click 时再去执行这个 tween 要怎么做?

所以才建议实现和 AnimationState 一样的 API。通常 tweening 都是支持 pause/play 什么的。

@pandamicro
Copy link
Contributor

感觉 by 的含义还是要再澄清下。否则用户想要做加法的话,第一直觉就是调用 add ……,容易混淆。
建议把 by 就简化成 mul,乘法操作。add 就是加法。action 之间的串联,改成 .then

我也赞同把 add 改为 then,但是这样就不需要 add 和 mul 了,核心 API 就:to, by, then

}

this._originProps = props;
this.initWithDuration(duration);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indent issue

};

// action constructors
let constructors = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

为什么需要把这些 constructors 也放到 cc.Animate 下面?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这些本来就不应该放到 cc 下的,cc 下的东西太多了,希望能把 cc.moveTo 等都干掉放到这下面来访问


cc.Easing = module.exports = Easing;
cc.easing = module.exports = easing;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个修改要在 deprecated 里面做兼容

else {
prop.start = value.clone();
prop.current = value.clone();
prop.end = relative ? (value.add || value.mul).call(value, prop.value) : prop.value;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个地方的处理感觉有点随意啊,对 props 的兼容性可能会有问题,另外,value.add 和 mul 也可能都不存在

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ctor 里有检测类型啦!

            if (!isNumber && (!value.lerp || (!value.add && !value.mul) || !value.clone)) {
                 cc.warn(`Can not animate ${name} property, because it do not have [lerp, (add|mul), clone] function.`);
                 continue;
             }

@pandamicro
Copy link
Contributor

另外,能不能展示一下 sequence 和 repeat 在 Animate 下的使用

@pandamicro
Copy link
Contributor

还有反向的结合,比如用户用

var action = cc.sequence(moveTo, cc.animate(...))

这样的用法有没有什么限制?

@jareguo
Copy link
Contributor

jareguo commented Dec 24, 2018

但是这样就不需要 add 和 mul 了,核心 API 就:to, by, then

用户自己的 prop,怎么区分要加还是要乘?比如就一个 number 的话。

@2youyou2
Copy link
Contributor Author

2youyou2 commented Dec 24, 2018

用户自己的 prop,怎么区分要加还是要乘?比如就一个 number 的话。

没看到其他 tween 还有分 add 和 mul 的

另外,能不能展示一下 sequence 和 repeat 在 Animate 下的使用

cc.animate()
  .to(...)
  .by(...)
  .repeat(5)

这里 to 和 by 会组合成一个 sequence,repeat 会对这个 sequence repeat 5 次

var action = cc.sequence(moveTo, cc.animate(...))

cc.animate 创建的是 Animate 类,不是 action,你这里应该这样使用

cc.animate()
.to()
.then(cc.animate()...)

@pandamicro
Copy link
Contributor

所以反向在 cc.sequence,cc.repeat 等 API 中,无法使用 cc.Animate 是吗?

@jareguo
Copy link
Contributor

jareguo commented Dec 24, 2018

用户自己的 prop,怎么区分要加还是要乘?比如就一个 number 的话。

没看到其他 tween 还有分 add 和 mul 的

其它根本就不支持 by,只有一个 to,所以就没区分了……

@pandamicro
Copy link
Contributor

这个 add 和 mul 函数的使用还是很奇怪,要么就都是 add 对应 lerp,什么情况下需要 mul ?
需要 mul 的情况可以都让用户自己写 progression

@jareguo
Copy link
Contributor

jareguo commented Dec 25, 2018

什么情况下需要 mul ?
需要 mul 的情况可以都让用户自己写 progression

视觉上主要是缩放的时候(缩小到 0.5 倍)、修改透明度的时候(透明度变成原先的 0.5)。

@2youyou2
Copy link
Contributor Author

2youyou2 commented Dec 25, 2018

要么就都是 add 对应 lerp,什么情况下需要 mul

quat 就没有 add 这个函数,只有 mul,还有 mat,如果要做一个四元数的相对旋转,就要用 mul 来计算

所以反向在 cc.sequence,cc.repeat 等 API 中,无法使用 cc.Animate 是吗

原来 action 可以支持的,cc.animate 都可以使用,最不济就是用 .then 来串联原来的 action

@jareguo
Copy link
Contributor

jareguo commented Dec 27, 2018

嗯,我不是很纠结 by/mul/add,都可以的。

@jareguo
Copy link
Contributor

jareguo commented Jan 15, 2019

这个 PR 后续还需要更新吗?如果需要的话,麻烦补充一下文档和范例!

@2youyou2
Copy link
Contributor Author

会更新,暂时没时间

@2youyou2 2youyou2 changed the title add cc.animate add cc.tween Jan 22, 2019
}

this._originProps = props;
this.initWithDuration(duration);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indent issue

* !#en
* Provide a simple and flexible way to create action
* !#zh
* 提供了一个简单灵活的方法来创建 action
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

文档强调啊一下 tween 的使用场景,比如是否可以和 cc.sequence, cc.spawn 混用,是否支持 .easing 接口,是否支持用户自定义属性等。

* @method get
* @return Action
*/
Tween.prototype.get = function () {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个 API 在什么时候有用?感觉完全不需要啊

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

内部需要,可以把 api 注释去掉并改为内部方法

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

没看到哪里有用到

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

搜一下 this._get

* .by(1, {scale: 3, position: cc.v3(200, 200, 200)}, {easing: 'sineOutIn'})
* .run(cc.find('Canvas/cocos'));
*/
function Tween (target) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

如果 run 的时候必须传递 target,那么在构造的时候传递 target 的意义是什么?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

run 改为 start/stop 了,start 也不需要传 target 了

ReverseTime: cc.ReverseTime,
};

Object.assign(Tween, actions, otherActions, constructors);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

为啥除了 prototype 还要放到类静态成员里面?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这些本来就不应该放到 cc 下的,cc 下的东西太多了,希望能把 cc.moveTo 等都干掉放到这下面来访问

看到了这条,之前这个类叫 cc.Animate,是可以的,现在叫 Tween 不太合适,把这些都放在 cc.Action 下面就可以了,或者单独创立一个命名空间:cc.actions。另外,为了调整命名空间的话,应该在各个类声明的位置修改,同时给原始的 cc.moveTo 之类的接口添加 deprecation 说明

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

是的,现在放到 Tween 下不合适了,可以改为放到 cc.Action 下,以后再改吧

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

一气改好啊,合进去万一有人用又蛋疼

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

或者你把这个快捷方式删除

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

哦,看到你去掉了

@pandamicro
Copy link
Contributor

@pandamicro pandamicro merged commit b526af8 into cocos:v2.0-release Feb 15, 2019
@Ronsku
Copy link

Ronsku commented Mar 6, 2019

@2youyou2 I think Typescript types needs some updates
image

Also a comprehensive documentation would be really lovely, since I don't completely understand everything that this allows me to do. If Typings would be in place it would be easier to figure out 👍

@LootKeeper
Copy link

@Ronsku you need to write:
new cc.Tween().target(this.node).to(1, { scale: 2 }, null).start();

@jareguo
Copy link
Contributor

jareguo commented Jul 19, 2019

@2youyou2 2youyou2 deleted the v2.0-release-animate branch August 30, 2019 10:25
minggo pushed a commit that referenced this pull request Feb 10, 2022
Co-authored-by: cocos-robot <engine-deploy@cocos.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants