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.
用javascript进行水模拟。 今天,我们继续JavaScript课程,并且我们的文章将介绍在水效果建模中使用js。 有时我们可以使用普通Javascript创建非常有趣的解决方案。
Here are sample and downloadable package:
以下是示例和可下载的软件包:
步骤1. HTML (Step 1. HTML)
As usual, we start with the HTML.
和往常一样,我们从HTML开始。
This is our main page code with all samples.
这是我们所有示例的主页代码。
index.html (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>
<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>
步骤2. CSS (Step 2. CSS)
Here are used CSS styles.
这是使用CSS样式。
css / main.css (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}
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}
步骤3. JS (Step 3. JS)
Here are our main control JS file.
这是我们的主要控制JS文件。
js / main.js (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);
}
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.
这是我们文章中最有趣,最重要的部分。 在这里,我们创建主要对象–场景,并向其中添加粒子。 还添加了几个事件(主要用于鼠标)。 所有这些看起来都像是低级编码,但是不用担心–这主要是数学。
[sociallocker]
[社交储物柜]
[/sociallocker]
[/ 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!
希望您很高兴与thas robo-water一起玩:)如果您想知道–别忘了感谢。 谢谢您提出的宝贵意见。 祝好运!
翻译自: https://www.script-tutorials.com/particles-in-water/