Last active
          September 8, 2017 22:42 
        
      - 
      
- 
        Save alexbourt/ca5b9e44f6ecbfcc6b8a52d805caa9f6 to your computer and use it in GitHub Desktop. 
Revisions
- 
        alexbourt revised this gist Sep 8, 2017 . 1 changed file with 40 additions and 1 deletion.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -40,7 +40,46 @@ function createParticles(canvas, width, height, cellSize = defaultCellSize) canvas.mouseX = 0; canvas.mouseY = 0; canvas.onclick = function(e) { if (e.button == 0) { var canvasRect = canvas.getBoundingClientRect(); var px = e.clientX - canvasRect.left; var py = e.clientY - canvasRect.top; var size = 300; var gap = 20; for (var y = py - size/2; y < py + size/2; y += gap) { for (var x = px - size/2; x < px + size/2; x += gap) { if ( x < 0 || x >= canvas.width && y < 0 || y >= canvas.height) continue; addParticle({ cell: null, px: x, py: y, ppx: x, ppy: y, fx: 0, fy: 0, vx: 0, vy: 0, color: '#ac4', density: 0, nearDensity: 0 }); } } } }; // cells canvas.cells = new Array(); 
- 
        alexbourt revised this gist Sep 8, 2017 . 1 changed file with 0 additions and 36 deletions.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -207,8 +207,6 @@ function createParticles(canvas, width, height, cellSize = defaultCellSize) } }; canvas.moveParticles = function() { for (var i = 0; i < canvas.cells.length; i++) @@ -228,40 +226,6 @@ function createParticles(canvas, width, height, cellSize = defaultCellSize) // forces canvas.applyGravity = function() { for (var i = 0; i < canvas.cells.length; i++) 
- 
        alexbourt revised this gist Sep 8, 2017 . 1 changed file with 0 additions and 341 deletions.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -40,131 +40,6 @@ function createParticles(canvas, width, height, cellSize = defaultCellSize) canvas.mouseX = 0; canvas.mouseY = 0; // cells canvas.cells = new Array(); @@ -259,33 +134,6 @@ function createParticles(canvas, width, height, cellSize = defaultCellSize) } }; // particles function addParticle(p) @@ -305,75 +153,8 @@ function createParticles(canvas, width, height, cellSize = defaultCellSize) cell.particles.push(p); } var radius = 2; // update canvas.update = function() @@ -800,128 +581,6 @@ function createParticles(canvas, width, height, cellSize = defaultCellSize) } }; canvas.updateParticleVelocities = function() { 
- 
        alexbourt created this gist Sep 8, 2017 .There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,1086 @@ var defaultCellSize = 48 * window.devicePixelRatio; function createParticles(canvas, width, height, cellSize = defaultCellSize) { canvas.width = width; canvas.height = height; // defaults canvas.showCells = false; canvas.showVelocity = false; canvas.showDensity = false; canvas.showForces = true; canvas.cellSize = cellSize; canvas.xCells = Math.ceil(canvas.width / canvas.cellSize); canvas.yCells = Math.ceil(canvas.height / canvas.cellSize); canvas.scale = 10; //canvas.particleBounce = 1; canvas.wallBounce = 0.2; canvas.damping = 0; canvas.random = 0; canvas.gravity = 9.8; canvas.viscositySigma = 0; // linear viscosity canvas.viscosityBeta = 0.001; // quadratic viscosity canvas.restDensity = 10; canvas.stiffness = 1.5; canvas.nearStiffness = 3; canvas.time = performance.now(); canvas.dt = 1; canvas.mouseDown = false; canvas.mouseX = 0; canvas.mouseY = 0; canvas.addEventListener("mousedown", canvas.onmousedown, false); canvas.addEventListener("mouseup" , canvas.onmouseup , false); canvas.addEventListener("mousemove", canvas.onmousemove, false); //canvas.addEventListener("touchstart", canvas.ontouchstart, false); //canvas.addEventListener("touchend" , canvas.ontouchend , false); //canvas.addEventListener("touchmove", canvas.ontouchmove, false); canvas.onclick = function(e) { if (e.button == 0) { var canvasRect = canvas.getBoundingClientRect(); var px = e.clientX - canvasRect.left; var py = e.clientY - canvasRect.top; var size = 300; var gap = 20; for (var y = py - size/2; y < py + size/2; y += gap) { for (var x = px - size/2; x < px + size/2; x += gap) { if ( x < 0 || x >= canvas.width && y < 0 || y >= canvas.height) continue; addParticle({ cell: null, px: x, py: y, ppx: x, ppy: y, fx: 0, fy: 0, vx: 0, vy: 0, color: '#ac4', density: 0, nearDensity: 0 }); } } } }; canvas.onmousedown = function(e) { if (e.button == 0) { canvas.mouseDown = true; var canvasRect = canvas.getBoundingClientRect(); canvas.mouseX = e.clientX - canvasRect.left; canvas.mouseY = e.clientY - canvasRect.top; } }; canvas.onmousemove = function(e) { if (canvas.mouseDown) { e.stopImmediatePropagation(); var canvasRect = canvas.getBoundingClientRect(); var ex = e.clientX - canvasRect.left; var ey = e.clientY - canvasRect.top; var ix = ex - canvas.mouseX; var iy = ey - canvas.mouseY; canvas.mouseX = ex; canvas.mouseY = ey; var h = canvas.cellSize; var _cx = Math.round(ex / canvas.cellSize); var _cy = Math.round(ey / canvas.cellSize); var _ci = _cy * canvas.xCells + _cx; var cell = canvas.cells[_ci]; var cyMin = Math.max(0, cell.cy - 2); var cyMax = Math.min(cell.cy + 2, canvas.yCells-1); var cxMin = Math.max(0, cell.cx - 2); var cxMax = Math.min(cell.cx + 2, canvas.xCells-1); for (var cy = cyMin; cy <= cyMax; cy++) { for (var cx = cxMin; cx <= cxMax; cx++) { var ci = cy * canvas.xCells + cx; var checkCell = canvas.cells[ci]; for (var k = 0; k < checkCell.particles.length; k++) { var p = checkCell.particles[k]; var dx = ex - p.px; var dy = ey - p.py; var dist2 = dx*dx + dy*dy; if (dist2 >= h*h) // check if particle is too far continue; var dist = Math.sqrt(dist2); var q = Math.pow(1 - dist/h, 0.5); p.vx += q * ix / 2; p.vy += q * iy / 2; } } } } }; canvas.onmouseup = function(e) { if (e.button == 0) canvas.mouseDown = false; }; // cells canvas.cells = new Array(); for (var y = 0; y < canvas.yCells; y++) { for (var x = 0; x < canvas.xCells; x++) { canvas.cells.push({ particles: new Array(), cx: x, cy: y, left: x * canvas.cellSize, top: y * canvas.cellSize, right: (x+1) * canvas.cellSize, bottom: (y+1) * canvas.cellSize, color: 'rgb(' + Math.floor(64+192*Math.random()) + ', ' + Math.floor(64+192*Math.random()) + ', ' + Math.floor(64+192*Math.random()) + ')' }); } } function saveCells() { //canvas.oldCells = canvas.cells; canvas.oldCells = new Array(); for (var i = 0; i < canvas.cells.length; i++) { var cell = canvas.cells[i]; var oldCell = { particles: new Array(), cx: cell.cx, cy: cell.cy, left: cell.left, top: cell.top, right: cell.right, bottom: cell.bottom, color: cell.color }; for (var j = 0; j < cell.particles.length; j++) { var p = cell.particles[j]; oldCell.particles.push({ cell: oldCell, px: p.px, py: p.py, ppx: p.ppx, ppy: p.ppy, fx: p.fx, fy: p.fx, vx: p.vx, vy: p.vx, color: p.color, density: p.density, nearDensity: p.nearDensity }); } canvas.oldCells.push(oldCell); } } function updateCells() { for (var i = 0; i < canvas.cells.length; i++) { var cell = canvas.cells[i]; for (var j = cell.particles.length - 1; j >= 0; j--) { var p = cell.particles[j]; if ( p.px >= cell.left && p.py >= cell.top && p.px < cell.right && p.py < cell.bottom || p.px < 0 || p.py < 0) continue; cell.particles.splice(j, 1); p.cell = null; addParticle(p); } } }; //function updateCellsAt(cxMin, cyMin, cxMax, cyMax) //{ // for (var cy = cyMin; cy <= cyMax; cy++) // { // for (var cx = cxMin; cx <= cxMax; cx++) // { // var cell = canvas.cells[cy * canvas.xCells + cx]; // for (var i = cell.particles.length - 1; i >= 0; i--) // { // var p = cell.particles[i]; // if ( p.px >= cell.left // && p.py >= cell.top // && p.px < cell.right // && p.py < cell.bottom) // continue; // cell.particles.splice(i, 1); // p.cell = null; // addParticle(p); // } // } // } //}; // particles function addParticle(p) { var cx = Math.floor(p.px / canvas.cellSize); var cy = Math.floor(p.py / canvas.cellSize); if ( cx < 0 || cy < 0 || cx >= canvas.xCells || cy >= canvas.yCells) return; var cell = canvas.cells[cy * canvas.xCells + cx]; p.cell = cell; cell.particles.push(p); } //function moveParticle(p, x, y) //{ // p.px = x; // p.py = y; // if ( p.px >= p.cell.left // && p.py >= p.cell.top // && p.px < p.cell.right // && p.py < p.cell.bottom) // return; // p.cell.particles.splice( // p.cell.particles.indexOf(p), // 1); // p.cell = null; // addParticle(p); //} /////////////////////// create some particles var radius = 2; //var gap = 10; //for (var py = canvas.height/2 + gap; py < canvas.height - radius; py += gap) //{ // for (var px = radius; px < canvas.width - radius; px += gap) // { // canvas.addParticle({ // px: px, // py: py, // ppx: px, // ppy: py, // dx: 0, // dy: 0, // vx: 0, //100 * (-1 + 2*Math.random()), // vy: 0, //100 * (-1 + 2*Math.random()), // radius: radius, // color: '#ac4', // density: 0, // nearDensity: 0 // //bounce: 1, // //colliding: false // }); // } //} //for (var py = radius; py < canvas.height/2; py += gap) //{ // for (var px = radius; px < canvas.width - radius; px += gap) // { // canvas.addParticle({ // px: px, // py: py, // ppx: px, // ppy: py, // vx: 0, //100 * (-1 + 2*Math.random()), // vy: 0, //100 * (-1 + 2*Math.random()), // radius: radius, // color: '#0cf', // density: 0, // nearDensity: 0 // //bounce: 1, // //colliding: false // }); // } //} // update canvas.update = function() { var time = performance.now(); canvas.dt = (time - canvas.time) / 1000 * canvas.scale; // in seconds canvas.time = time; canvas.updateParticles(); canvas.paint(); }; canvas.updateParticles = function() { canvas.applyRandom(); canvas.applyDamping(); canvas.applyGravity(); canvas.applyViscosity(); canvas.saveParticlePositions(); canvas.moveParticles(); //updateCells(); canvas.relaxParticleDensity(); //updateCells(); canvas.bounceOffWalls(); updateCells(); // housekeeping canvas.updateParticleVelocities(); }; // move canvas.saveParticlePositions = function() { for (var i = 0; i < canvas.cells.length; i++) { var cell = canvas.cells[i]; for (var j = 0; j < cell.particles.length; j++) { var p = cell.particles[j]; p.ppx = p.px; p.ppy = p.py; } } }; canvas.moveParticles = function() { for (var i = 0; i < canvas.cells.length; i++) { var cell = canvas.cells[i]; for (var j = 0; j < cell.particles.length; j++) { var p = cell.particles[j]; p.px += p.vx * canvas.dt, p.py += p.vy * canvas.dt; } } }; // forces canvas.applyRandom = function() { for (var i = 0; i < canvas.cells.length; i++) { var cell = canvas.cells[i]; for (var j = 0; j < cell.particles.length; j++) { var p = cell.particles[j]; p.vx += (-1 + Math.random()*2) * canvas.random; p.vy += (-1 + Math.random()*2) * canvas.random; } } }; canvas.applyDamping = function() { for (var i = 0; i < canvas.cells.length; i++) { var cell = canvas.cells[i]; for (var j = 0; j < cell.particles.length; j++) { var p = cell.particles[j]; p.vx *= 1 - canvas.damping; p.vy *= 1 - canvas.damping; } } }; canvas.applyGravity = function() { for (var i = 0; i < canvas.cells.length; i++) { var cell = canvas.cells[i]; for (var j = 0; j < cell.particles.length; j++) cell.particles[j].vy += canvas.gravity * canvas.dt; } }; // viscosity canvas.applyViscosity = function() { var h = canvas.cellSize; for (var i = 0; i < canvas.cells.length; i++) { var cell = canvas.cells[i]; var cyMin = Math.max(0, cell.cy - 1); var cyMax = Math.min(cell.cy + 1, canvas.yCells - 1); var cxMin = Math.max(0, cell.cx - 1); var cxMax = Math.min(cell.cx + 1, canvas.xCells - 1); for (var j = 0; j < cell.particles.length; j++) { var p = cell.particles[j]; for (var cy = cyMin; cy <= cyMax; cy++) { for (var cx = cxMin; cx <= cxMax; cx++) { var ci = cy * canvas.xCells + cx; var checkCell = canvas.cells[ci]; for (var k = 0; k < checkCell.particles.length; k++) { if (i == ci && j == k) // check if the test is against itself continue; var p2 = checkCell.particles[k]; var dx = p2.px - p.px; var dy = p2.py - p.py; var dist2 = dx*dx + dy*dy; if (dist2 >= h*h) // check if particle is too far continue; var dist = Math.sqrt(dist2); var q = 1 - dist/h; var dvx = p.vx - p2.vx; var dvy = p.vy - p2.vy; var x1 = dx / nozero(dist); var y1 = dy / nozero(dist); var u = dvx*x1 + dvy*y1; // dot product if (u > 0) { var I = canvas.dt * q * ( canvas.viscositySigma * u + canvas.viscosityBeta * u*u); var Ix = I * x1; var Iy = I * y1; p.vx -= Ix/2; p.vy -= Iy/2; p2.vx += Ix/2; p2.vy += Iy/2; } } } } } } }; // double density relaxation canvas.relaxParticleDensity = function() { saveCells(); // var h = canvas.cellSize; for (var i = 0; i < canvas.cells.length; i++) { var oldCell = canvas.oldCells[i]; var cell = canvas.cells[i]; var cyMin = Math.max(0, cell.cy - 1); var cyMax = Math.min(cell.cy + 1, canvas.yCells - 1); var cxMin = Math.max(0, cell.cx - 1); var cxMax = Math.min(cell.cx + 1, canvas.xCells - 1); for (var j = 0; j < cell.particles.length; j++) { var p = cell.particles[j]; p.density = 0; p.nearDensity = 0; for (var cy = cyMin; cy <= cyMax; cy++) { for (var cx = cxMin; cx <= cxMax; cx++) { var ci = cy * canvas.xCells + cx; var checkCell = canvas.cells[ci]; for (var k = 0; k < checkCell.particles.length; k++) { if (i == ci && j == k) // check if the test is against itself continue; var p2 = checkCell.particles[k]; var dx = p2.px - p.px; var dy = p2.py - p.py; var dist2 = dx*dx + dy*dy; if (dist2 >= h*h) // check if particle is too far continue; var dist = Math.sqrt(dist2); var q = 1 - dist/h; p.density += Math.sqr (q); p.nearDensity += Math.cube(q); } } } var pressure = canvas.stiffness * (p.density - canvas.restDensity); var nearPressure = canvas.nearStiffness * p.nearDensity; p.fx = 0; p.fy = 0; var pOld = oldCell.particles[j]; for (var cy = cyMin; cy <= cyMax; cy++) { for (var cx = cxMin; cx <= cxMax; cx++) { var ci = cy * canvas.xCells + cx; var checkOldCell = canvas.oldCells[ci]; var checkCell = canvas.cells[ci]; for (var k = 0; k < checkOldCell.particles.length; k++) { if (i == ci && j == k) // check if the test is against itself continue; var p2 = checkCell.particles[k]; var p2old = checkOldCell.particles[k]; var dx = p2old.px - pOld.px; var dy = p2old.py - pOld.py; var dist2 = dx*dx + dy*dy; if (dist2 >= h*h) // check if particle is too far continue; var dist = Math.sqrt(dist2); var q = 1 - dist/h; var D = Math.sqr(canvas.dt) * ( pressure * q + nearPressure * q*q); p2old.fx = D/2 * dx / nozero(dist); // multiplied by unit vector p2old.fy = D/2 * dy / nozero(dist); p2.px += p2old.fx; p2.py += p2old.fy; p.fx -= p2old.fx; p.fy -= p2old.fy; } } } p.px += p.fx; p.py += p.fy; } } }; // collisions function dist(x1, y1, x2, y2) { var dx = x2 - x1; var dy = y2 - y1; return Math.sqrt(dx*dx + dy*dy); } function dist2(x1, y1, x2, y2) { var dx = x2 - x1; var dy = y2 - y1; return dx*dx + dy*dy; } canvas.bounceOffWalls = function() { var left = 0; var top = 0; var right = canvas.width; var bottom = canvas.height; for (var i = 0; i < canvas.cells.length; i++) { var cell = canvas.cells[i]; for (var j = 0; j < cell.particles.length; j++) { var p = cell.particles[j]; if (p.px < left) { var iy = p.ppy + (p.py - p.ppy) * (left - p.ppx) / nozero(p.px - p.ppx); var ix = left; var d = dist(ix, iy, p.px, p.py); var v = dist(p.ppx, p.ppy, p.px, p.py); var f = canvas.wallBounce * d / nozero(v); p.px = 2 * left - p.px; p.ppx = 2 * left - p.ppx; p.px = ix + (p.px - ix) * f; p.py = iy + (p.py - iy) * f; p.ppx = ix + (p.ppx - ix) * f; p.ppy = iy + (p.ppy - iy) * f; } else if (p.px > right) { var iy = p.ppy + (p.py - p.ppy) * (right - p.ppx) / nozero(p.px - p.ppx); var ix = right; var d = dist(ix, iy, p.px, p.py); var v = dist(p.ppx, p.ppy, p.px, p.py); var f = canvas.wallBounce * d / nozero(v); p.px = 2 * right - p.px; p.ppx = 2 * right - p.ppx; p.px = ix + (p.px - ix) * f; p.py = iy + (p.py - iy) * f; p.ppx = ix + (p.ppx - ix) * f; p.ppy = iy + (p.ppy - iy) * f; } if (p.py < top) { var ix = p.ppx + (p.px - p.ppx) * (top - p.ppy) / nozero(p.py - p.ppy); var iy = top; var d = dist(ix, iy, p.px, p.py); var v = dist(p.ppx, p.ppy, p.px, p.py); var f = canvas.wallBounce * d / nozero(v); p.py = 2 * top - p.py; p.ppy = 2 * top - p.ppy; p.px = ix + (p.px - ix) * f; p.py = iy + (p.py - iy) * f; p.ppx = ix + (p.ppx - ix) * f; p.ppy = iy + (p.ppy - iy) * f; } else if (p.py > bottom) { var ix = p.ppx + (p.px - p.ppx) * (bottom - p.ppy) / nozero(p.py - p.ppy); var iy = bottom; var d = dist(ix, iy, p.px, p.py); var v = dist(p.ppx, p.ppy, p.px, p.py); var f = canvas.wallBounce * d / nozero(v); p.py = 2 * bottom - p.py; p.ppy = 2 * bottom - p.ppy; p.px = ix + (p.px - ix) * f; p.py = iy + (p.py - iy) * f; p.ppx = ix + (p.ppx - ix) * f; p.ppy = iy + (p.ppy - iy) * f; } } } }; //canvas.bounceOffOther = function() //{ // // mark all as uncollided // for (var i = 0; i < canvas.cells.length; i++) // { // var cell = canvas.cells[i]; // for (var j = 0; j < cell.particles.length; j++) // cell.particles[j].colliding = false; // } // // test for collisions // // http://www.gamasutra.com/view/feature/131424/pool_hall_lessons_fast_accurate_.php // for (var i = 0; i < canvas.cells.length; i++) // { // var cell = canvas.cells[i]; // var cyMin = Math.max(0, cell.cy - 1); // var cyMax = Math.min(cell.cy + 1, canvas.yCells - 1); // var cxMin = Math.max(0, cell.cx - 1); // var cxMax = Math.min(cell.cx + 1, canvas.xCells - 1); // for (var j = 0; j < cell.particles.length; j++) // { // var p = cell.particles[j]; // for (var cy = cyMin; cy <= cyMax; cy++) // { // for (var cx = cxMin; cx <= cxMax; cx++) // { // var checkCell = canvas.cells[cy * canvas.xCells + cx]; // for (var k = 0; k < checkCell.particles.length; k++) // { // var c = checkCell.particles[k]; // var sr = p.radius + c.radius; // sum of radii // var sr2 = sr*sr; // var pMass = p.radius*p.radius; // var cMass = c.radius*c.radius; // // // var dx = c.px - p.px; // var dy = c.py - p.py; // // check if the test is against itself // if (Math.abs(dx) + Math.abs(dy) == 0) // continue; // var dp2 = dx*dx + dy*dy; // // subtract c vector from p vector to turn moving-moving into moving-static // var pvx = p.vx - c.vx; // var pvy = p.vy - c.vy; // // check if there is definitely no collision // var dpv2 = pvx*pvx + pvy*pvy; // if (dpv2 < dp2 - sr2) // TODO: check the tutorial to see if the -sr2 really works // continue; // // check if p is not moving toward c // if (pvx*dx + pvy*dy <= 0) // dot product // continue; // // check if p will intersect c on its trajectory // var dv = Math.sqrt(dpv2); // this can be calculated once per particle with the new vector // var nx = pvx / dv; // var ny = pvy / dv; // var d2t2 = nx*dx + ny*dy; // distance to closest tangent // var d2c2 = dp2 - d2t2; // square of distance from closest tangent to center of c // if (d2c2 > sr2) // continue; // // calculate how far p can move before it hits c // var dist = Math.sqrt(d2t2) - Math.sqrt(sr2 - d2c2); // // check if movement direction is congruent // if (dist > dv) // continue; // p.colliding = true; // // shorten movement vectors // var shorten = dist/dv; // p.vx *= shorten; // p.vy *= shorten; // c.vx *= shorten; // c.vy *= shorten; // // bounce // var dp = Math.sqrt(dp2); // var ndx = dx / dp; // var ndy = dy / dp; // var pa = p.vx*ndx + p.vy*ndy; // var ca = c.vx*ndx + c.vy*ndy; // var opt = 2 * (pa - ca) / (pMass + cMass); // var npvx = p.vx - opt * cMass * ndx; // var npvy = p.vy - opt * cMass * ndy; // var ncvx = c.vx - opt * pMass * ndx; // var ncvy = c.vy - opt * pMass * ndy; // p.vx = npvx; // p.vy = npvy; // c.vx = ncvx; // c.vy = ncvy; // } // } // } // } // } //}; canvas.updateParticleVelocities = function() { for (var i = 0; i < canvas.cells.length; i++) { var cell = canvas.cells[i]; for (var j = 0; j < cell.particles.length; j++) { var p = cell.particles[j]; p.vx = (p.px - p.ppx) / nozero(canvas.dt); p.vy = (p.py - p.ppy) / nozero(canvas.dt); } } }; // paint canvas.paint = function() { c = canvas.getContext('2d'); // background c.fillStyle = '#000411'; c.fillRect(0, 0, canvas.width, canvas.height); // particles for (var i = 0; i < canvas.cells.length; i++) { var cell = canvas.cells[i]; for (var j = 0; j < cell.particles.length; j++) { var p = cell.particles[j]; // body if ( !canvas.showVelocity && !canvas.showDensity && !canvas.showForces) { c.beginPath(); c.arc(p.px, p.py, radius, 0, Tau, false); c.fillStyle = canvas.showCells ? cell.color : p.color; //if (p.colliding && canvas.showCollisions) // c.fillStyle = '#ff4'; c.fill(); } if (canvas.showVelocity) { var angle = getAngle( p.px, p.py, p.px + p.vx, p.py + p.vy); var l = Math.sqrt(p.vx*p.vx + p.vy*p.vy); var df = 60; l = Math.pow(l / df, 0.75) * df; c.beginPath(); c.moveTo( p.px + l * Math.cos(angle) / 2, p.py + l * Math.sin(angle) / 2); c.lineTo( p.px - l * Math.cos(angle) / 2, p.py - l * Math.sin(angle) / 2); c.lineWidth = 1; c.strokeStyle = '#0f0'; c.stroke(); } else if (canvas.showDensity) { var h = canvas.cellSize; c.beginPath(); c.arc(p.px, p.py, h/20 * p.density / canvas.restDensity, 0, Tau, false); c.lineWidth = 1;//Math.cube(p.density / canvas.restDensity) * 2; c.strokeStyle = '#f44'; c.stroke(); } else if (canvas.showForces) { var angle = getAngle( p.px, p.py, p.px + p.fx, p.py + p.fy); var l = dist(0, 0, p.fx, p.fy); //var df = 60; //l = Math.pow(l / df, 0.75) * df; l *= 2 * canvas.scale; c.beginPath(); c.moveTo( p.px + l * Math.cos(angle), p.py + l * Math.sin(angle)); c.lineTo( p.px - l * Math.cos(angle), p.py - l * Math.sin(angle)); c.lineWidth = 1; var scale = 10; var pressure = p.density - canvas.restDensity; //c.strokeStyle = 'rgb(' // + Math.min(Math.round(pressure / canvas.restDensity * 255 * scale), 255).toString() // + ', 0, ' // + Math.min(Math.round(Math.abs(-pressure / canvas.restDensity) * 255 * scale), 255).toString() // + ')'; c.strokeStyle = '#ff0'; c.stroke(); } } } // cells if (canvas.showCells) { c.lineWidth = 1; //c.font = '16px Arial bold, sans-serif'; //c.textAlign = 'left'; //c.textBaseline = 'top'; for (var i = 0; i < canvas.cells.length; i++) { var cell = canvas.cells[i]; if (cell.particles.length > 0) { c.strokeStyle = cell.color; c.fillStyle = cell.color; c.strokeRect( 0.5 + cell.left, 0.5 + cell.top, cell.right - cell.left - 1, cell.bottom - cell.top - 1); //c.fillText( // cell.particles.length, // cell.left + 2, // cell.top + 2); } } } }; }