1. 动画原理与基础概念

1.1 动画原理

动画是通过快速连续显示静态图像来创造运动错觉的技术:

// 动画基础概念演示
class AnimationConcepts {
    constructor(canvas) {
        this.canvas = canvas;
        this.ctx = canvas.getContext('2d');
        this.frameCount = 0;
        this.startTime = performance.now();
    }
    
    // 基础动画循环
    basicAnimationLoop() {
        // 清除画布
        this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
        
        // 计算时间
        const currentTime = performance.now();
        const deltaTime = currentTime - this.startTime;
        
        // 简单的移动动画
        const x = (deltaTime * 0.1) % this.canvas.width;
        const y = this.canvas.height / 2;
        
        // 绘制移动的圆
        this.ctx.fillStyle = 'red';
        this.ctx.beginPath();
        this.ctx.arc(x, y, 20, 0, Math.PI * 2);
        this.ctx.fill();
        
        // 显示帧信息
        this.frameCount++;
        this.ctx.fillStyle = 'black';
        this.ctx.font = '14px Arial';
        this.ctx.fillText(`Frame: ${this.frameCount}`, 10, 20);
        this.ctx.fillText(`Time: ${(deltaTime / 1000).toFixed(2)}s`, 10, 40);
        
        // 继续动画
        requestAnimationFrame(() => this.basicAnimationLoop());
    }
    
    // 帧率概念演示
    demonstrateFrameRate() {
        const frameRates = [60, 30, 15, 10];
        let currentFPS = 0;
        let lastFrameTime = 0;
        
        const animate = (currentTime) => {
            const targetInterval = 1000 / frameRates[currentFPS];
            
            if (currentTime - lastFrameTime >= targetInterval) {
                this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
                
                // 绘制不同帧率的动画
                const progress = (currentTime * 0.001) % 4;
                const x = 100 + progress * 100;
                
                this.ctx.fillStyle = 'blue';
                this.ctx.beginPath();
                this.ctx.arc(x, 100, 15, 0, Math.PI * 2);
                this.ctx.fill();
                
                // 显示当前帧率
                this.ctx.fillStyle = 'black';
                this.ctx.font = '16px Arial';
                this.ctx.fillText(`Current FPS: ${frameRates[currentFPS]}`, 10, 30);
                
                lastFrameTime = currentTime;
            }
            
            requestAnimationFrame(animate);
        };
        
        // 每3秒切换帧率
        setInterval(() => {
            currentFPS = (currentFPS + 1) % frameRates.length;
        }, 3000);
        
        animate(0);
    }
}

// 使用示例
const canvas = document.getElementById('canvas');
const animationDemo = new AnimationConcepts(canvas);
animationDemo.basicAnimationLoop();

1.2 时间管理

// 时间管理类
class TimeManager {
    constructor() {
        this.startTime = performance.now();
        this.lastFrameTime = this.startTime;
        this.deltaTime = 0;
        this.totalTime = 0;
        this.frameCount = 0;
        this.fps = 0;
        this.fpsUpdateInterval = 1000; // 1秒更新一次FPS
        this.lastFpsUpdate = this.startTime;
        this.framesSinceLastUpdate = 0;
    }
    
    // 更新时间
    update() {
        const currentTime = performance.now();
        
        // 计算增量时间(毫秒)
        this.deltaTime = currentTime - this.lastFrameTime;
        this.lastFrameTime = currentTime;
        
        // 计算总时间
        this.totalTime = currentTime - this.startTime;
        
        // 更新帧计数
        this.frameCount++;
        this.framesSinceLastUpdate++;
        
        // 更新FPS
        if (currentTime - this.lastFpsUpdate >= this.fpsUpdateInterval) {
            this.fps = Math.round((this.framesSinceLastUpdate * 1000) / (currentTime - this.lastFpsUpdate));
            this.lastFpsUpdate = currentTime;
            this.framesSinceLastUpdate = 0;
        }
    }
    
    // 获取增量时间(秒)
    getDeltaTime() {
        return this.deltaTime / 1000;
    }
    
    // 获取总时间(秒)
    getTotalTime() {
        return this.totalTime / 1000;
    }
    
    // 获取FPS
    getFPS() {
        return this.fps;
    }
    
    // 重置计时器
    reset() {
        this.startTime = performance.now();
        this.lastFrameTime = this.startTime;
        this.deltaTime = 0;
        this.totalTime = 0;
        this.frameCount = 0;
        this.fps = 0;
        this.lastFpsUpdate = this.startTime;
        this.framesSinceLastUpdate = 0;
    }
    
    // 暂停/恢复
    pause() {
        this.isPaused = true;
        this.pauseStartTime = performance.now();
    }
    
    resume() {
        if (this.isPaused) {
            const pauseDuration = performance.now() - this.pauseStartTime;
            this.startTime += pauseDuration;
            this.lastFrameTime += pauseDuration;
            this.lastFpsUpdate += pauseDuration;
            this.isPaused = false;
        }
    }
}

// 使用时间管理器的动画示例
const timeManager = new TimeManager();

