import { Component, Node, Vec3, tween, Quat, Sprite, Color, math, easing, Camera, ITweenOption, IPunchTweenOption, IShakeTweenOption } from 'cc'; // import { calcPunchData, calcShakeData } from './Util'; ////////////////////// // Transform ////////////////////// Node.prototype.qtPosition = function(to: Vec3, duration: number, opts?: ITweenOption) { return tween(this).to(duration, { position: to }, opts); } Node.prototype.qtPositionX = function(to: number, duration: number, opts?: ITweenOption) { const startPos = this.position; return tween(this).to(duration, { position: new Vec3(to, startPos.y, startPos.z) }, opts); } Node.prototype.qtPositionY = function(to: number, duration: number, opts?: ITweenOption) { const startPos = this.position; return tween(this).to(duration, { position: new Vec3(startPos.x, to, startPos.z) }, opts); } Node.prototype.qtPositionZ = function(to: number, duration: number, opts?: ITweenOption) { const startPos = this.position; return tween(this).to(duration, { position: new Vec3(startPos.x, startPos.y, to) }, opts); } Node.prototype.qtWorldPosition = function(to: Vec3, duration: number, opts?: ITweenOption) { return tween(this).to(duration, { worldPosition: to }, opts); } Node.prototype.qtWorldPositionX = function(to: number, duration: number, opts?: ITweenOption) { const startPos = this.worldPosition; return tween(this).to(duration, { worldPosition: new Vec3(to, startPos.y, startPos.z) }, opts); } Node.prototype.qtWorldPositionY = function(to: number, duration: number, opts?: ITweenOption) { const startPos = this.worldPosition; return tween(this).to(duration, { worldPosition: new Vec3(startPos.x, to, startPos.z) }, opts); } Node.prototype.qtWorldPositionZ = function(to: number, duration: number, opts?: ITweenOption) { const startPos = this.worldPosition; return tween(this).to(duration, { worldPosition: new Vec3(startPos.x, startPos.y, to) }, opts); } Node.prototype.qtRotation = function(to: Vec3, duration: number, opts?: ITweenOption) { return tween(this).to(duration, { eulerAngles: to }, opts); } Node.prototype.qtRotationQuat = function(to: Quat, duration: number, opts?: ITweenOption) { return tween(this).to(duration, { rotation: to }, opts); } Node.prototype.qtScale = function(to: Vec3|number, duration: number, opts?: ITweenOption) { let toScale = to; if (!(to instanceof Vec3)) { toScale = new Vec3(to, to, to); } return tween(this).to(duration, { scale: toScale }, opts); } Node.prototype.qtScaleX = function(to: number, duration: number, opts?: ITweenOption) { const startScale = this.scale; return tween(this).to(duration, { scale: new Vec3(to, startScale.y, startScale.z) }, opts); } Node.prototype.qtScaleY = function(to: number, duration: number, opts?: ITweenOption) { const startScale = this.scale; return tween(this).to(duration, { scale: new Vec3(startScale.x, to, startScale.z) }, opts); } Node.prototype.qtScaleZ = function(to: number, duration: number, opts?: ITweenOption) { const startScale = this.scale; return tween(this).to(duration, { scale: new Vec3(startScale.x, startScale.y, to) }, opts); } Node.prototype.qtPunchPosition = function(punch: Vec3, duration: number, opts?: IPunchTweenOption) { const vibrato = opts?.vibrato ?? 3; const elasticity = opts?.elasticity ?? 0.5; const {tos, durations} = calcPunchData(this.position.clone(), punch, duration, vibrato, elasticity); const punchTween = tween(this); tos.forEach((to, index) => { const d = durations[index]; let tweenOpts: ITweenOption|undefined; if (index === 0) { tweenOpts = { onStart: opts.onStart } } else if (index === tos.length - 1) { tweenOpts = { onComplete: opts.onComplete } } punchTween.then(tween().to(d, {position: to}, tweenOpts)); }); return punchTween.union(); } Node.prototype.qtPunchRotation = function(punch: Vec3, duration: number, opts?: IPunchTweenOption) { const vibrato = opts?.vibrato ?? 3; const elasticity = opts?.elasticity ?? 0.5; const {tos, durations} = calcPunchData(this.rotation.clone(), punch, duration, vibrato, elasticity); const punchTween = tween(this); tos.forEach((to, index) => { const d = durations[index]; let tweenOpts: ITweenOption|undefined; if (index === 0) { tweenOpts = { onStart: opts.onStart } } else if (index === tos.length - 1) { tweenOpts = { onComplete: opts.onComplete } } punchTween.then(tween().to(d, {eulerAngles: to}, tweenOpts)); }); return punchTween.union(); } Node.prototype.qtPunchScale = function(punch: Vec3, duration: number, opts?: IPunchTweenOption) { const vibrato = opts?.vibrato ?? 3; const elasticity = opts?.elasticity ?? 0.5; const {tos, durations} = calcPunchData(this.scale.clone(), punch, duration, vibrato, elasticity); const punchTween = tween(this); tos.forEach((to, index) => { const d = durations[index]; let tweenOpts: ITweenOption|undefined; if (index === 0) { tweenOpts = { onStart: opts.onStart } } else if (index === tos.length - 1) { tweenOpts = { onComplete: opts.onComplete } } punchTween.then(tween().to(d, {scale: to}, tweenOpts)); }); return punchTween.union(); } Node.prototype.qtJumpPosition = function(to: Vec3, jumpHeight: number, jumpNum: number, duration: number, opts?: ITweenOption) { const tweenPos = new Vec3(); const jumpTween = tween(this); const totalNum = jumpNum * 2; this.jumpY = 0; let startPosY = 0; const yUpTween = tween().to(duration / totalNum, { jumpY: jumpHeight }, { onStart: (target: Node) => { startPosY = target.position.y; target.jumpY = 0; }, onUpdate: (target: Node, ratio) => { tweenPos.set(target.position); tweenPos.y = startPosY + target.jumpY; target.position = tweenPos; }, onComplete: (target: Node) => { target.jumpY = 0; }, easing: 'quadOut' }).to(duration / totalNum, { jumpY: jumpHeight }, { onStart: (target: Node) => { startPosY = target.position.y; }, onUpdate: (target: Node, ratio) => { tweenPos.set(target.position); tweenPos.y = startPosY - target.jumpY; target.position = tweenPos; }, onComplete: (target: Node) => { target.jumpY = 0; }, easing: 'quadIn', }).union().repeat(jumpNum); this.jumpOffsetY = 0; let offsetY = 0; const offsetYTween = tween().to(duration, { jumpOffsetY: to.y - this.position.y }, { onStart: (target: Node) => { offsetY = to.y - target.position.y; target.jumpOffsetY = 0; }, onUpdate: (target: Node, ratio) => { const interpOffsetY = easing.quadOut(ratio) * offsetY; tweenPos.set(target.position); tweenPos.y += interpOffsetY; target.position = tweenPos; }, onComplete: (target: Node) => { target.jumpOffsetY = 0; }, easing: 'quadOut' }); this.jumpX = this.position.x; this.jumpZ = this.position.z; const xzTween = tween().to(duration, { jumpX: to.x, jumpZ: to.z }, { onStart: opts.onStart, onUpdate: (target: Node, ratio) => { tweenPos.set(target.position); tweenPos.x = target.jumpX; tweenPos.z = target.jumpZ; target.position = tweenPos; opts.onUpdate?.(); }, onComplete: (target: Node) => { // delete target.jumpX; // delete target.jumpY; // delete target.jumpZ; // delete target.jumpOffsetY; target.jumpX = target.position.x; target.jumpZ = target.position.z; opts.onComplete?.(); } }) jumpTween.parallel(yUpTween, offsetYTween, xzTween); return jumpTween; } Node.prototype.qtShakePosition = function(strength: Vec3|number, duration: number, opts?: IShakeTweenOption) { const vibrato = opts?.vibrato ?? 10; const randomness = opts?.randomness ?? 90; const fadeOut = opts?.fadeOut ?? true; let toStrength: Vec3; let vectorBased = false; if (!(strength instanceof Vec3)) { toStrength = new Vec3(strength, strength, strength); } else { toStrength = strength; vectorBased = true; } const {tos, durations} = calcShakeData(this.position.clone(), duration, toStrength, vibrato, randomness, false, vectorBased, fadeOut) const shakeTween = tween(this); tos.forEach((to, index)=> { const d = durations[index]; let tweenOpts: ITweenOption|undefined; if (index === 0) { tweenOpts = { onStart: opts.onStart } } else if (index === tos.length - 1) { tweenOpts = { onComplete: opts.onComplete } } shakeTween.then(tween().to(d, {position: to}, tweenOpts)); }); return shakeTween.union(); } Node.prototype.qtShakeRotation = function(strength: Vec3|number, duration: number, opts?: IShakeTweenOption) { const vibrato = opts?.vibrato ?? 10; const randomness = opts?.randomness ?? 90; const fadeOut = opts?.fadeOut ?? true; let toStrength: Vec3; let vectorBased = false; if (!(strength instanceof Vec3)) { toStrength = new Vec3(strength, strength, strength); } else { toStrength = strength; vectorBased = true; } const {tos, durations} = calcShakeData(this.eulerAngles.clone(), duration, toStrength, vibrato, randomness, false, vectorBased, fadeOut) const shakeTween = tween(this); tos.forEach((to, index)=> { const d = durations[index]; let tweenOpts: ITweenOption|undefined; if (index === 0) { tweenOpts = { onStart: opts.onStart } } else if (index === tos.length - 1) { tweenOpts = { onComplete: opts.onComplete } } shakeTween.then(tween().to(d, {eulerAngles: to}, tweenOpts)); }); return shakeTween.union(); } Node.prototype.qtShakeScale = function(strength: Vec3|number, duration: number, opts?: IShakeTweenOption) { const vibrato = opts?.vibrato ?? 10; const randomness = opts?.randomness ?? 90; const fadeOut = opts?.fadeOut ?? true; let toStrength: Vec3; let vectorBased = false; if (!(strength instanceof Vec3)) { toStrength = new Vec3(strength, strength, strength); } else { toStrength = strength; vectorBased = true; } const {tos, durations} = calcShakeData(this.scale.clone(), duration, toStrength, vibrato, randomness, false, vectorBased, fadeOut) const shakeTween = tween(this); tos.forEach((to, index)=> { const d = durations[index]; let tweenOpts: ITweenOption|undefined; if (index === 0) { tweenOpts = { onStart: opts.onStart } } else if (index === tos.length - 1) { tweenOpts = { onComplete: opts.onComplete } } shakeTween.then(tween().to(d, {scale: to}, tweenOpts)); }); return shakeTween.union(); } ////////////////////// // Sprite ////////////////////// // good color lerp // https://www.alanzucconi.com/2016/01/06/colour-interpolation/ Sprite.prototype.qtColor = function(to: Color, duration: number, opts?: ITweenOption) { return tween(this).to(duration, { color: to }, opts); } Sprite.prototype.qtOpacity = function(to: number, duration: number, opts?: ITweenOption) { const startColor = this.color.clone(); const tempColor = new Color(); return tween(this).to(duration, { color: new Color(startColor.r, startColor.g, startColor.b, to) }, { onStart: opts.onStart, onUpdate: (target: {_val: number}, ratio: number) => { const lerpA = startColor.a + (to - startColor.a) * ratio tempColor.set(startColor.r, startColor.g, startColor.b, lerpA); this.color = tempColor; opts.onUpdate?.(); }, onComplete: opts.onComplete }); } ////////////////////// // Camera ////////////////////// Camera.prototype.qtShakePosition = function(strength: Vec3|number, duration: number, opts?: IShakeTweenOption) { const vibrato = opts?.vibrato ?? 10; const randomness = opts?.randomness ?? 90; const fadeOut = opts?.fadeOut ?? true; let toStrength: Vec3; let vectorBased = false; if (!(strength instanceof Vec3)) { toStrength = new Vec3(strength, strength, strength); } else { toStrength = strength; vectorBased = true; } const {tos, durations} = calcShakeData(this.node.position.clone(), duration, toStrength, vibrato, randomness, true, vectorBased, fadeOut) const shakeTween = tween(this.node); tos.forEach((to, index)=> { const d = durations[index]; let tweenOpts: ITweenOption|undefined; if (index === 0) { tweenOpts = { onStart: opts.onStart } } else if (index === tos.length - 1) { tweenOpts = { onComplete: opts.onComplete } } shakeTween.then(tween().to(d, {position: to}, tweenOpts)); }); return shakeTween.union(); }