Using the cc.tween in Cocos Creator
Authors: Xunyi, youyou
cc.tween introduction
Cocos Creator provides a new set of APIs in v2.0.9 -- cc.tween
. cc.tween
can easing any property of an object, similar to the cc.Action. But cc.tween
is much easier to use than cc.Action
, because cc.tween
provides a chain-created method that can manipulate any object, and easing any of the object's properties.
cc.Action
is migrated from Cocos2d-x to Cocos Creator. Providing an API that is cumbersome, only supports use on the node properties, and requires adding a new action if you want to support new properties. In order to provide a better API, cc.tween
on the basis of cc.Action
made a layer of API encapsulation. Here's a comparison between cc.Action
and cc.tween
in use:
cc.Action:
this.node.runAction( cc.sequence( cc.spawn( cc.moveTo(1, 100, 100), cc.rotateTo(1, 360), ), cc.scale(1, 2) ) )
cc.tween:
cc.tween(this.node) .to(1, { position: cc.v2(100, 100), rotation: 360 }) .to(1, { scale: 2 }) .start()
Chain APIs
Each API of cc.tween
generates a action internally and adds this action to the internal queue. After the API is called, it returns its own instance, so that the code can be organized by chain call.
When cc.tween
calls start
, a cc.sequence queue is generated that combines the previously generated action queue.
So the chain structure of cc.tween
is to execute each API in turn, that is, it will execute an API and then execute the next API.
cc.tween(this.node)
// at 0s, node's scale is still 1.
.to(1, { scale: 2 })
// at 1s, after executing the first action, scale is 2
.to(1, { scale: 3 })
// at 2s, after executing the second action, scale is 3
.start()
// Call start and start executing cc.tween
Set the properties of cc.tween
cc.tween
provides two APIs for setting properties:
to
: Calculate the absolute value of the property. And the final run result is the property value that is set.by
: Calculate the relative value of the property. And the final run result is the property value that is set, plus the property value of the node at the start of the run.
cc.tween(node)
.to(1, {scale: 2}) // node.scale === 2
.by(1, {scale: 2}) // node.scale === 4 (2+2)
.by(1, {scale: 1}) // node.scale === 5
.to(1, {scale: 2}) // node.scale === 2
.start()
Support for easing any property of any object
let obj = { a: 0 }
cc.tween(obj)
.to(1, { a: 100 })
.start()
Execute multiple properties simultaneously
cc.tween(this.node)
// Easing three properties a, b, c at the same time
.to(1, { scale: 2, position: cc.v2(100, 100), rotation: 90 })
.start()
easing
You can use easing
to make the easing more vivid. cc.tween
provides a variety of ways to use it for different situations.
// Pass in the easing name and use the built-in easing function directly
cc.tween().to(1, { scale: 2 }, { easing: 'sineOutIn'})
// Using custom easing functions
cc.tween().to(1, { scale: 2 }, { easing: t => t*t; })
// Use the easing function only for a single property
// value must be used with easing or progress
cc.tween().to(1, { scale: 2, position: { value: cc.v3(100, 100, 100), easing: 'sineOutIn' } })
Custom progress
Compared to easing, custom progress function has more freedom to control the easing process.
// Customize the progress for all properties
cc.tween().to(1, { scale: 2, rotation: 90 }, {
progress: (start, end, current, ratio) => {
return start + (end - start) * ratio;
}
})
// Customize the progress for a single property
cc.tween().to(1, {
scale: 2,
position: {
value: cc.v3(),
progress: (start, end, current, t) => {
// Note that the passed in property is cc.Vec3, so you need to use Vec3.lerp for interpolation calculations
return start.lerp(end, t, current);
}
}
})
Replication easing
The clone
function will clone a current easing and accept a target as a parameter
// First create a easing as a template
let tween = cc.tween().to(4, { scale: 2 })
// Copy tween and use node Canvas/cocos as target
tween.clone(cc.find('Canvas/cocos')).start()
// Copy tween and use node Canvas/cocos2 as target
tween.clone(cc.find('Canvas/cocos2')).start()
Insert other easing into the queue
You can create some fixed easing in advance, and then reduce the writing of your code by combining these easing to form a new easing.
let scale = cc.tween().to(1, { scale: 2 })
let rotate = cc.tween().to(1, { rotation: 90})
let move = cc.tween().to(1, { position: cc.v3(100, 100, 100)})
// Zoom first, then rotate
cc.tween(this.node).then(scale).then(rotate)
// Zoom first, then move
cc.tween(this.node).then(scale).then(move)
Parallel execution easing
cc.tween
is executed in the form of a sequence when it is executed in a chain. However, when writing complex easing, you may need to execute multiple queues in parallel at the same time. So cc.tween
provides the parallel interface to meet this requirement.
let t = cc.tween;
t(this.node)
// Execute two cc.tween at the same time
.parallel(
t().to(1, { scale: 2 }),
t().to(2, { position: cc.v2(100, 100) })
)
.call(() => {
console.log('All tweens finished.')
})
.start()
Callback
cc.tween(this.node)
.to(2, { rotation: 90})
.to(1, { scale: 2})
// This callback function is not called until the preceding action has been performed
.call(() => { cc.log('This is a callback') })
.start()
Repeat execution
The repeat/repeatForever function will use the previous action as the object of action. However, if there are parameters that provide additional action or tween, the repeat/repeatForever function will use the incoming action or tween as the object of action.
cc.tween(this.node)
.by(1, { scale: 1 })
// Repeat 10 times for the previous by
.repeat(10)
// Finally node.scale === 11
.start()
// Can also be used like this
cc.tween(this.node)
.repeat(10,
cc.tween().by(1, { scale: 1 })
)
.start()
// Keep it going over and over again.
cc.tween(this.node)
.by(1, { scale: 1 })
.repeatForever()
.start()
Delayed execution
cc.tween(this.node)
// Delay 1s
.delay(1)
.to(1, { scale: 2 })
// Another delay of 1s
.delay(1)
.to(1, { scale: 3 })
.start()