function timeBasedAnimation() {
    timeManager.update();
    
    const ctx = canvas.getContext('2d');
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    
    // 基于时间的移动(每秒移动100像素)
    const speed = 100; // 像素/秒
    const x = (timeManager.getTotalTime() * speed) % canvas.width;
    
    // 绘制对象
    ctx.fillStyle = 'green';
    ctx.beginPath();
    ctx.arc(x, 150, 20, 0, Math.PI * 2);
    ctx.fill();
    
    // 显示时间信息
    ctx.fillStyle = 'black';
    ctx.font = '14px Arial';
    ctx.fillText(`FPS: ${timeManager.getFPS()}`, 10, 20);
    ctx.fillText(`Total Time: ${timeManager.getTotalTime().toFixed(2)}s`, 10, 40);
    ctx.fillText(`Delta Time: ${(timeManager.getDeltaTime() * 1000).toFixed(2)}ms`, 10, 60);
    
    requestAnimationFrame(timeBasedAnimation);
}

timeBasedAnimation();

2. requestAnimationFrame详解

2.1 requestAnimationFrame基础

// requestAnimationFrame详细使用
class AnimationFrameManager {
    constructor() {
        this.animationId = null;
        this.isRunning = false;
        this.callbacks = [];
    }
    
    // 添加动画回调
    addCallback(callback, priority = 0) {
        this.callbacks.push({ callback, priority });
        this.callbacks.sort((a, b) => b.priority - a.priority);
    }
    
    // 移除动画回调
    removeCallback(callback) {
        this.callbacks = this.callbacks.filter(item => item.callback !== callback);
    }
    
    // 开始动画循环
    start() {
        if (!this.isRunning) {
            this.isRunning = true;
            this.animate();
        }
    }
    
    // 停止动画循环
    stop() {
        if (this.isRunning) {
            this.isRunning = false;
            if (this.animationId) {
                cancelAnimationFrame(this.animationId);
                this.animationId = null;
            }
        }
    }
    
    // 动画循环
    animate(timestamp) {
        if (!this.isRunning) return;
        
        // 执行所有回调
        this.callbacks.forEach(({ callback }) => {
            try {
                callback(timestamp);
            } catch (error) {
                console.error('Animation callback error:', error);
            }
        });
        
        // 请求下一帧
        this.animationId = requestAnimationFrame((ts) => this.animate(ts));
    }
    
    // 单次动画帧
    nextFrame(callback) {
        requestAnimationFrame(callback);
    }
    
    // 延迟动画帧
    delayedFrame(callback, frames = 1) {
        if (frames <= 1) {
            requestAnimationFrame(callback);
        } else {
            requestAnimationFrame(() => {
                this.delayedFrame(callback, frames - 1);
            });
        }
    }
}

// 使用动画帧管理器
const frameManager = new AnimationFrameManager();

// 添加多个动画
frameManager.addCallback((timestamp) => {
    // 高优先级动画:清除画布
    const ctx = canvas.getContext('2d');
    ctx.clearRect(0, 0, canvas.width, canvas.height);
}, 100);

frameManager.addCallback((timestamp) => {
    // 中优先级动画:绘制背景
    const ctx = canvas.getContext('2d');
    const gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
    gradient.addColorStop(0, 'lightblue');
    gradient.addColorStop(1, 'lightgreen');
    ctx.fillStyle = gradient;
    ctx.fillRect(0, 0, canvas.width, canvas.height);
}, 50);

frameManager.addCallback((timestamp) => {
    // 低优先级动画:绘制移动对象
    const ctx = canvas.getContext('2d');
    const x = (timestamp * 0.1) % canvas.width;
    const y = Math.sin(timestamp * 0.005) * 50 + canvas.height / 2;
    
    ctx.fillStyle = 'red';
    ctx.beginPath();
    ctx.arc(x, y, 15, 0, Math.PI * 2);
    ctx.fill();
}, 10);

frameManager.start();

2.2 帧率控制

// 帧率控制类
class FrameRateController {
    constructor(targetFPS = 60) {
        this.targetFPS = targetFPS;
        this.targetInterval = 1000 / targetFPS;
        this.lastFrameTime = 0;
        this.accumulator = 0;
        this.maxDeltaTime = 1000 / 20; // 最大增量时间(20 FPS)
    }
    
    // 设置目标帧率
    setTargetFPS(fps) {
        this.targetFPS = fps;
        this.targetInterval = 1000 / fps;
    }
    
    // 检查是否应该渲染帧
    shouldRender(currentTime) {
        if (currentTime - this.lastFrameTime >= this.targetInterval) {
            this.lastFrameTime = currentTime;
            return true;
        }
        return false;
    }
    
    // 固定时间步长更新
    fixedTimeStep(currentTime, updateCallback, renderCallback) {
        const deltaTime = Math.min(currentTime - this.lastFrameTime, this.maxDeltaTime);
        this.lastFrameTime = currentTime;
        this.accumulator += deltaTime;
        
        // 固定时间步长更新
        while (this.accumulator >= this.targetInterval) {
            updateCallback(this.targetInterval);
            this.accumulator -= this.targetInterval;
        }
        
        // 渲染(可以插值)
        const interpolation = this.accumulator / this.targetInterval;
        renderCallback(interpolation);
    }
    
