Creating Animated Particles in Water Effect using JavaScript

Creating Animated Particles in Water Effect using JavaScript

3 59485
Creating Animated Particles in Water Effect using JavaScript

Water simulation with javascript. Today we continue JavaScript lessons, and our article will about using js in modeling of water effects. Sometimes we can create very interesting solutions using ordinary Javascript.

Here are sample and downloadable package:

Live Demo

Step 1. HTML

As usual, we start with the HTML.

This is our main page code with all samples.

index.html

<link rel="stylesheet" href="css/main.css" type="text/css" media="all" />
<script src="js/main.js" type="text/javascript"></script>
<div class="example">
    <img id="unit" src="unit.png" style="visibility:hidden" >
    <div id="main"></div>
    <div id="fps"></div>
</div>

Step 2. CSS

Here are used CSS styles.

css/main.css

body{background:#eee;font-family:Verdana, Helvetica, Arial, sans-serif;margin:0;padding:0}
.example{position:relative;background:#FFF;width:600px;height:600px;border:1px #000 solid;margin:20px auto;padding:20px;-moz-border-radius:3px;-webkit-border-radius:3px}
#main{position:absolute;width:520px;height:520px;background:#000;outline:#f0f solid 3px;overflow:hidden;cursor:pointer}
#fps{position:absolute;right:20px;top:20px}

Step 3. JS

Here are our main control JS file.

js/main.js

var wp = function () {
    // variables
    var scr, grid, npart, diam, nx, ny, nw, nh, gw, gh;
    var xm = 0;
    var ym = 0;
    var obj = new Array(npart);
    var down = false;
    var fps = 0;
    // add listeners
    var addEvent = function  (o, e, f) {
        if (window.addEventListener) o.addEventListener(e, f, false);
        else if (window.attachEvent) r = o.attachEvent('on' + e, f);
    }
    // resize function
    var resize = function () {
        nw = scr.offsetWidth;
        nh = scr.offsetHeight;
        var o = scr;
        for (nx = 0, ny = 0; o != null; o = o.offsetParent) {
            nx += o.offsetLeft;
            ny += o.offsetTop;
        }
        gw = Math.round(nw / pdiam);
        gh = Math.round(nh / pdiam);
    }
    // particle constructor
    var Particle = function (img) {
        this.x = Math.random() * nw;
        this.y = Math.random() * nh;
        this.vx = 0;
        this.vy = 0;
        this.dx = 0;
        this.dy = 0;
        this.wi = img.width * .5;
        this.hi = img.height * .5;
        // new html elements
        var d = document.createElement('img');
        d.style.position = "absolute";
        d.style.left = "-1000px";
        d.src = img.src;
        scr.appendChild(d);
        this.plo = d.style;
    }
    // move particle
    Particle.prototype.move = function () {
        this.x  += this.dx;
        this.y  += this.dy;
        this.vx += this.dx;
        this.vy += this.dy;
        this.dx  = 0;
        this.dy  = 0;
        // DOM
        this.plo.left = Math.round(this.x - this.wi) + 'px';
        this.plo.top  = Math.round(this.y - this.hi) + 'px';
    }
    // water simulation
    Particle.prototype.physics = function () {
        // mouse influence
        if (down) {
            var dx = this.x - xm;
            var dy = this.y - ym;
            var d = Math.sqrt(dx * dx + dy * dy);
            if (d < pdiam * 2) {
                this.dx += dx / d;
                this.dy += dy / d;
            }
        }
        // gravity and acceleration
        this.vy += .2;
        this.x += this.vx;
        this.y += this.vy;
        // screens limits
        if (this.x < pdiam * .5) this.dx += (pdiam * .5 - this.x);
        else if (this.x > nw - pdiam * .5) this.dx -= (this.x - nw + pdiam * .5);
        if (this.y < pdiam * .5) this.dy += (pdiam * .5 - this.y);
        else if (this.y > nh - pdiam * .5) this.dy -= (this.y - nh + pdiam * .5);
        // grid coordinates
        var gx = Math.round(this.x / pdiam);
        var gy = Math.round(this.y / pdiam);
        // neightbors constraints
        for (var ix = gx - 1; ix <= gx + 1; ix++) {
            for (var iy = gy - 1; iy <= gy + 1; iy++) {
                var g = grid[iy * gw + ix] || [];
                for (j = 0, l = g.length; j < l; j++) {
                    var that = g[j];
                    var dx = that.x - this.x;
                    var dy = that.y - this.y;
                    var d = Math.sqrt(dx * dx + dy * dy);
                    if (d < pdiam && d > 0) {
                        dx = (dx / d) * (pdiam - d) * .25;
                        dy = (dy / d) * (pdiam - d) * .25;
                        this.dx -= dx;
                        this.dy -= dy;
                        that.dx += dx;
                        that.dy += dy;
                    }
                }
            }
        }
        // update neighbors array
        if (!grid[gy * gw + gx]) grid[gy * gw + gx] = [this];
        else grid[gy * gw + gx].push(this);
    }
    // loop
    var run = function () {
        fps++;
        grid = new Array(gw * gh);
        for(var i = 0; i < npart; i++) obj[i].physics();
        for(var i = 0; i < npart; i++) obj[i].move();
        setTimeout(run, 1);
    }
    return {
        // initialization
        init : function (n, d) {
            scr = document.getElementById('main');
            npart = n;
            pdiam = d;
            // subscribing to events
            addEvent(document, 'mousemove', function (e) {
                if (window.event) e = window.event;
                xm = e.clientX - nx;
                ym = e.clientY - ny;
            });
            addEvent(window, 'resize', resize);
            addEvent(document, 'mousedown', function(e) {if (e.preventDefault) e.preventDefault(); down = true;return false;});
            addEvent(document, 'mouseup', function() { down = false;return false;});
            document.onselectstart = function () { return false; }
            scr.ondrag = function () { return false; }
            // fps countrt
            setInterval(function() {
                document.getElementById('fps').innerHTML = fps + ' FPS';
                fps = 0;
            }, 1000);
            // starting
            resize();
            for (var i = 0; i < npart; i++) obj[i] = new Particle(document.getElementById('unit'));
            run();
        }
    }
}();
window.onload = function() {
  wp.init(50, 45);
}

This is most interesting and important part of our article. Here we creating our main object – scene, and adding particle to it. Also added several events (mainly for mouse). All this looks like low level coding, but don`t worry – this is mainly mathematics.


Live Demo

[sociallocker]

download in package

[/sociallocker]


Conclusion

Hope that you was happy to play with thas robo-water :) If is you were wondering – do not forget to thank. I would be grateful for your interesting comments. Good luck!

SIMILAR ARTICLES


3 COMMENTS

  1. How is this a tutorial or a lesson? You might as well just link to the file and tell people to view source.

Leave a Reply