最新文章
Canvas复杂动画开发:从原理到小程序应用
requestAnimationFrame// Canvas动画基础框架
class CanvasAnimation {
constructor(canvas) {
this.canvas = canvas;
this.ctx = canvas.getContext('2d');
this.animationId = null;
this.isAnimating = false;
}
// 动画主循环
animate() {
if (!this.isAnimating) return;
// 清除上一帧
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
// 更新状态
this.update();
// 绘制当前帧
this.draw();
// 继续下一帧
this.animationId = requestAnimationFrame(() => this.animate());
}
// 更新逻辑(由子类实现)
update() {}
// 绘制逻辑(由子类实现)
draw() {}
}// 粒子系统实现
class ParticleSystem {
constructor(canvas, particleCount = 500) {
this.canvas = canvas;
this.ctx = canvas.getContext('2d');
this.particles = [];
this.initParticles(particleCount);
}
initParticles(count) {
for (let i = 0; i < count; i++) {
this.particles.push({
x: Math.random() * this.canvas.width,
y: Math.random() * this.canvas.height,
vx: (Math.random() - 0.5) * 2,
vy: (Math.random() - 0.5) * 2,
radius: Math.random() * 3 + 1,
color: `hsl(${Math.random() * 360}, 100%, 70%)`
});
}
}
update() {
this.particles.forEach(particle => {
// 边界检测
if (particle.x <= 0 || particle.x >= this.canvas.width) particle.vx *= -1;
if (particle.y <= 0 || particle.y >= this.canvas.height) particle.vy *= -1;
// 更新位置
particle.x += particle.vx;
particle.y += particle.vy;
});
}
draw() {
this.particles.forEach(particle => {
this.ctx.beginPath();
this.ctx.arc(particle.x, particle.y, particle.radius, 0, Math.PI * 2);
this.ctx.fillStyle = particle.color;
this.ctx.fill();
});
}
}// 简化的物理动画示例
class PhysicsAnimation {
constructor(canvas) {
this.canvas = canvas;
this.ctx = canvas.getContext('2d');
this.objects = [];
this.gravity = 0.1;
this.friction = 0.99;
}
addObject(obj) {
this.objects.push({
...obj,
vx: 0,
vy: 0,
ax: 0,
ay: this.gravity
});
}
update() {
this.objects.forEach(obj => {
// 应用加速度
obj.vx += obj.ax;
obj.vy += obj.ay;
// 应用摩擦力
obj.vx *= this.friction;
obj.vy *= this.friction;
// 更新位置
obj.x += obj.vx;
obj.y += obj.vy;
// 边界碰撞检测
if (obj.y + obj.height > this.canvas.height) {
obj.y = this.canvas.height - obj.height;
obj.vy *= -0.8; // 能量损失
}
});
}
}// 微信小程序Canvas动画示例
Page({
data: {
canvasWidth: 300,
canvasHeight: 300
},
onReady() {
this.initCanvas();
this.startAnimation();
},
initCanvas() {
// 创建Canvas上下文
this.ctx = wx.createCanvasContext('myCanvas');
this.angle = 0;
},
startAnimation() {
const drawFrame = () => {
// 清除画布
this.ctx.clearRect(0, 0, this.data.canvasWidth, this.data.canvasHeight);
// 绘制旋转矩形
this.ctx.save();
this.ctx.translate(150, 150);
this.ctx.rotate(this.angle * Math.PI / 180);
this.ctx.fillStyle = '#1aad19';
this.ctx.fillRect(-50, -50, 100, 100);
this.ctx.restore();
// 更新角度
this.angle = (this.angle + 2) % 360;
// 绘制到画布
this.ctx.draw();
// 继续动画循环
this.animationFrame = requestAnimationFrame(drawFrame);
};
drawFrame();
},
onUnload() {
// 清理资源
if (this.animationFrame) {
cancelAnimationFrame(this.animationFrame);
}
}
});// 动态图表实现
class AnimatedChart {
constructor(canvas, data) {
this.canvas = canvas;
this.ctx = canvas.getContext('2d');
this.data = data;
this.animationProgress = 0;
}
drawBarChart() {
const barWidth = this.canvas.width / this.data.length * 0.8;
const maxValue = Math.max(...this.data);
const scale = this.canvas.height * 0.8 / maxValue;
this.data.forEach((value, index) => {
const x = index * (this.canvas.width / this.data.length);
const height = value * scale * this.animationProgress;
const y = this.canvas.height - height;
// 渐变效果
const gradient = this.ctx.createLinearGradient(x, y, x, this.canvas.height);
gradient.addColorStop(0, '#4facfe');
gradient.addColorStop(1, '#00f2fe');
this.ctx.fillStyle = gradient;
this.ctx.fillRect(x + 10, y, barWidth, height);
});
}
animate() {
if (this.animationProgress < 1) {
this.animationProgress += 0.02;
this.draw();
requestAnimationFrame(() => this.animate());
}
}
}// 游戏角色动画类
class GameCharacter {
constructor(canvas, spriteSheet) {
this.canvas = canvas;
this.ctx = canvas.getContext('2d');
this.spriteSheet = spriteSheet;
this.currentFrame = 0;
this.frameCount = 8;
this.animationSpeed = 100; // ms per frame
this.lastUpdate = Date.now();
}
update() {
const now = Date.now();
if (now - this.lastUpdate > this.animationSpeed) {
this.currentFrame = (this.currentFrame + 1) % this.frameCount;
this.lastUpdate = now;
}
}
draw(x, y) {
const frameWidth = this.spriteSheet.width / this.frameCount;
const frameHeight = this.spriteSheet.height;
this.ctx.drawImage(
this.spriteSheet,
this.currentFrame * frameWidth, 0, frameWidth, frameHeight,
x, y, frameWidth, frameHeight
);
}
}












冀公网安备