    // 自适应帧率
    adaptiveFrameRate(currentTime, callback) {
        const deltaTime = currentTime - this.lastFrameTime;
        
        if (deltaTime >= this.targetInterval) {
            // 计算实际帧率
            const actualFPS = 1000 / deltaTime;
            
            // 如果帧率过低,降低目标帧率
            if (actualFPS < this.targetFPS * 0.8) {
                this.setTargetFPS(Math.max(30, this.targetFPS - 5));
            }
            // 如果帧率稳定,尝试提高目标帧率
            else if (actualFPS > this.targetFPS * 1.1) {
                this.setTargetFPS(Math.min(60, this.targetFPS + 5));
            }
            
            this.lastFrameTime = currentTime;
            callback(deltaTime);
        }
    }
}

// 使用帧率控制器
const frameController = new FrameRateController(30); // 30 FPS

// 游戏对象
const gameObject = {
    x: 0,
    y: 200,
    vx: 100, // 像素/秒
    vy: 0,
    previousX: 0,
    previousY: 200
};

// 更新函数
function updateGame(deltaTime) {
    gameObject.previousX = gameObject.x;
    gameObject.previousY = gameObject.y;
    
    gameObject.x += gameObject.vx * (deltaTime / 1000);
    
    // 边界检测
    if (gameObject.x > canvas.width) {
        gameObject.x = 0;
    }
}

// 渲染函数(带插值)
function renderGame(interpolation) {
    const ctx = canvas.getContext('2d');
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    
    // 插值位置
    const renderX = gameObject.previousX + (gameObject.x - gameObject.previousX) * interpolation;
    const renderY = gameObject.previousY + (gameObject.y - gameObject.previousY) * interpolation;
    
    // 绘制对象
    ctx.fillStyle = 'blue';
    ctx.beginPath();
    ctx.arc(renderX, renderY, 20, 0, Math.PI * 2);
    ctx.fill();
    
    // 显示信息
    ctx.fillStyle = 'black';
    ctx.font = '14px Arial';
    ctx.fillText(`Target FPS: ${frameController.targetFPS}`, 10, 20);
    ctx.fillText(`Interpolation: ${interpolation.toFixed(3)}`, 10, 40);
}

// 主循环
function gameLoop(timestamp) {
    frameController.fixedTimeStep(timestamp, updateGame, renderGame);
    requestAnimationFrame(gameLoop);
}

gameLoop(0);

3. 动画状态管理

3.1 动画状态机

// 动画状态机
class AnimationStateMachine {
    constructor() {
        this.states = new Map();
        this.currentState = null;
        this.previousState = null;
        this.stateData = {};
    }
    
    // 添加状态
    addState(name, config) {
        this.states.set(name, {
            enter: config.enter || (() => {}),
            update: config.update || (() => {}),
            exit: config.exit || (() => {}),
            transitions: config.transitions || {}
        });
    }
    
    // 设置初始状态
    setState(stateName, data = {}) {
        if (this.currentState) {
            this.previousState = this.currentState;
            const currentStateConfig = this.states.get(this.currentState);
            if (currentStateConfig) {
                currentStateConfig.exit(this.stateData);
            }
        }
        
        this.currentState = stateName;
        this.stateData = { ...data };
        
        const newStateConfig = this.states.get(stateName);
        if (newStateConfig) {
            newStateConfig.enter(this.stateData);
        }
    }
    
    // 更新当前状态
    update(deltaTime) {
        if (this.currentState) {
            const stateConfig = this.states.get(this.currentState);
            if (stateConfig) {
                stateConfig.update(deltaTime, this.stateData);
                
                // 检查状态转换
                for (const [condition, nextState] of Object.entries(stateConfig.transitions)) {
                    if (this.checkCondition(condition, this.stateData)) {
                        this.setState(nextState);
                        break;
                    }
                }
            }
        }
    }
    
    // 检查转换条件
    checkCondition(condition, data) {
        if (typeof condition === 'function') {
            return condition(data);
        }
        if (typeof condition === 'string') {
            return data[condition];
        }
        return false;
    }
    
    // 获取当前状态
    getCurrentState() {
        return this.currentState;
    }
    
    // 获取状态数据
    getStateData() {
        return this.stateData;
    }
}

// 动画角色类
class AnimatedCharacter {
    constructor(x, y) {
        this.x = x;
        this.y = y;
        this.vx = 0;
        this.vy = 0;
        this.speed = 100;
        this.animationTime = 0;
        
        // 创建状态机
        this.stateMachine = new AnimationStateMachine();
        
        // 定义状态
        this.setupStates();
        
        // 设置初始状态
        this.stateMachine.setState('idle');
    }
    
