You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
102 lines
3.1 KiB
102 lines
3.1 KiB
|
3 weeks ago
|
import { Node, tween, Tween, Vec3 } from 'cc';
|
||
|
|
|
||
|
|
/** 放大阶段(秒) */
|
||
|
|
const PULSE_UP_SEC = 0.4;
|
||
|
|
/** 峰顶停留(秒) */
|
||
|
|
const PULSE_PEAK_SEC = 0.14;
|
||
|
|
/** 缩回阶段(秒) */
|
||
|
|
const PULSE_DOWN_SEC = 0.4;
|
||
|
|
/** 峰顶 Y 偏移(像素) */
|
||
|
|
const PULSE_LIFT_Y = 6;
|
||
|
|
|
||
|
|
/** 跳动形变代理(sx/sy 相对基准 scale 的倍率) */
|
||
|
|
interface PulsePose {
|
||
|
|
sx: number;
|
||
|
|
sy: number;
|
||
|
|
y: number;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* BattleGame btnItem 循环跳动:非等比 scale(拉宽/拉高)+ 轻微上浮。
|
||
|
|
*/
|
||
|
|
export class BattleGameItemAdBtnPulse {
|
||
|
|
private _node: Node | null = null;
|
||
|
|
private readonly _baseScale = new Vec3(1, 1, 1);
|
||
|
|
private _baseX = 0;
|
||
|
|
private _baseY = 0;
|
||
|
|
private _baseZ = 0;
|
||
|
|
private _loopTween: Tween<PulsePose> | null = null;
|
||
|
|
private readonly _pose: PulsePose = { sx: 1, sy: 1, y: 0 };
|
||
|
|
private readonly _onPulseUpdate = (): void => { this._applyPose(); };
|
||
|
|
|
||
|
|
/** 绑定节点并启动循环跳动 */
|
||
|
|
bind(node: Node | null): void {
|
||
|
|
this.unbind();
|
||
|
|
if (!node?.isValid) return;
|
||
|
|
this._node = node;
|
||
|
|
const p = node.position;
|
||
|
|
const s = node.scale;
|
||
|
|
this._baseX = p.x;
|
||
|
|
this._baseY = p.y;
|
||
|
|
this._baseZ = p.z;
|
||
|
|
this._baseScale.set(s.x, s.y, s.z);
|
||
|
|
this._resetPose();
|
||
|
|
this._startLoop();
|
||
|
|
}
|
||
|
|
|
||
|
|
/** 停止跳动并还原节点姿态 */
|
||
|
|
unbind(): void {
|
||
|
|
const node = this._node;
|
||
|
|
if (this._loopTween) {
|
||
|
|
this._loopTween.stop();
|
||
|
|
this._loopTween = null;
|
||
|
|
}
|
||
|
|
if (node?.isValid) {
|
||
|
|
Tween.stopAllByTarget(node);
|
||
|
|
Tween.stopAllByTarget(this._pose);
|
||
|
|
node.setScale(this._baseScale);
|
||
|
|
node.setPosition(this._baseX, this._baseY, this._baseZ);
|
||
|
|
}
|
||
|
|
this._node = null;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** 循环宽高形变脉冲 */
|
||
|
|
private _startLoop(): void {
|
||
|
|
const node = this._node;
|
||
|
|
if (!node?.isValid) return;
|
||
|
|
const pose = this._pose;
|
||
|
|
this._resetPose();
|
||
|
|
const opts = { onUpdate: this._onPulseUpdate };
|
||
|
|
this._loopTween = tween(pose)
|
||
|
|
.repeatForever(
|
||
|
|
tween(pose)
|
||
|
|
.to(PULSE_UP_SEC, {
|
||
|
|
sx: 0.96, sy: 1.12, y: PULSE_LIFT_Y * 0.65,
|
||
|
|
}, { easing: 'sineInOut', ...opts })
|
||
|
|
.to(PULSE_PEAK_SEC, {
|
||
|
|
sx: 1.14, sy: 0.90, y: PULSE_LIFT_Y,
|
||
|
|
}, { easing: 'sineOut', ...opts })
|
||
|
|
.to(PULSE_DOWN_SEC, {
|
||
|
|
sx: 1, sy: 1, y: 0,
|
||
|
|
}, { easing: 'sineInOut', ...opts }),
|
||
|
|
)
|
||
|
|
.start();
|
||
|
|
}
|
||
|
|
|
||
|
|
/** 将代理姿态应用到节点 */
|
||
|
|
private _applyPose(): void {
|
||
|
|
const node = this._node;
|
||
|
|
if (!node?.isValid) return;
|
||
|
|
const p = this._pose;
|
||
|
|
node.setScale(this._baseScale.x * p.sx, this._baseScale.y * p.sy, 1);
|
||
|
|
node.setPosition(this._baseX, this._baseY + p.y, this._baseZ);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** 重置代理到常态 */
|
||
|
|
private _resetPose(): void {
|
||
|
|
this._pose.sx = 1;
|
||
|
|
this._pose.sy = 1;
|
||
|
|
this._pose.y = 0;
|
||
|
|
}
|
||
|
|
}
|