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!
How is this a tutorial or a lesson? You might as well just link to the file and tell people to view source.
It seems that this is more demonstration with code – how to create similar :)
this is really awesome.
thanks for the script share.