    setupStates() {
        // 空闲状态
        this.stateMachine.addState('idle', {
            enter: (data) => {
                this.vx = 0;
                this.vy = 0;
                data.animationPhase = 0;
            },
            update: (deltaTime, data) => {
                data.animationPhase += deltaTime * 0.003;
                
                // 检查是否开始移动
                if (Math.abs(this.vx) > 0 || Math.abs(this.vy) > 0) {
                    data.shouldWalk = true;
                }
            },
            transitions: {
                'shouldWalk': 'walking'
            }
        });
        
        // 行走状态
        this.stateMachine.addState('walking', {
            enter: (data) => {
                data.animationPhase = 0;
                data.shouldWalk = false;
            },
            update: (deltaTime, data) => {
                data.animationPhase += deltaTime * 0.01;
                
                // 更新位置
                this.x += this.vx * deltaTime / 1000;
                this.y += this.vy * deltaTime / 1000;
                
                // 检查是否停止移动
                if (Math.abs(this.vx) < 0.1 && Math.abs(this.vy) < 0.1) {
                    data.shouldIdle = true;
                }
                
                // 检查是否开始跳跃
                if (data.shouldJump) {
                    data.shouldJump = false;
                    data.jumpStarted = true;
                }
            },
            transitions: {
                'shouldIdle': 'idle',
                'jumpStarted': 'jumping'
            }
        });
        
        // 跳跃状态
        this.stateMachine.addState('jumping', {
            enter: (data) => {
                data.jumpStarted = false;
                data.jumpTime = 0;
                data.jumpHeight = 0;
                data.maxJumpHeight = 50;
            },
            update: (deltaTime, data) => {
                data.jumpTime += deltaTime;
                
                // 跳跃动画(简单的抛物线)
                const progress = data.jumpTime / 500; // 500ms跳跃时间
                if (progress < 1) {
                    data.jumpHeight = Math.sin(progress * Math.PI) * data.maxJumpHeight;
                } else {
                    data.jumpCompleted = true;
                }
                
                // 继续水平移动
                this.x += this.vx * deltaTime / 1000;
            },
            transitions: {
                'jumpCompleted': 'walking'
            }
        });
    }
    
    // 设置移动速度
    setVelocity(vx, vy) {
        this.vx = vx;
        this.vy = vy;
    }
    
    // 跳跃
    jump() {
        const data = this.stateMachine.getStateData();
        data.shouldJump = true;
    }
    
    // 更新
    update(deltaTime) {
        this.animationTime += deltaTime;
        this.stateMachine.update(deltaTime);
    }
    
    // 渲染
    render(ctx) {
        const state = this.stateMachine.getCurrentState();
        const data = this.stateMachine.getStateData();
        
        ctx.save();
        ctx.translate(this.x, this.y - (data.jumpHeight || 0));
        
        // 根据状态绘制不同的动画
        switch (state) {
            case 'idle':
                this.renderIdle(ctx, data);
                break;
            case 'walking':
                this.renderWalking(ctx, data);
                break;
            case 'jumping':
                this.renderJumping(ctx, data);
                break;
        }
        
        ctx.restore();
        
        // 显示状态信息
        ctx.fillStyle = 'black';
        ctx.font = '12px Arial';
        ctx.fillText(`State: ${state}`, this.x - 20, this.y - 60);
    }
    
    renderIdle(ctx, data) {
        // 简单的呼吸动画
        const scale = 1 + Math.sin(data.animationPhase) * 0.05;
        ctx.scale(scale, scale);
        
        ctx.fillStyle = 'blue';
        ctx.fillRect(-15, -15, 30, 30);
    }
    
    renderWalking(ctx, data) {
        // 行走动画(左右摆动)
        const sway = Math.sin(data.animationPhase) * 3;
        ctx.translate(sway, 0);
        
        ctx.fillStyle = 'green';
        ctx.fillRect(-15, -15, 30, 30);
        
        // 腿部动画
        ctx.fillStyle = 'darkgreen';
        const legOffset = Math.sin(data.animationPhase) * 5;
        ctx.fillRect(-10 + legOffset, 15, 8, 10);
        ctx.fillRect(2 - legOffset, 15, 8, 10);
    }
    
    renderJumping(ctx, data) {
        // 跳跃姿态
        ctx.fillStyle = 'orange';
        ctx.fillRect(-15, -15, 30, 30);
        
        // 手臂向上
        ctx.fillStyle = 'darkorange';
        ctx.fillRect(-20, -10, 8, 15);
        ctx.fillRect(12, -10, 8, 15);
    }
}

// 使用动画角色
const character = new AnimatedCharacter(200, 300);

// 键盘控制
const keys = {};

window.addEventListener('keydown', (e) => {
    keys[e.key] = true;
});

window.addEventListener('keyup', (e) => {
    keys[e.key] = false;
});

// 主循环
function characterAnimationLoop(timestamp) {
    const deltaTime = 16; // 假设60FPS
    
    // 处理输入
    let vx = 0, vy = 0;
    if (keys['ArrowLeft'] || keys['a']) vx = -character.speed;
    if (keys['ArrowRight'] || keys['d']) vx = character.speed;
    if (keys['ArrowUp'] || keys['w']) vy = -character.speed;
    if (keys['ArrowDown'] || keys['s']) vy = character.speed;
    if (keys[' ']) character.jump();
    
    character.setVelocity(vx, vy);
    
    // 更新和渲染
    character.update(deltaTime);
    
    const ctx = canvas.getContext('2d');
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    character.render(ctx);
    
    requestAnimationFrame(characterAnimationLoop);
}

characterAnimationLoop();

3.2 动画队列系统

// 动画队列系统
class AnimationQueue {
    constructor() {
        this.animations = [];
        this.currentAnimation = null;
        this.isPlaying = false;
    }
    
    // 添加动画到队列
    add(animation) {
        this.animations.push(animation);
        if (!this.isPlaying) {
            this.playNext();
        }
        return this;
    }
    
    // 插入动画到队列前面
    prepend(animation) {
        this.animations.unshift(animation);
        return this;
    }
    
