Heim > Web-Frontend > js-Tutorial > JS+Canvas erzielt Regen- und Schneeeffekte

JS+Canvas erzielt Regen- und Schneeeffekte

高洛峰
Freigeben: 2017-02-08 15:03:04
Original
2119 Leute haben es durchsucht

Ich habe kürzlich an einem Projekt gearbeitet, bei dem es darum ging, die Animationseffekte von Regen und leichtem Schnee zu realisieren. Deshalb habe ich hier eine Tropfenkomponente erstellt, um den üblichen Effekt fallender Objekte auf der Leinwand zu zeigen. Bevor ich Ihnen den Text vorstelle, möchte ich Ihnen die Darstellungen zeigen:

Zeigen Sie die Darstellungen:

Es regnet und schneit

JS+Canvas 实现下雨下雪效果

Der Effekt scheint gut zu sein. Im Vergleich zur Verwendung erstellter Dom-Elemente zum Erstellen von Positionierungsanimationen für mehrere Objekte ist die Verwendung von Canvas einfacher und schneller und die Leistung ist besser

Rufen Sie den Code auf

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
#canvas{
width:100%;
height: 100%;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script src="canvasDrop.js"></script>
<script>
canvasDrop.init({
type: "rain", // drop类型,有rain or snow
speed : [0.4,2.5], //速度范围
size_range: [0.5,1.5],//大小半径范围
hasBounce: true, //是否有反弹效果or false,
wind_direction: -105 //角度
hasGravity: true //是否有重力考虑
});
</script>
</body>
</html>
Nach dem Login kopieren

Okay, erklären wir zunächst das einfache Implementierungsprinzip. Definieren Sie zunächst einige globale Variablen, die wir verwenden werden, z. B. Windrichtungswinkel, Wahrscheinlichkeit, Objektdaten usw.

Definieren Sie globale Variablen

//定义两个对象数据
//分别是drops下落物体对象
//和反弹物体bounces对象
var drops = [], bounces = [];
//这里设定重力加速度为0.2/一帧
var gravity = 0.2;
var speed_x_x, //横向加速度
speed_x_y, //纵向加速度
wind_anger; //风向
//画布的像素宽高
var canvasWidth,
canvasHeight;
//创建drop的几率
var drop_chance;
//配置对象
var OPTS;
//判断是否有requestAnimationFrame方法,如果有则使用,没有则大约一秒30帧
window.requestAnimFrame =
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 30);
};
Nach dem Login kopieren

Kernobjekte definieren

Als nächstes müssen wir mehrere wichtige Objekte definieren, insgesamt nur drei. In der gesamten Drop-Komponente sind folgende definiert :

Vektorgeschwindigkeitsobjekt mit horizontalem x und vertikalem y. Die Geschwindigkeitseinheit ist: V = Verschiebungspixel/Frame

Das Verständnis des Vektorobjekts ist ebenfalls sehr einfach und grob , Aufzeichnung der Geschwindigkeit des fallenden Objekts/V

var Vector = function(x, y) {
//私有属性 横向速度x ,纵向速度y
this.x = x || 0;
this.y = y || 0;
};
//公有方法- add : 速度改变函数,根据参数对速度进行增加
//由于业务需求,考虑的都是下落加速的情况,故没有减速的,后期可拓展
/*
* @param v object || string 
*/
Vector.prototype.add = function(v) {
if (v.x != null && v.y != null) {
this.x += v.x;
this.y += v.y;
} else {
this.x += v;
this.y += v;
}
return this;
};
//公有方法- copy : 复制一个vector,来用作保存之前速度节点的记录
Vector.prototype.copy = function() {
//返回一个同等速度属性的Vector实例
return new Vector(this.x, this.y);
};
Drop 下落物体对象, 即上面效果中的雨滴和雪, 在后面你也可自己拓展为陨石或者炮弹
对于Drop对象其基本定义如下
//构造函数
var Drop = function() {
/* .... */
};
//公有方法-update 
Drop.prototype.update = function() {
/* .... */
};
//公有方法-draw
Drop.prototype.draw = function() {
/* .... */
};
Nach dem Login kopieren

Haben Sie nach dem Lesen der oben genannten drei Methoden ihre Funktion erraten? Lassen Sie uns als Nächstes verstehen, was diese drei Methoden bewirken

