top of page
Search
cedarcantab

snippable box



let ctx = canvas.getContext('2d');

let pos = PosGrid(20,20,250,250, 20);

let vel = pos.map( () => [0,0]);

let force = pos.map( () => [0,0]);

let mass = pos.map( () => .1 + 100*Math.random());

let fixed = pos.map( () => false);

let [el_node, el_len] = ElementMesh(30);

let el_width = el_len.map(()=> 2*Math.random());

let g = 10;

let spring = 2000;

let max_strain = .2;

let mouse_x, mouse_y;

canvas.onmousemove = (e) => {

mouse_x = e.offsetX;

mouse_y = e.offsetY;

}

(function loop() {

SnipNear(mouse_x, mouse_y);

for (let i = 0; i < 20; i++) {

RemoveOverstrainedElements();

UpdateForce();

UpdateVelocity(.05);

UpdatePosition(.05);

}

DrawElements();

DrawNodes();

requestAnimationFrame(loop);

})();

/* - - - Functions - - - */

function DrawNodes() {

for (let node in pos) {

let x = pos[node][0];

let y = pos[node][1];

let s = Math.sqrt(mass[node]);

if (fixed[node]) {

ctx.fillStyle = '#cc0000';

ctx.fillRect(x-5, y-5, 10, 10);

} else {

ctx.fillStyle = '#001100';

ctx.fillRect(x-s/2,y-s/2,s,s);

}

}

}

function DrawElements(){

ctx.clearRect(0,0,canvas.width, canvas.height);

ctx.strokeStyle = '#000077';

for (let el in el_node) {

let [a,b] = el_node[el];

ctx.beginPath();

ctx.lineWidth = el_width[el];

ctx.moveTo(pos[a][0], pos[a][1]);

ctx.lineTo(pos[b][0], pos[b][1]);

ctx.stroke();

}

}

function ElementMesh(max_len) {

let el_node = [], el_len = [];

for (let a in pos) {

for (let b in pos) {

let dx = pos[b][0] - pos[a][0];

let dy = pos[b][1] - pos[a][1];

let L = Math.sqrt(dx*dx +dy*dy);

if (L > 0 && L < max_len) {

if (!el_node.includes([b,a])) {

el_node.push([a,b]);

el_len.push(L);

}

}

}

}

return [el_node, el_len];

}

function PosGrid(x,y,w,h, step){

let pos = [];

for (let X = x; X < x + w; X += step) {

for (let Y = y; Y < y + h; Y += step) {

pos.push( [X,Y]);

}

}

return pos;

}

function RemoveOverstrainedElements() {

for (let el in el_node) {

let a = el_node[el][0];

let b = el_node[el][1];

let dx = pos[b][0] - pos[a][0];

let dy = pos[b][1] - pos[a][1];

let L = Math.sqrt(dx*dx + dy*dy);

let L0 = el_len[el];

let strain = Math.abs((L - L0)/L0);

if (strain > max_strain) {

el_node.splice(el,1);

el_len.splice(el,1);

el_width.splice(el,1);

}

}

}

function SnipNear(x,y, radius=20) {

for (let el in el_node) {

let a = el_node[el][0];

let b = el_node[el][1];

let dx = x - (pos[b][0] + pos[a][0])/2;

let dy = y - (pos[b][1] + pos[a][1])/2;

let L = Math.sqrt(dx*dx + dy*dy);

if (L < radius) {

el_node.splice(el,1);

el_len.splice(el,1);

el_width.splice(el,1);

}

}

}

function UpdateForce() {

for (let node in force) {

force[node][0] = 0;

force[node][1] = g;

}

for (let el in el_node) {

let a = el_node[el][0];

let b = el_node[el][1];

let dx = pos[b][0] - pos[a][0];

let dy = pos[b][1] - pos[a][1];

let L = Math.sqrt(dx*dx + dy*dy);

let L0 = el_len[el];

let strain = (L - L0)/L0;

let fx = (dx/L)*strain*spring;

let fy = (dy/L)*strain*spring;

force[a][0] += fx;

force[a][1] += fy;

force[b][0] -= fx;

force[b][1] -= fy;

}

}

function UpdatePosition(dt) {

for (let node in pos) {

pos[node][0] += vel[node][0]*dt;

pos[node][1] += vel[node][1]*dt;

if (pos[node][1] > canvas.height) {

pos[node][1] = canvas.height;

vel[node][1] *= -.95;

}

}

}

function UpdateVelocity(dt) {

for (let node in vel) {

if (!fixed[node]){

let fx = force[node][0];

let fy = force[node][1];

let m = mass[node];

vel[node][0] *= .999;

vel[node][1] *= .999;

vel[node][0] += fx/m*dt;

vel[node][1] += fy/m*dt;

}

}

}

3 views0 comments

Recent Posts

See All

p2 naive broadphase

var Broadphase = require('../collision/Broadphase'); module.exports = NaiveBroadphase; /** * Naive broadphase implementation. Does N^2...

sopiro motor constranit

import { Matrix2, Vector2 } from "./math.js"; import { RigidBody } from "./rigidbody.js"; import { Settings } from "./settings.js";...

Comments


記事: Blog2_Post
bottom of page