    // 播放下一个动画
    playNext() {
        if (this.animations.length > 0) {
            this.currentAnimation = this.animations.shift();
            this.isPlaying = true;
            
            if (this.currentAnimation.onStart) {
                this.currentAnimation.onStart();
            }
        } else {
            this.isPlaying = false;
            this.currentAnimation = null;
        }
    }
    
    // 更新当前动画
    update(deltaTime) {
        if (this.currentAnimation) {
            const finished = this.currentAnimation.update(deltaTime);
            
            if (finished) {
                if (this.currentAnimation.onComplete) {
                    this.currentAnimation.onComplete();
                }
                this.playNext();
            }
        }
    }
    
    // 清空队列
    clear() {
        this.animations = [];
        if (this.currentAnimation && this.currentAnimation.onCancel) {
            this.currentAnimation.onCancel();
        }
        this.currentAnimation = null;
        this.isPlaying = false;
    }
    
    // 暂停/恢复
    pause() {
        if (this.currentAnimation && this.currentAnimation.pause) {
            this.currentAnimation.pause();
        }
    }
    
    resume() {
        if (this.currentAnimation && this.currentAnimation.resume) {
            this.currentAnimation.resume();
        }
    }
    
    // 获取队列长度
    getQueueLength() {
        return this.animations.length + (this.currentAnimation ? 1 : 0);
    }
}

// 基础动画类
class BaseAnimation {
    constructor(duration, easing = null) {
        this.duration = duration;
        this.easing = easing || this.linearEasing;
        this.startTime = null;
        this.isPaused = false;
        this.pausedTime = 0;
    }
    
    // 开始动画
    start() {
        this.startTime = performance.now();
    }
    
    // 更新动画
    update(deltaTime) {
        if (!this.startTime) {
            this.start();
        }
        
        if (this.isPaused) {
            return false;
        }
        
        const currentTime = performance.now();
        const elapsed = currentTime - this.startTime - this.pausedTime;
        const progress = Math.min(elapsed / this.duration, 1);
        const easedProgress = this.easing(progress);
        
        this.onUpdate(easedProgress, progress);
        
        return progress >= 1;
    }
    
    // 暂停
    pause() {
        if (!this.isPaused) {
            this.isPaused = true;
            this.pauseStartTime = performance.now();
        }
    }
    
    // 恢复
    resume() {
        if (this.isPaused) {
            this.pausedTime += performance.now() - this.pauseStartTime;
            this.isPaused = false;
        }
    }
    
    // 线性缓动
    linearEasing(t) {
        return t;
    }
    
    // 子类需要实现的方法
    onUpdate(easedProgress, progress) {
        // 子类实现
    }
}

// 移动动画
class MoveAnimation extends BaseAnimation {
    constructor(target, fromX, fromY, toX, toY, duration, easing) {
        super(duration, easing);
        this.target = target;
        this.fromX = fromX;
        this.fromY = fromY;
        this.toX = toX;
        this.toY = toY;
    }
    
    onUpdate(easedProgress) {
        this.target.x = this.fromX + (this.toX - this.fromX) * easedProgress;
        this.target.y = this.fromY + (this.toY - this.fromY) * easedProgress;
    }
}

// 缩放动画
class ScaleAnimation extends BaseAnimation {
    constructor(target, fromScale, toScale, duration, easing) {
        super(duration, easing);
        this.target = target;
        this.fromScale = fromScale;
        this.toScale = toScale;
    }
    
    onUpdate(easedProgress) {
        this.target.scale = this.fromScale + (this.toScale - this.fromScale) * easedProgress;
    }
}

// 旋转动画
class RotateAnimation extends BaseAnimation {
    constructor(target, fromRotation, toRotation, duration, easing) {
        super(duration, easing);
        this.target = target;
        this.fromRotation = fromRotation;
        this.toRotation = toRotation;
    }
    
    onUpdate(easedProgress) {
        this.target.rotation = this.fromRotation + (this.toRotation - this.fromRotation) * easedProgress;
    }
}

// 使用动画队列
const animatedObject = {
    x: 100,
    y: 100,
    scale: 1,
    rotation: 0
};

const animationQueue = new AnimationQueue();

// 创建动画序列
animationQueue
    .add(new MoveAnimation(animatedObject, 100, 100, 300, 100, 1000))
    .add(new ScaleAnimation(animatedObject, 1, 1.5, 500))
    .add(new RotateAnimation(animatedObject, 0, Math.PI, 800))
    .add(new MoveAnimation(animatedObject, 300, 100, 100, 300, 1200))
    .add(new ScaleAnimation(animatedObject, 1.5, 1, 500))
    .add(new RotateAnimation(animatedObject, Math.PI, 0, 600));

// 渲染循环
function queueAnimationLoop() {
    animationQueue.update(16);
    
    const ctx = canvas.getContext('2d');
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    
    ctx.save();
    ctx.translate(animatedObject.x, animatedObject.y);
    ctx.rotate(animatedObject.rotation);
    ctx.scale(animatedObject.scale, animatedObject.scale);
    
    ctx.fillStyle = 'purple';
    ctx.fillRect(-25, -25, 50, 50);
    
    ctx.restore();
    
    // 显示队列信息
    ctx.fillStyle = 'black';
    ctx.font = '14px Arial';
    ctx.fillText(`Queue Length: ${animationQueue.getQueueLength()}`, 10, 20);
    ctx.fillText(`Playing: ${animationQueue.isPlaying}`, 10, 40);
    
    requestAnimationFrame(queueAnimationLoop);
}

