LayaAir TimeLine 使用说明
概述
TimeLine 类是 LayaAir 引擎中的时间轴动画类,用于创建复杂的动画序列。与 Tween 不同,TimeLine 可以管理多个动画标签(label),实现更精细的动画控制和序列编排。
目录
- 基础用法
- 链式调用 API
- 标签系统
- 播放控制
- 完整示例
基础用法
创建 TimeLine
// 创建 TimeLine 实例
let timeLine = new Laya.TimeLine();
// 添加动画
timeLine.to(sprite, { x: 500 }, 1000);
// 播放
timeLine.play();
基本动画序列
let sprite = new Laya.Sprite();
sprite.graphics.drawRect(0, 0, 100, 100, "#FF0000");
sprite.pos(100, 100);
Laya.stage.addChild(sprite);
// 创建时间轴动画
let timeLine = new Laya.TimeLine();
timeLine.to(sprite, { x: 500 }, 1000, Laya.Ease.bounceOut);
timeLine.play();
链式调用 API
TimeLine 链式调用
TimeLine 支持链式调用,可以方便地构建复杂的动画序列。
let timeLine = new Laya.TimeLine();
// 链式添加多个动画
timeLine.to(sprite, { x: 500 }, 1000, Laya.Ease.bounceOut)
.to(sprite, { y: 300 }, 800, Laya.Ease.elasticOut)
.from(sprite, { scaleX: 0, scaleY: 0 }, 500, Laya.Ease.backOut)
.play();
链式方法说明
| to(target, props, duration, ease, delay) | 从当前值动画到目标值 | .to(sprite, {x: 500}, 1000) |
| from(target, props, duration, ease, delay) | 从指定值动画到当前值 | .from(sprite, {scaleX: 0}, 500) |
| addLabel(label, offset) | 在指定时间位置添加标签 | .addLabel("start", 0) |
| play(offset, loop) | 播放时间轴 | .play(0, false) |
| pause() | 暂停播放 | timeLine.pause() |
| resume() | 恢复播放 | timeLine.resume() |
| stop() | 停止播放 | timeLine.stop() |
| gotoLabel(label) | 跳转到指定标签 | .gotoLabel("start") |
| gotoTime(time) | 跳转到指定时间(毫秒) | .gotoTime(1000) |
| destroy() | 销毁时间轴 | timeLine.destroy() |
属性
| scale | 播放速度缩放,1.0 为正常速度 | timeLine.scale = 2 (2倍速) |
| index | 当前帧索引(可读写) | timeLine.index |
| total | 总帧数 | timeLine.total |
标签系统
标签是 TimeLine 的核心功能,允许在时间轴上标记关键位置。
添加和使用标签
let timeLine = new Laya.TimeLine();
// 在不同时间位置添加标签
timeLine.addLabel("start", 0) // 0ms 处添加 "start" 标签
.to(sprite, { x: 200 }, 500)
.addLabel("middle", 500) // 500ms 处添加 "middle" 标签
.to(sprite, { x: 400 }, 500)
.addLabel("end", 1000) // 1000ms 处添加 "end" 标签
.to(sprite, { x: 600 }, 500);
// 跳转到指定标签播放
timeLine.gotoLabel("middle");
// 或跳转到标签并播放
timeLine.play(0, false);
// 播放中可以跳转
timeLine.gotoLabel("start");
使用标签进行场景切换
// 创建一个带多个场景标签的动画
let timeLine = new Laya.TimeLine();
timeLine.addLabel("scene1", 0)
.to(sprite1, { alpha: 1 }, 500)
.addLabel("scene2", 500)
.to(sprite1, { alpha: 0 }, 500)
.to(sprite2, { alpha: 1 }, 500)
.addLabel("scene3", 1500)
.to(sprite2, { alpha: 0 }, 500)
.to(sprite3, { alpha: 1 }, 500);
// 按钮切换场景
button1.on(Laya.Event.CLICK, this, () => {
timeLine.gotoLabel("scene1");
});
button2.on(Laya.Event.CLICK, this, () => {
timeLine.gotoLabel("scene2");
});
button3.on(Laya.Event.CLICK, this, () => {
timeLine.gotoLabel("scene3");
});
timeLine.play(0, true); // 循环播放
播放控制
基本播放控制
let timeLine = new Laya.TimeLine();
timeLine.to(sprite, { x: 500 }, 2000);
// 播放
timeLine.play();
// 暂停
timeLine.pause();
// 恢复
timeLine.resume();
// 停止
timeLine.stop();
// 跳转到指定时间(毫秒)
timeLine.gotoTime(1000);
播放参数
// play(offset, loop)
// offset: 开始播放的时间偏移(毫秒)
// loop: 是否循环播放
// 从头开始播放,不循环
timeLine.play(0, false);
// 从 1 秒处开始播放
timeLine.play(1000, false);
// 循环播放
timeLine.play(0, true);
播放速度控制
// 设置播放速度
// 1.0 = 正常速度
// 2.0 = 2 倍速
// 0.5 = 0.5 倍速
timeLine.scale = 2;
// 实现慢动作效果
timeLine.scale = 0.5;
// 恢复正常速度
timeLine.scale = 1;
完整示例
示例1:基础动画序列
class BasicTimeLine {
private box: Laya.Sprite;
private timeLine: Laya.TimeLine;
constructor() {
Laya.init(800, 600).then(() => {
Laya.stage.bgColor = "#232628";
this.createBox();
this.createTimeLine();
});
}
private createBox(): void {
this.box = new Laya.Sprite();
this.box.graphics.drawRect(0, 0, 100, 100, "#FF7F50");
this.box.pivot(50, 50);
this.box.pos(100, 300);
Laya.stage.addChild(this.box);
}
private createTimeLine(): void {
this.timeLine = new Laya.TimeLine();
// 创建三步动画序列
this.timeLine.to(this.box, { x: 300 }, 1000, Laya.Ease.cubicOut)
.to(this.box, { y: 150 }, 800, Laya.Ease.bounceOut)
.to(this.box, { rotation: 360 }, 1000, Laya.Ease.elasticOut);
// 播放
this.timeLine.play();
}
}
new BasicTimeLine();
示例2:多对象协同动画
class MultiObjectTimeLine {
private box1: Laya.Sprite;
private box2: Laya.Sprite;
private box3: Laya.Sprite;
constructor() {
Laya.init(800, 600).then(() => {
Laya.stage.bgColor = "#232628";
this.createBoxes();
this.createTimeLine();
});
}
private createBoxes(): void {
// 创建三个不同颜色的方块
this.box1 = new Laya.Sprite();
this.box1.graphics.drawRect(0, 0, 80, 80, "#FF5722");
this.box1.pos(100, 300);
Laya.stage.addChild(this.box1);
this.box2 = new Laya.Sprite();
this.box2.graphics.drawRect(0, 0, 80, 80, "#4CAF50");
this.box2.pos(100, 400);
Laya.stage.addChild(this.box2);
this.box3 = new Laya.Sprite();
this.box3.graphics.drawRect(0, 0, 80, 80, "#2196F3");
this.box3.pos(100, 500);
Laya.stage.addChild(this.box3);
}
private createTimeLine(): void {
let timeLine = new Laya.TimeLine();
// 三个对象依次进入
timeLine.to(this.box1, { x: 400 }, 600, Laya.Ease.backOut)
.to(this.box2, { x: 400 }, 600, Laya.Ease.backOut, 100) // 延迟 100ms
.to(this.box3, { x: 400 }, 600, Laya.Ease.backOut, 200); // 延迟 200ms
timeLine.play();
}
}
new MultiObjectTimeLine();
示例3:使用标签的场景切换
class LabelTimeLine {
private sprite: Laya.Sprite;
private timeLine: Laya.TimeLine;
private buttons: Laya.Sprite[] = [];
constructor() {
Laya.init(800, 600).then(() => {
Laya.stage.bgColor = "#232628";
this.createSprite();
this.createButtons();
this.createTimeLine();
});
}
private createSprite(): void {
this.sprite = new Laya.Sprite();
this.sprite.graphics.drawCircle(0, 0, 50, "#E91E63");
this.sprite.pos(150, 300);
Laya.stage.addChild(this.sprite);
}
private createButtons(): void {
let labels = ["位置A", "位置B", "位置C"];
let colors = ["#FF5722", "#4CAF50", "#2196F3"];
for (let i = 0; i < 3; i++) {
let btn = new Laya.Sprite();
btn.graphics.drawRect(0, 0, 100, 40, colors[i]);
btn.size(100, 40); // 设置点击区域
btn.pos(100 + i * 150, 500);
Laya.stage.addChild(btn);
this.buttons.push(btn);
btn.on(Laya.Event.CLICK, this, () => {
this.timeLine.gotoLabel(labels[i]);
});
let text = new Laya.Text();
text.text = labels[i];
text.color = "#FFFFFF";
text.fontSize = 16;
text.pos(100 + i * 150 + 25, 508);
Laya.stage.addChild(text);
}
}
private createTimeLine(): void {
this.timeLine = new Laya.TimeLine();
// 定义三个位置的动画
this.timeLine.addLabel("位置A", 0)
.to(this.sprite, { x: 150, y: 300 }, 800, Laya.Ease.bounceOut)
.addLabel("位置B", 800)
.to(this.sprite, { x: 400, y: 300 }, 800, Laya.Ease.bounceOut)
.addLabel("位置C", 1600)
.to(this.sprite, { x: 650, y: 300 }, 800, Laya.Ease.bounceOut);
this.timeLine.play(0, true); // 循环播放
}
}
new LabelTimeLine();
示例4:暂停与恢复控制
class PauseResumeTimeLine {
private box: Laya.Sprite;
private timeLine: Laya.TimeLine;
private isPaused: boolean = false;
private statusText: Laya.Text;
constructor() {
Laya.init(800, 600).then(() => {
Laya.stage.bgColor = "#232628";
this.createBox();
this.createUI();
this.createTimeLine();
});
}
private createBox(): void {
this.box = new Laya.Sprite();
this.box.graphics.drawRect(0, 0, 100, 100, "#9C27B0");
this.box.pivot(50, 50);
this.box.pos(100, 300);
Laya.stage.addChild(this.box);
}
private createUI(): void {
// 状态文字
this.statusText = new Laya.Text();
this.statusText.text = "点击舞台暂停/恢复";
this.statusText.color = "#FFFFFF";
this.statusText.fontSize = 24;
this.statusText.pos(250, 500);
Laya.stage.addChild(this.statusText);
}
private createTimeLine(): void {
this.timeLine = new Laya.TimeLine();
// 创建一个较长的动画
this.timeLine.to(this.box, { x: 700 }, 3000, Laya.Ease.linearNone)
.to(this.box, { rotation: 360 }, 2000);
this.timeLine.play(0, true);
// 点击舞台暂停/恢复
Laya.stage.on(Laya.Event.CLICK, this, this.togglePause);
}
private togglePause(): void {
if (this.isPaused) {
this.timeLine.resume();
this.statusText.text = "点击舞台暂停/恢复";
this.isPaused = false;
} else {
this.timeLine.pause();
this.statusText.text = "已暂停 – 点击恢复";
this.isPaused = true;
}
}
}
new PauseResumeTimeLine();
示例5:变速播放
class SpeedControlTimeLine {
private box: Laya.Sprite;
private timeLine: Laya.TimeLine;
private currentSpeed: number = 1;
constructor() {
Laya.init(800, 600).then(() => {
Laya.stage.bgColor = "#232628";
this.createBox();
this.createUI();
this.createTimeLine();
});
}
private createBox(): void {
this.box = new Laya.Sprite();
this.box.graphics.drawRect(0, 0, 100, 100, "#FF9800");
this.box.pivot(50, 50);
this.box.pos(100, 300);
Laya.stage.addChild(this.box);
}
private createUI(): void {
let buttons = [
{ label: "0.5x", speed: 0.5, x: 100 },
{ label: "1x", speed: 1, x: 250 },
{ label: "2x", speed: 2, x: 400 },
{ label: "3x", speed: 3, x: 550 }
];
buttons.forEach(btn => {
let sprite = new Laya.Sprite();
sprite.graphics.drawRect(0, 0, 80, 40, "#424242");
sprite.size(80, 40); // 设置点击区域
sprite.pos(btn.x, 500);
Laya.stage.addChild(sprite);
let text = new Laya.Text();
text.text = btn.label;
text.color = "#FFFFFF";
text.fontSize = 18;
text.pos(btn.x + 25, 508);
Laya.stage.addChild(text);
sprite.on(Laya.Event.CLICK, this, () => {
this.timeLine.scale = btn.speed;
this.currentSpeed = btn.speed;
console.log("播放速度:", btn.speed);
});
});
}
private createTimeLine(): void {
this.timeLine = new Laya.TimeLine();
this.timeLine.to(this.box, { x: 700 }, 2000, Laya.Ease.cubicInOut)
.to(this.box, { x: 100 }, 2000, Laya.Ease.cubicInOut);
this.timeLine.play(0, true);
}
}
new SpeedControlTimeLine();
示例6:组合动画(位置+旋转+缩放)
class ComboTimeLine {
private box: Laya.Sprite;
constructor() {
Laya.init(800, 600).then(() => {
Laya.stage.bgColor = "#232628";
this.createBox();
this.createTimeLine();
});
}
private createBox(): void {
this.box = new Laya.Sprite();
this.box.graphics.drawRect(0, 0, 100, 100, "#00BCD4");
this.box.pivot(50, 50);
this.box.pos(100, 300);
Laya.stage.addChild(this.box);
// 点击重新播放
Laya.stage.on(Laya.Event.CLICK, this, () => {
this.createTimeLine();
});
}
private createTimeLine(): void {
let timeLine = new Laya.TimeLine();
// 复杂的组合动画
timeLine.to(this.box, { x: 400, y: 300, scaleX: 1.5, scaleY: 1.5, rotation: 180 },
1500, Laya.Ease.elasticOut)
.to(this.box, { x: 700, y: 150, scaleX: 1, scaleY: 1, rotation: 360 },
1200, Laya.Ease.bounceOut)
.to(this.box, { alpha: 0 }, 500, Laya.Ease.linearNone);
timeLine.play();
}
}
new ComboTimeLine();
示例7:循环动画效果
class LoopTimeLine {
constructor() {
Laya.init(800, 600).then(() => {
Laya.stage.bgColor = "#232628";
this.createLoadingAnimation();
});
}
private createLoadingAnimation(): void {
let dots: Laya.Sprite[] = [];
// 创建多个点
for (let i = 0; i < 5; i++) {
let dot = new Laya.Sprite();
dot.graphics.drawCircle(0, 0, 15, "#FF4081");
dot.pos(250 + i * 80, 300);
Laya.stage.addChild(dot);
dots.push(dot);
}
let timeLine = new Laya.TimeLine();
// 波浪式动画
dots.forEach((dot, index) => {
timeLine.to(dot, { y: 200 }, 400, Laya.Ease.sineOut, index * 80)
.to(dot, { y: 300 }, 400, Laya.Ease.sineIn);
});
// 循环播放
timeLine.play(0, true);
}
}
new LoopTimeLine();
示例8:淡入淡出切换效果
class FadeTimeLine {
private sprite1: Laya.Sprite;
private sprite2: Laya.Sprite;
private timeLine: Laya.TimeLine;
constructor() {
Laya.init(800, 600).then(() => {
Laya.stage.bgColor = "#232628";
this.createSprites();
this.createTimeLine();
});
}
private createSprites(): void {
// 第一个精灵(红色)
this.sprite1 = new Laya.Sprite();
this.sprite1.graphics.drawRect(0, 0, 200, 200, "#F44336");
this.sprite1.pos(300, 200);
this.sprite1.alpha = 1;
Laya.stage.addChild(this.sprite1);
// 第二个精灵(蓝色)
this.sprite2 = new Laya.Sprite();
this.sprite2.graphics.drawRect(0, 0, 200, 200, "#2196F3");
this.sprite2.pos(300, 200);
this.sprite2.alpha = 0;
Laya.stage.addChild(this.sprite2);
// 点击切换
Laya.stage.on(Laya.Event.CLICK, this, () => {
this.timeLine.play(0, false);
});
}
private createTimeLine(): void {
this.timeLine = new Laya.TimeLine();
// 淡出 sprite1,淡入 sprite2
this.timeLine.to(this.sprite1, { alpha: 0 }, 800, Laya.Ease.linearNone)
.to(this.sprite2, { alpha: 1 }, 800, Laya.Ease.linearNone);
this.timeLine.play(0, true); // 循环播放
}
}
new FadeTimeLine();
示例9:使用 gotoTime 精确控制
class GotoTimeTimeLine {
private box: Laya.Sprite;
private timeLine: Laya.TimeLine;
private totalTime: number = 5000; // 总时长(毫秒),需手动计算
constructor() {
Laya.init(800, 600).then(() => {
Laya.stage.bgColor = "#232628";
this.createBox();
this.createProgressBar();
this.createTimeLine();
});
}
private createBox(): void {
this.box = new Laya.Sprite();
this.box.graphics.drawRect(0, 0, 100, 100, "#8BC34A");
this.box.pivot(50, 50);
this.box.pos(100, 250);
Laya.stage.addChild(this.box);
}
private createProgressBar(): void {
// 进度条背景
let bg = new Laya.Sprite();
bg.graphics.drawRect(0, 0, 600, 10, "#424242");
bg.pos(100, 450);
Laya.stage.addChild(bg);
// 创建可点击的进度条
let progressBar = new Laya.Sprite();
progressBar.graphics.drawRect(0, 0, 600, 30, "#000000"); // 透明点击区域
progressBar.size(600, 30); // 设置点击区域
progressBar.pos(100, 440);
progressBar.alpha = 0.01;
Laya.stage.addChild(progressBar);
progressBar.on(Laya.Event.CLICK, this, (e: Laya.Event) => {
// 计算点击位置对应的进度时间
let clickX = e.stageX – 100;
let progress = clickX / 600;
let targetTime = progress * this.totalTime;
this.timeLine.gotoTime(targetTime);
console.log("跳转到时间:", targetTime, "ms");
});
// 添加提示文字
let text = new Laya.Text();
text.text = "点击进度条跳转";
text.color = "#AAAAAA";
text.fontSize = 16;
text.pos(320, 480);
Laya.stage.addChild(text);
}
private createTimeLine(): void {
this.timeLine = new Laya.TimeLine();
// 创建一个可预览进度的动画
this.timeLine.to(this.box, { x: 700 }, 3000, Laya.Ease.cubicInOut)
.to(this.box, { rotation: 360 }, 2000, Laya.Ease.linearNone);
this.timeLine.play(0, true);
}
}
new GotoTimeTimeLine();
示例10:复杂的过场动画
class TransitionTimeLine {
constructor() {
Laya.init(800, 600).then(() => {
Laya.stage.bgColor = "#232628";
this.createTransition();
});
}
private createTransition(): void {
// 创建标题文字
let title = new Laya.Text();
title.text = "GAME OVER";
title.color = "#FFFFFF";
title.fontSize = 80;
title.bold = true;
title.pos(400, 300);
title.alpha = 0;
title.pivot(title.width / 2, title.height / 2);
Laya.stage.addChild(title);
// 创建背景遮罩
let overlay = new Laya.Sprite();
overlay.graphics.drawRect(0, 0, 800, 600, "#000000");
overlay.alpha = 0;
Laya.stage.addChild(overlay);
// 创建按钮
let button = new Laya.Sprite();
button.graphics.drawRect(0, 0, 200, 60, "#FF5722");
button.pos(300, 400);
button.scaleY = 0;
Laya.stage.addChild(button);
let buttonText = new Laya.Text();
buttonText.text = "RETRY";
buttonText.color = "#FFFFFF";
buttonText.fontSize = 30;
buttonText.pos(360, 415);
buttonText.alpha = 0;
Laya.stage.addChild(buttonText);
// 创建过场动画时间轴
let timeLine = new Laya.TimeLine();
timeLine.addLabel("fade_in", 0)
// 背景渐显
.to(overlay, { alpha: 0.7 }, 500, Laya.Ease.linearNone)
// 标题弹入
.addLabel("title_in", 500)
.to(title, { alpha: 1, scaleX: 1.2, scaleY: 1.2 }, 800, Laya.Ease.backOut)
.to(title, { scaleX: 1, scaleY: 1 }, 300, Laya.Ease.linearNone)
// 按钮出现
.addLabel("button_in", 1600)
.to(button, { scaleY: 1 }, 500, Laya.Ease.backOut)
.to(buttonText, { alpha: 1 }, 300, Laya.Ease.linearNone);
timeLine.play(0, false);
}
}
new TransitionTimeLine();
TimeLine 与 Tween 的对比
| 适用场景 | 复杂的动画序列编排 | 单个或简单动画 |
| 标签系统 | 支持(可添加多个标签) | 不支持 |
| 多对象动画 | 支持统一管理多个对象 | 每个对象独立控制 |
| 播放控制 | play/pause/resume/stop/goto | pause/resume/kill |
| 速度控制 | scale 属性 | timeScale 方法 |
| 循环控制 | play(loop) | repeat(count) |
| 链式调用 | to/from/addLabel | to/from/go/duration 等 |
注意事项
内存管理:不再使用时调用 destroy() 方法销毁 TimeLine 实例
避免重复播放:在调用 play() 前先调用 stop() 或 destroy()
标签命名:使用有意义的标签名称,便于维护
性能优化:大量动画时考虑对象池,避免频繁创建销毁 TimeLine
时间单位:TimeLine 中所有时间单位均为毫秒(ms)
目标对象引用:确保动画期间目标对象不被销毁
与 Tween 配合:TimeLine 适合编排复杂序列,Tween 适合简单单一动画
按钮点击区域:使用 drawRect 创建按钮时,必须调用 size(width, height) 设置点击区域,否则无法触发事件
let btn = new Laya.Sprite();
btn.graphics.drawRect(0, 0, 100, 40, "#FF0000");
btn.size(100, 40); // 必须设置,否则无法触发点击事件



