JS + Canvas achieves rain and snow effect, jscanvas

Source: Internet
Author: User

JS + Canvas achieves rain and snow effect, jscanvas

Recently I made a project where I needed to implement the animation effects of rain and light snow. So I made a drop component here to show the effects of common drop objects on the canvas. Before giving you an introduction to the text, we will show you the following:

Display:

Rain and snow

It looks good. Compared with creating dom elements to create multi-object displacement animations, canvas makes it easier and faster, and delivers better performance.

Call Code

<! DOCTYPE html> 

Well, next I will explain the simple implementation principles. First, I will define some global variables we will use, such as the wind direction angle, probability, and object data.

Define global variables

// Define the data of two objects. // the data of the drops falling object and the bounces object var drops = [], bounces = []; // here, the gravity acceleration is set to 0.2/A frame var gravity = 0.2; var speed_x_x, // horizontal acceleration speed_x_y, // Longitudinal acceleration wind_anger; // wind direction // var canvasWidth and canvasHeight of the pixel width and height of the canvas; // The probability of creating a drop var drop_chance; // configure the object var OPTS; // determine whether the requestAnimationFrame method exists, if yes, It is used. If no, it is about 30 windows frames per second. requestAnimFrame = window. requestAnimationFrame | window. webkitRequestAnimationFrame | window. required requestanimationframe | window. oRequestAnimationFrame | window. msRequestAnimationFrame | function (callback) {window. setTimeout (callback, 1000/30 );};

Define core objects

Next, we need to define several important objects. The Organization needs to define fewer objects. In total, only three core objects are defined in the entire drop component. The three core objects are as follows:

Vector speed object with horizontal x and vertical y. Unit: V = displacement pixel/Frame

The understanding of the Vector object is also very simple and rough, that is, to record the drop speed of the falling object/V

Var Vector = function (x, y) {// Private Attribute horizontal speed x, vertical speed ythis. x = x | 0; this. y = y | 0 ;}; // public method-add: speed change function, which increases the speed according to the parameter. // due to business needs, the acceleration of whereabouts is considered, so there is no slowdown, and later can expand/** @ 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 ;}; // public method-copy: copy a vector to save the record Vector of the previous speed node. prototype. copy = function () {// returns a Vector instance of the same speed attribute return new Vector (this. x, this. y) ;}; Drop the falling object, that is, the raindrops and snow in the above effect, in the future, you can expand to a meteorite or shell. The basic definition of the Drop object is as follows // constructor var Drop = function (){/*.... * //}; // public method-update Drop. prototype. update = function (){/*.... * //}; // public method-drawDrop. prototype. draw = function (){/*.... */};

After reading the above three methods, Have you guessed their functions? Let's see what these three methods have done.

Constructor

Constructors are mainly responsible for defining the initial information of drop objects, such as velocity, initial coordinates, size, and acceleration.

// Constructor Dropvar Drop = function () {// randomly sets the initial coordinate of the drop. // first, randomly selects the path from which the falling object is 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);} // set the size of the falling element // random value this is obtained through the Radius Range of the called OPTS function. radius = (OPTS. size_range [0] + Math. random () * OPTS. size_range [1]) * DPR; // get the initial drop speed // follow the speed range of the called OPTS Function Machine value this. speed = (OPTS. speed [0] + Math. random () * OPTS. speed [1]) * DPR; this. prev = this. pos; // multiply the angle by 0.017453293 (2PI/360) to convert it to a radian. Var eachAnger = 0.017453293; // obtain the wind direction angle wind_anger = OPTS. wind_direction * eachAnger; // obtain the transverse acceleration speed_x = this. speed * Math. cos (wind_anger); // obtain the vertical acceleration speed_y =-this. speed * Math. sin (wind_anger); // bind a speed instance this. vel = new Vector (wind_x, wind_y );};

Update method of Drop object

The update method is responsible for changing the attributes of each frame drop instance, such as the displacement.

Drop. prototype. update = function () {this. prev = this. pos. copy (); // if there is gravity, the vertical speed is increased if (OPTS. hasGravity) {this. vel. y + = gravity;} // this. pos. add (this. vel );};

Draw method of Drop object

The draw method is responsible for the painting of each frame drop instance.

Drop. prototype. draw = function () {ctx. beginPath (); ctx. moveTo (this. pos. x, this. pos. y); // currently, there are only two types of conditions: 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 (); // The other is snow -- circular} 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 ();}};

Bounce falls onto the rebound object, that is, the water drops of the above rain rebound, you can also expand to the rebound of gravel or dust

The definition is very simple, so I will not describe it in detail here

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();};

External Interface

Update

It is equivalent to the start function of the entire canvas animation.

Function update () {var d = new Date; // clear the painting ctx. clearRect (0, 0, canvas. width, canvas. height); var I = drops. length; while (I --) {var drop = drops [I]; drop. update (); // if the drop instance drops to the bottom, the instance object if (drop. pos. y> = canvas. height) {// if You Want to rebound, add the bounce instance if (OPTS. hasBounce) {var n = Math. round (4 + Math. random () * 4); while (n --) bounces. push (new Bounce (drop. pos. x, canvas. height);} // If the drop instance drops to the bottom, you need to clear the instance object drops in the drops array. splice (I, 1);} drop. draw ();} // if You Need To rebound 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) ;}/// number of results generated each time if (drops. length <OPTS. maxNum) {if (Math. random () <drop_chance) {var I = 0, len = OPTS. numLevel; for (; I <len; I ++) {drops. push (new Drop () ;}}// continuously looping updaterequestAnimFrame (update );}

Init

The init interface initializes all basic attributes of the entire canvas, such as obtaining the pixel ratio of the screen, setting the pixel size of the canvas, and setting the style.

Function init (opts) {OPTS = opts; canvas = document. getElementById (opts. id); ctx = canvas. getContext ("2d"); // compatible with HD screens, the canvas pixel must also change DPR = window. devicePixelRatio; // canvas pixel size, which must be compatible with HD screens. Therefore, the canvas length and width must be multiplied by DPRcanvasWidth = canvas. clientWidth * DPR; canvasHeight = canvas. clientHeight * DPR; // you can specify the canvas width and height. width = canvasWidth; canvas. height = canvasHeight; drop_chance = 0.4; // set the style setStyle ();} function setStyle () {if (OPTS. type = "rain") {ctx. lineWidth = 1 * DPR; ctx. strokeStyle = 'rgba (223,223,223, 0.6) '; ctx. fillStyle = 'rgba (223,223,223, 0.6) ';} else {ctx. lineWidth = 2 * DPR; ctx. strokeStyle = 'rgba (254,254,254, 0.8) '; ctx. fillStyle = 'rgba (254,254,254, 0.8 )';}}

Conclusion

Well, a simple drop component has been completed. Of course, it is not perfect in many places. After writing the drop component, we will implement the canvas animation, I believe there are many places to explore in H5 scenarios.

Finally, let's talk about the shortcomings and future work:

0. Currently, this component does not have many external interfaces, there are not many adjustable scopes, And the abstraction is not very thorough.

1. Set basic styles using setStyle

2. The update and draw methods of Drop and Bounce objects are customized, allowing you to set up more fall speed and size change forms and style effects

3. You should add pause, acceleration, and deceleration operations for the animation.

The above is a small series of related knowledge about JS and Canvas Implementation of rain and snow effects. I hope to help you. If you have any questions, please leave a message for me, the editor will reply to you in a timely manner. Thank you very much for your support for the help House website!

This article reprinted: http://blog.csdn.net/xllily_11/article/details/51444311

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.