queueAnimationLoop();

4. 缓动函数与插值

4.1 常用缓动函数

// 缓动函数库
class Easing {
    // 线性
    static linear(t) {
        return t;
    }
    
    // 二次方缓动
    static easeInQuad(t) {
        return t * t;
    }
    
    static easeOutQuad(t) {
        return t * (2 - t);
    }
    
    static easeInOutQuad(t) {
        return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
    }
    
    // 三次方缓动
    static easeInCubic(t) {
        return t * t * t;
    }
    
    static easeOutCubic(t) {
        return (--t) * t * t + 1;
    }
    
    static easeInOutCubic(t) {
        return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
    }
    
    // 四次方缓动
    static easeInQuart(t) {
        return t * t * t * t;
    }
    
    static easeOutQuart(t) {
        return 1 - (--t) * t * t * t;
    }
    
    static easeInOutQuart(t) {
        return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t;
    }
    
    // 正弦缓动
    static easeInSine(t) {
        return 1 - Math.cos(t * Math.PI / 2);
    }
    
    static easeOutSine(t) {
        return Math.sin(t * Math.PI / 2);
    }
    
    static easeInOutSine(t) {
        return -(Math.cos(Math.PI * t) - 1) / 2;
    }
    
    // 指数缓动
    static easeInExpo(t) {
        return t === 0 ? 0 : Math.pow(2, 10 * (t - 1));
    }
    
    static easeOutExpo(t) {
        return t === 1 ? 1 : 1 - Math.pow(2, -10 * t);
    }
    
    static easeInOutExpo(t) {
        if (t === 0) return 0;
        if (t === 1) return 1;
        if (t < 0.5) return Math.pow(2, 20 * t - 10) / 2;
        return (2 - Math.pow(2, -20 * t + 10)) / 2;
    }
    
    // 弹性缓动
    static easeInElastic(t) {
        if (t === 0) return 0;
        if (t === 1) return 1;
        
        const p = 0.3;
        const s = p / 4;
        return -(Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p));
    }
    
    static easeOutElastic(t) {
        if (t === 0) return 0;
        if (t === 1) return 1;
        
        const p = 0.3;
        const s = p / 4;
        return Math.pow(2, -10 * t) * Math.sin((t - s) * (2 * Math.PI) / p) + 1;
    }
    
    static easeInOutElastic(t) {
        if (t === 0) return 0;
        if (t === 1) return 1;
        
        const p = 0.3 * 1.5;
        const s = p / 4;
        
        if (t < 0.5) {
            return -0.5 * (Math.pow(2, 20 * t - 10) * Math.sin((20 * t - 11.125) * (2 * Math.PI) / p));
        }
        return 0.5 * (Math.pow(2, -20 * t + 10) * Math.sin((20 * t - 11.125) * (2 * Math.PI) / p)) + 1;
    }
    
    // 回弹缓动
    static easeInBounce(t) {
        return 1 - Easing.easeOutBounce(1 - t);
    }
    
    static easeOutBounce(t) {
        if (t < 1 / 2.75) {
            return 7.5625 * t * t;
        } else if (t < 2 / 2.75) {
            return 7.5625 * (t -= 1.5 / 2.75) * t + 0.75;
        } else if (t < 2.5 / 2.75) {
            return 7.5625 * (t -= 2.25 / 2.75) * t + 0.9375;
        } else {
            return 7.5625 * (t -= 2.625 / 2.75) * t + 0.984375;
        }
    }
    
    static easeInOutBounce(t) {
        if (t < 0.5) {
            return Easing.easeInBounce(t * 2) * 0.5;
        }
        return Easing.easeOutBounce(t * 2 - 1) * 0.5 + 0.5;
    }
    
    // 超出缓动
    static easeInBack(t, s = 1.70158) {
        return t * t * ((s + 1) * t - s);
    }
    
    static easeOutBack(t, s = 1.70158) {
        return (t = t - 1) * t * ((s + 1) * t + s) + 1;
    }
    
    static easeInOutBack(t, s = 1.70158) {
        if ((t *= 2) < 1) {
            return 0.5 * (t * t * (((s *= 1.525) + 1) * t - s));
        }
        return 0.5 * ((t -= 2) * t * (((s *= 1.525) + 1) * t + s) + 2);
    }
}

// 缓动函数演示
class EasingDemo {
    constructor(canvas) {
        this.canvas = canvas;
        this.ctx = canvas.getContext('2d');
        this.startTime = performance.now();
        this.duration = 2000; // 2秒
        
        // 缓动函数列表
        this.easingFunctions = [
            { name: 'Linear', func: Easing.linear, color: 'red' },
            { name: 'EaseInQuad', func: Easing.easeInQuad, color: 'blue' },
            { name: 'EaseOutQuad', func: Easing.easeOutQuad, color: 'green' },
            { name: 'EaseInOutQuad', func: Easing.easeInOutQuad, color: 'orange' },
            { name: 'EaseInElastic', func: Easing.easeInElastic, color: 'purple' },
            { name: 'EaseOutBounce', func: Easing.easeOutBounce, color: 'brown' }
        ];
    }
    