Konstrukteur

Der Konstruktor ist hauptsächlich für die Definition der Anfangsinformationen des Drop-Objekts verantwortlich, wie Geschwindigkeit, Anfangskoordinaten, Größe, Beschleunigung usw.

//构造函数 Drop
var Drop = function() {
//随机设置drop的初始坐标 
//首先随机选择下落对象是从从哪一边
var randomEdge = Math.random()*2;
if(randomEdge > 1){
this.pos = new Vector(50 + Math.random() * canvas.width, -80);
}else{
this.pos = new Vector(canvas.width, Math.random() * canvas.height);
}
//设置下落元素的大小
//通过调用的OPTS函数的半径范围进行随机取值
this.radius = (OPTS.size_range[0] + Math.random() * OPTS.size_range[1]) *DPR;
//获得drop初始速度
//通过调用的OPTS函数的速度范围进行随机取值
this.speed = (OPTS.speed[0] + Math.random() * OPTS.speed[1]) *DPR;
this.prev = this.pos;
//将角度乘以 0.017453293 (2PI/360)即可转换为弧度。
var eachAnger = 0.017453293; 
//获得风向的角度
wind_anger = OPTS.wind_direction * eachAnger;
//获得横向加速度 
speed_x = this.speed * Math.cos(wind_anger);
//获得纵向加速度
speed_y = - this.speed * Math.sin(wind_anger);
//绑定一个速度实例
this.vel = new Vector(wind_x, wind_y);
};
Nach dem Login kopieren

Die Aktualisierungsmethode des Drop-Objekts

Die Update-Methode ist für die Änderung der Attribute der Drop-Instanz in jedem Frame verantwortlich, wie z. B. die Änderung der Verschiebung

Drop.prototype.update = function() {
this.prev = this.pos.copy();
//如果是有重力的情况,则纵向速度进行增加
if (OPTS.hasGravity) {
this.vel.y += gravity;
}
//
this.pos.add(this.vel);
};
Nach dem Login kopieren

Die Draw-Methode des Drop-Objekt

Die Zeichenmethode ist für die Zeichnung jeder Frame-Drop-Instanz verantwortlich

Drop.prototype.draw = function() {
ctx.beginPath();
ctx.moveTo(this.pos.x, this.pos.y);
//目前只分为两种情况,一种是rain 即贝塞尔曲线
if(OPTS.type =="rain"){
ctx.moveTo(this.prev.x, this.prev.y);
var ax = Math.abs(this.radius * Math.cos(wind_anger));
var ay = Math.abs(this.radius * Math.sin(wind_anger));
ctx.bezierCurveTo(this.pos.x + ax, this.pos.y + ay, this.prev.x + ax , this.prev.y + ay, this.pos.x, this.pos.y);
ctx.stroke();
//另一种是snow--即圆形
}else{
ctx.moveTo(this.pos.x, this.pos.y);
ctx.arc(this.pos.x, this.pos.y, this.radius, 0, Math.PI*2);
ctx.fill();
}
};
Nach dem Login kopieren

Bounce fallendes Bounce-Objekt, das heißt, Wassertropfen, die vom Regen abprallen, können später auch zu aufprallenden Kiesstücken erweitert werden

ist sehr einfach und wird hier nicht im Detail erklärt

var Bounce = function(x, y) {
var dist = Math.random() * 7;
var angle = Math.PI + Math.random() * Math.PI;
this.pos = new Vector(x, y);
this.radius = 0.2+ Math.random()*0.8;
this.vel = new Vector(
Math.cos(angle) * dist,
Math.sin(angle) * dist
);
};
Bounce.prototype.update = function() {
this.vel.y += gravity;
this.vel.x *= 0.95;
this.vel.y *= 0.95;
this.pos.add(this.vel);
};
Bounce.prototype.draw = function() {
ctx.beginPath();
ctx.arc(this.pos.x, this.pos.y, this.radius*DPR, 0, Math.PI * 2);
ctx.fill();
};
Nach dem Login kopieren

Externe Schnittstelle

Update

entspricht der Startfunktion der gesamten Canvas-Animation

