特效描述:利用HTML5实现 Canvas 卫星碰撞 动画特效。利用HTML5实现Canvas卫星碰撞动画特效
代码结构
1. 引入JS
2. HTML代码
// small particle system with satellites
// standard shim
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function( callback ) {
window.setTimeout(callback, 1000 / 60);
};
})();
// helper functions
function randomMax(max) {
return Math.floor(Math.random() * max);
}
function getParticleColor(transparent) {
var r = (100 + randomMax(155));
var g = (100 + randomMax(155));
var b = (100 + randomMax(155));
if (transparent) {
return 'rgba(' + r + ',' + g + ',' + b + ',' + '0.8)';
} else {
return 'rgb(' + r + ',' + g + ',' + b + ')';
}
}
// dom stuff and fps counter
var canvas = document.getElementById('mainCanvas');
var fpsOut = document.getElementById('fps');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var ctx = canvas.getContext('2d');
var fps = 0, now, lastUpdate = (new Date())*1 - 1, fpsFilter = 50;
// globals
var particleBackground = 'rgba(36, 28, 31, 0.8)',
minParticleSize = 15,
particleSizeDelta = 10,
minOrbitRadius = minParticleSize + particleSizeDelta,
maxSatOrbitRadius = minOrbitRadius + 15,
minSatSize = 3,
satSizeDelta = 5,
maxParticleSpeed = 5,
maxSatOrbitSpeed = 0.07;
numParticles = 10,
numSat = 4;
var Satellite = function (orbit) {
this.r = minSatSize + randomMax(satSizeDelta);
this.orbit = orbit;
this.ax = 2 * Math.PI * Math.random();
this.ay = 2 * Math.PI * Math.random();
this.dx = maxSatOrbitSpeed * Math.random();
this.dy = maxSatOrbitSpeed * Math.random();
this.color = getParticleColor();
this.x = 0;
this.y = 0;
this.forward = false;
};
var Particle = function () {
var particleOffset = minParticleSize + particleSizeDelta + 2 * maxParticleSpeed;
this.x = Math.round(particleOffset + Math.random() * (canvas.width - 2 * particleOffset));
this.y = Math.round(particleOffset + Math.random() * (canvas.height - 2 * particleOffset));
this.dx = maxParticleSpeed * Math.random() * (Math.random() > 0.5 ? 1 : -1);
this.dy = maxParticleSpeed * Math.random() * (Math.random() > 0.5 ? 1 : -1);
this.r = minParticleSize + randomMax(particleSizeDelta);
this.color = getParticleColor(true);
this.createSat();
};
Particle.prototype.draw = function (id) {
for (var l = 0; l < particleSystem.particles.length; l++) {
if (l !== id && this.colidesWith(particleSystem.particles[l])) {
var newDx = (Math.abs(this.dx) + Math.abs(particleSystem.particles[l].dx)) / 2;
var newDy = (Math.abs(this.dy) + Math.abs(particleSystem.particles[l].dy)) / 2;
this.dx = (this.dx > 0 ? -1 : 1) * newDx;
this.dy = (this.dy > 0 ? -1 : 1) * newDy;
particleSystem.particles[l].dx = (particleSystem.particles[l].dx > 0 ? -1 : 1) * newDx;
particleSystem.particles[l].dy = (particleSystem.particles[l].dy > 0 ? -1 : 1) * newDy;
}
}
this.x += this.dx;
this.y += this.dy;
if (this.x + this.dx + 2 * this.r < 0) {
this.x = canvas.width;
}
if (this.x + this.dx - 2 * this.r > canvas.width) {
this.x = 0;
}
if (this.y + this.dy + 2 * this.r < 0) {
this.y = canvas.height;
}
if (this.y + this.dy - 2 * this.r > canvas.height) {
this.y = 0;
}
for (var j = 0; j < this.satellites.length; j++) {
this.satellites[j].ax += this.satellites[j].dx;
this.satellites[j].ay += this.satellites[j].dy;
this.satellites[j].x = Math.sin(this.satellites[j].ax) * this.satellites[j].orbit;
this.satellites[j].y = Math.cos(this.satellites[j].ay) * this.satellites[j].orbit;
if (Math.cos(this.satellites[j].ax) < 0 || Math.sin(this.satellites[j].ay) < 0) {
this.satellites[j].forward = true;
} else {
this.satellites[j].forward = false;
this.drawSat(this.satellites[j]);
}
}
ctx.beginPath();
var fillStyle = ctx.createRadialGradient(this.x, this.y, this.r * 0.3, this.x, this.y, this.r);
fillStyle.addColorStop(0, this.color);
fillStyle.addColorStop(0.3, particleBackground);
fillStyle.addColorStop(0.6, particleBackground);
fillStyle.addColorStop(0.7, this.color);
fillStyle.addColorStop(0.8, particleBackground);
fillStyle.addColorStop(0.9, particleBackground);
fillStyle.addColorStop(1, this.color);
ctx.fillStyle = fillStyle;
ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2);
ctx.fill();
for (var k = 0; k < this.satellites.length; k++) {
var sat = this.satellites[k];
if (sat.forward) {
this.drawSat(sat);
}
}
};
Particle.prototype.createSat = function () {
this.satellites = [];
for (var i = 0; i < numSat; i++) {
this.satellites.push(new Satellite(minOrbitRadius + maxSatOrbitRadius * Math.random()));
}
};
Particle.prototype.drawSat = function (sat) {
ctx.beginPath();
var fillStyleSat = ctx.createRadialGradient(this.x + sat.x, this.y + sat.y, sat.r * 0.3, this.x + sat.x, this.y + sat.y, sat.r);
fillStyleSat.addColorStop(0, sat.color);
fillStyleSat.addColorStop(1, particleBackground);
ctx.fillStyle = fillStyleSat;
ctx.arc(this.x + sat.x, this.y + sat.y, sat.r, 0, Math.PI * 2);
ctx.fill();
};
Particle.prototype.colidesWith = function (particle) {
var distance = Math.sqrt(Math.pow(this.x - particle.x, 2) + Math.pow(this.y - particle.y, 2));
return distance <= (particle.r + this.r);
};
var ParticleSystem = function () {
this.particles = [];
for (var i = 0; i < numParticles; i++) {
this.particles.push(new Particle());
}
};
ParticleSystem.prototype.draw = function () {
for (var i = 0; i < this.particles.length; i++) {
this.particles[i].draw(i);
}
};
var gui = new dat.GUI();
gui.add(window, 'numParticles').min(1).max(50).step(1).name('Num. Particles').onFinishChange(function(){
particleSystem = new ParticleSystem();
});
gui.add(window, 'maxParticleSpeed').min(1).max(20).step(1).onFinishChange(function(){
for (var i = 0; i < particleSystem.particles.length; i++) {
particleSystem.particles[i].dx = maxParticleSpeed * Math.random() * (Math.random() > 0.5 ? 1 : -1);
particleSystem.particles[i].dy = maxParticleSpeed * Math.random() * (Math.random() > 0.5 ? 1 : -1);
}
});
gui.add(window, 'numSat').min(1).max(10).step(1).name('Satellite number').onFinishChange(function(){
for (var i = 0; i < particleSystem.particles.length; i++) {
particleSystem.particles[i].createSat();
}
});
gui.add(window, 'maxSatOrbitSpeed').min(0.01).max(0.9).step(0.005).name('Max sat speed').onFinishChange(function(){
for (var i = 0; i < particleSystem.particles.length; i++) {
particleSystem.particles[i].createSat();
}
});
var particleSystem = new ParticleSystem();
window.onresize = function() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
particleSystem = new ParticleSystem();
};
(function animloop(){
requestAnimFrame(animloop);
ctx.clearRect(0, 0, canvas.width, canvas.height);
particleSystem.draw();
var thisFrameFPS = 1000 / ((now=new Date()) - lastUpdate);
fps += (thisFrameFPS - fps) / fpsFilter;
lastUpdate = now;
})();
setInterval(function(){
fpsOut.innerHTML = fps.toFixed(1) + " fps";
}, 1000);