    animate() {
        const currentTime = performance.now();
        const elapsed = (currentTime - this.startTime) % (this.duration + 1000); // 1秒暂停
        const progress = Math.min(elapsed / this.duration, 1);
        
        this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
        
        // 绘制参考线
        this.drawGrid();
        
        // 绘制每个缓动函数的效果
        this.easingFunctions.forEach((easing, index) => {
            const y = 50 + index * 60;
            const easedProgress = easing.func(progress);
            const x = 50 + easedProgress * 300;
            
            // 绘制轨道
            this.ctx.strokeStyle = 'lightgray';
            this.ctx.lineWidth = 1;
            this.ctx.beginPath();
            this.ctx.moveTo(50, y);
            this.ctx.lineTo(350, y);
            this.ctx.stroke();
            
            // 绘制移动的圆
            this.ctx.fillStyle = easing.color;
            this.ctx.beginPath();
            this.ctx.arc(x, y, 8, 0, Math.PI * 2);
            this.ctx.fill();
            
            // 绘制标签
            this.ctx.fillStyle = 'black';
            this.ctx.font = '12px Arial';
            this.ctx.fillText(easing.name, 360, y + 4);
            
            // 绘制进度值
            this.ctx.fillText(`${easedProgress.toFixed(3)}`, 480, y + 4);
        });
        
        // 绘制总体进度
        this.ctx.fillStyle = 'black';
        this.ctx.font = '16px Arial';
        this.ctx.fillText(`Progress: ${progress.toFixed(3)}`, 50, 30);
        
        requestAnimationFrame(() => this.animate());
    }
    
    drawGrid() {
        this.ctx.strokeStyle = 'lightgray';
        this.ctx.lineWidth = 0.5;
        
        // 垂直线
        for (let x = 50; x <= 350; x += 50) {
            this.ctx.beginPath();
            this.ctx.moveTo(x, 40);
            this.ctx.lineTo(x, this.canvas.height - 20);
            this.ctx.stroke();
        }
    }
}

// 启动缓动演示
const easingDemo = new EasingDemo(canvas);
easingDemo.animate();

4.2 插值技术

”`javascript // 插值工具类 class Interpolation { // 线性插值 static lerp(a, b, t) { return a + (b - a) * t; }

// 向量插值
static lerpVector(v1, v2, t) {
    return {
        x: this.lerp(v1.x, v2.x, t),
        y: this.lerp(v1.y, v2.y, t)
    };
}

// 颜色插值
static lerpColor(color1, color2, t) {
    const rgb1 = this.hexToRgb(color1);
    const rgb2 = this.hexToRgb(color2);

    const r = Math.round(this.lerp(rgb1.r, rgb2.r, t));
    const g = Math.round(this.lerp(rgb1.g, rgb2.g, t));
    const b = Math.round(this.lerp(rgb1.b, rgb2.b, t));

    return `rgb(${r}, ${g}, ${b})`;
}

// 角度插值(考虑最短路径)
static lerpAngle(a1, a2, t) {
    const diff = a2 - a1;
    const shortestAngle = ((diff % (Math.PI * 2)) + (Math.PI * 3)) % (Math.PI * 2) - Math.PI;
    return a1 + shortestAngle * t;
}

// 样条插值
static catmullRom(p0, p1, p2, p3, t) {
    const t2 = t * t;
    const t3 = t2 * t;

    return 0.5 * (
        (2 * p1) +
        (-p0 + p2) * t +
        (2 * p0 - 5 * p1 + 4 * p2 - p3) * t2 +
        (-p0 + 3 * p1 - 3 * p2 + p3) * t3
    );
}

// 贝塞尔插值
static bezier(p0, p1, p2, p3, t) {
    const u = 1 - t;
    const tt = t * t;
    const uu = u * u;
    const uuu = uu * u;
    const ttt = tt * t;

    return uuu * p0 + 3 * uu * t * p1 + 3 * u * tt * p2 + ttt * p3;
}

// 平滑步进
static smoothstep(edge0, edge1, x) {
    const t = Math.max(0, Math.min(1, (x - edge0) / (edge1 - edge0)));
    return t * t * (3 - 2 * t);
}

// 更平滑的步进
static smootherstep(edge0, edge1, x) {
    const t = Math.max(0, Math.min(1, (x - edge0) / (edge1 - edge0)));
    return t * t * t * (t * (t * 6 - 15) + 10);
}

// 十六进制转RGB
static hexToRgb(hex) {
    const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
    return result ? {
        r: parseInt(result[1], 16),
        g: parseInt(result[2], 16),
        b: parseInt(result[3], 16)
    } : null;
}

}

// 插值演示 class InterpolationDemo { constructor(canvas) { this.canvas = canvas; this.ctx = canvas.getContext(‘2d’); this.startTime = performance.now();

    // 控制点
    this.points = [
        { x: 100, y: 200 },
        { x: 200, y: 100 },
        { x: 400, y: 300 },
        { x: 500, y: 150 }
    ];

    // 颜色
    this.colors = ['#ff0000', '#00ff00', '#0000ff', '#ffff00'];
}

animate() {
    const currentTime = performance.now();
    const elapsed = (currentTime - this.startTime) % 4000; // 4秒循环
    const progress = elapsed / 4000;

    this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);

    // 绘制控制点
    this.drawControlPoints();

    // 线性插值演示
    this.drawLinearInterpolation(progress);

    // 样条插值演示
    this.drawSplineInterpolation();

    // 贝塞尔插值演示
    this.drawBezierInterpolation(progress);

    // 颜色插值演示
    this.drawColorInterpolation(progress);

    requestAnimationFrame(() => this.animate());
}

drawControlPoints() {
    this.ctx.fillStyle = 'red';
    this.points.forEach((point, index) => {
        this.ctx.beginPath();
        this.ctx.arc(point.x, point.y, 5, 0, Math.PI * 2);
        this.ctx.fill();

        this.ctx.fillStyle = 'black';
        this.ctx.font = '12px Arial';
        this.ctx.fillText(`P${index}`, point.x + 8, point.y - 8);
        this.ctx.fillStyle = 'red';
    });
}

drawLinearInterpolation(progress) {
    // 在前三个点之间进行线性插值
    const segmentProgress = (progress * 3) % 1;
    const segmentIndex = Math.floor(progress * 3) % 3;

    const p1 = this.points[segmentIndex];
    const p2 = this.points[segmentIndex + 1];

    const interpolated = Interpolation.lerpVector(p1, p2, segmentProgress);

    // 绘制路径
    this.ctx.strokeStyle = 'blue';
    this.ctx.lineWidth = 2;
    this.ctx.beginPath();
    for (let i = 0; i < this.points.length - 1; i++) {
        if (i === 0) {
            this.ctx.moveTo(this.points[i].x, this.points[i].y);
        }
        this.ctx.lineTo(this.points[i + 1].x, this.points[i + 1].y);
    }
    this.ctx.stroke();

    // 绘制插值点
    this.ctx.fillStyle = 'blue';
    this.ctx.beginPath();
    this.ctx.arc(interpolated.x, interpolated.y, 8, 0, Math.PI * 2);
    this.ctx.fill();

    // 标签
    this.ctx.fillStyle = 'black';
    this.ctx.font = '14px Arial';
    this.ctx.fillText('Linear', 10, 50);
}

drawSplineInterpolation() {
    // 绘制Catmull-Rom样条
    this.ctx.strokeStyle = 'green';
    this.ctx.lineWidth = 2;
    this.ctx.beginPath();

    const steps = 100;
    for (let i = 0; i <= steps; i++) {
        const t = i / steps;
        const segmentIndex = Math.floor(t * (this.points.length - 3));
        const localT = (t * (this.points.length - 3)) % 1;

        if (segmentIndex < this.points.length - 3) {
            const p0 = this.points[segmentIndex];
            const p1 = this.points[segmentIndex + 1];
            const p2 = this.points[segmentIndex + 2];
            const p3 = this.points[segmentIndex + 3];

            const x = Interpolation.catmullRom(p0.x, p1.x, p2.x, p3.x, localT);
            const y = Interpolation.catmullRom(p0.y, p1.y, p2.y, p3.y, localT);

            if (i === 0) {
                this.ctx.moveTo(x, y);
            } else {
                this.ctx.lineTo(x, y);
            }
        }
    }
    this.ctx.stroke();

    // 标签
    this.ctx.fillStyle = 'black';
    this.ctx.font = '14px Arial';
    this.ctx.fillText('Catmull-Rom Spline', 10, 70);
}

drawBezierInterpolation(progress) {
    // 使用所有四个点作为贝塞尔控制点
    this.ctx.strokeStyle = 'purple';
    this.ctx.lineWidth = 2;
    this.ctx.beginPath();

    const steps = 100;
    for (let i = 0; i <= steps; i++) {
        const t = i / steps;

        const x = Interpolation.bezier(
            this.points[0].x, this.points[1].x,
            this.points[2].x, this.points[3].x, t
        );
        const y = Interpolation.bezier(
            this.points[0].y, this.points[1].y,
            this.points[2].y, this.points[3].y, t
        );

        if (i === 0) {
            this.ctx.moveTo(x, y);
        } else {
            this.ctx.lineTo(x, y);
        }
    }
    this.ctx.stroke();

    // 绘制当前位置
    const currentX = Interpolation.bezier(
        this.points[0].x, this.points[1].x,
        this.points[2].x, this.points[3].x, progress
    );
    const currentY = Interpolation.bezier(
        this.points[0].y, this.points[1].y,
        this.points[2].y, this.points[3].y, progress
    );

    this.ctx.fillStyle = 'purple';
    this.ctx.beginPath();
    this.ctx.arc(currentX, currentY, 8, 0, Math.PI * 2);
    this.ctx.fill();

    // 标签
    this.ctx.fillStyle = 'black';
    this.ctx.font = '14px Arial';
    this.ctx.fillText('Bezier Curve', 10, 90);
}

drawColorInterpolation(progress) {
    // 颜色插值演示
    const colorIndex = Math.floor(progress * (this.colors.length - 1));
    const localProgress = (progress * (this.colors.length - 1)) % 1;

    const color1 = this.colors[colorIndex];
    const color2 = this.colors[Math.min(colorIndex + 1, this.colors.length - 1)];

    const interpolatedColor = Interpolation.lerpColor(color1, color2, localProgress);

    // 绘制颜色条
    const barY = this.canvas.height - 50;
    const barWidth = 300;
    const barHeight = 20