function update() {
var d = new Date;
//清理画图
ctx.clearRect(0, 0, canvas.width, canvas.height);
var i = drops.length;
while (i--) {
var drop = drops[i];
drop.update();
//如果drop实例下降到底部,则需要在drops数组中清楚该实例对象
if (drop.pos.y >= canvas.height) {
//如果需要回弹,则在bouncess数组中加入bounce实例
if(OPTS.hasBounce){
var n = Math.round(4 + Math.random() * 4);
while (n--)
bounces.push(new Bounce(drop.pos.x, canvas.height));
}
//如果drop实例下降到底部,则需要在drops数组中清楚该实例对象
drops.splice(i, 1);
}
drop.draw();
}
//如果需要回弹
if(OPTS.hasBounce){
var i = bounces.length;
while (i--) {
var bounce = bounces[i];
bounce.update();
bounce.draw();
if (bounce.pos.y > canvas.height) bounces.splice(i, 1);
}
}
//每次产生的数量
if(drops.length < OPTS.maxNum){
if (Math.random() < drop_chance) {
var i = 0,
len = OPTS.numLevel;
for(; i<len; i++){
drops.push(new Drop());
}
}
}
//不断循环update
requestAnimFrame(update);
}
Nach dem Login kopieren

init

init-Schnittstelle, initialisiert die gesamte Leinwand. Alle grundlegenden Eigenschaften wie das Ermitteln des Pixelverhältnisses des Bildschirms, das Festlegen der Pixelgröße der Leinwand und das Festlegen des Stils

function init(opts) {
OPTS = opts;
canvas = document.getElementById(opts.id);
ctx = canvas.getContext("2d");
////兼容高清屏幕,canvas画布像素也要相应改变
DPR = window.devicePixelRatio;
//canvas画板像素大小, 需兼容高清屏幕,故画板canvas长宽应该乘于DPR
canvasWidth = canvas.clientWidth * DPR;
canvasHeight =canvas.clientHeight * DPR;
//设置画板宽高
canvas.width = canvasWidth;
canvas.height = canvasHeight;
drop_chance = 0.4;
//设置样式
setStyle();
}
function setStyle(){
if(OPTS.type =="rain"){
ctx.lineWidth = 1 * DPR;
ctx.strokeStyle = &#39;rgba(223,223,223,0.6)&#39;;
ctx.fillStyle = &#39;rgba(223,223,223,0.6)&#39;;
}else{
ctx.lineWidth = 2 * DPR;
ctx.strokeStyle = &#39;rgba(254,254,254,0.8)&#39;;
ctx.fillStyle = &#39;rgba(254,254,254,0.8)&#39;;
}
}
Nach dem Login kopieren

Fazit

Okay, nun ist eine einfache Drop-Komponente fertiggestellt. Nach dem Schreiben gibt es natürlich viele Unvollkommenheiten Ich glaube, dass es in dieser Drop-Komponente viele Dinge gibt, die in der H5-Szene für die Animationsimplementierung von Canvas untersucht werden können.

Lassen Sie uns abschließend über die Mängel und die anschließende Arbeit sprechen:

0 Diese Komponente verfügt derzeit nicht über genügend externe Schnittstellen, der einstellbare Bereich ist nicht sehr groß und die Abstraktion ist es nicht sehr gründlich

1. setStyle legt den Grundstil fest

2. Anpassung der Aktualisierungs- und Zeichenmethoden von Drop- und Bounce-Objekten, sodass Benutzer eine höhere Fallgeschwindigkeit festlegen können und Größenänderungen Die Form- und Stileffekte

3. Schnittstellen für Animationspausen, Beschleunigungs- und Verzögerungsvorgänge sollten hinzugefügt werden

Das Obige ist die vom Editor I eingeführte JS- und Canvas-Implementierung Ich hoffe, dass Ihnen dieses Wissen über die Wirkung von Regen und Schnee hilfreich sein wird. Wenn Sie Fragen haben, hinterlassen Sie mir bitte eine Nachricht und der Herausgeber wird Ihnen rechtzeitig antworten. Ich möchte mich auch bei Ihnen allen für Ihre Unterstützung der chinesischen PHP-Website bedanken!

Weitere Artikel zu JS+Canvas zur Erzielung von Regen- und Schneeeffekten finden Sie auf der chinesischen PHP-Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage