var Verlet = function(Width, Height) { this.Masses = []; this.Constraints = []; this.Width = Width; this.Height = Height; this.AddMass = function(Mass) { this.Masses.push(Mass); } this.Update = function(TimeDelta) { for (k in this.Masses) { var m = this.Masses[k]; if (typeof(m) == "function") continue; m.Update(TimeDelta, {X: this.Width, Y: this.Height}); } } } var Mass = function(X, Y, Weight) { this.Weight = Weight; this.PX = this.X = X; this.PY = this.Y = Y; this.Active = true; this.Update = function(TimeDelta, Bounds) { if (!this.Active) return; // do a verlet step var VX = this.X - this.PX; var VY = this.Y - this.PY; this.PX = this.X; this.PY = this.Y; // add gravity (mgt^2/2) VY = VY + (this.Weight * (9.98 * (TimeDelta*TimeDelta)) / 2) * 100; // add speed to X, Y this.X = this.X + VX; this.Y = this.Y + VY; // console.log(this); // limit to bounds if (this.Y < 0) { this.Y = 0; this.VY = 0; } if (this.X < 0) { this.X = 0; this.VX = 0; } if (this.Y > Bounds.Y) { this.Y = Bounds.Y; this.VY = 0; } if (this.X > Bounds.X) { this.X = Bounds.X; this.VX = 0; } } } var v = new Verlet(800, 600); v.AddMass(new Mass(5, 5, 1)); v.AddMass(new Mass(20, 5, 1)); v.AddMass(new Mass(35, 5, 1)); var c = document.getElementById("main"); var ctx = c.getContext('2d'); c.width = 800; c.height = 600; setInterval(function() { ctx.fillStyle = '#000000'; ctx.beginPath(); ctx.rect(0, 0, 800, 600); ctx.closePath(); ctx.fill(); v.Update(1/50); ctx.fillStyle = '#FFFFFF'; for (k in v.Masses) { var m = v.Masses[k]; if (typeof(m) == "function") continue; ctx.beginPath(); ctx.arc(m.X, m.Y, 5, 0, Math.PI*2, true); ctx.closePath(); ctx.fill(); } }, 1000/50); var DragID = -1; var DragOffsetX = 0; var DragOffsetY = 0; var DragMoveListener = function(e) { var MouseX = e.layerX - c.offsetLeft; var MouseY = e.layerY - c.offsetTop; var m = v.Masses[DragID] m.PX = m.X; m.PY = m.Y; m.X = MouseX + DragOffsetX; m.Y = MouseY + DragOffsetY; } var DragEndListener = function(e) { v.Masses[DragID].Active = true; DragID = -1; c.removeEventListener("mouseup", DragEndListener); c.removeEventListener("mousemove", DragMoveListener); c.addEventListener("mousedown", DragStartListener); } var DragStartListener = function(e) { var MouseX = e.layerX - c.offsetLeft; var MouseY = e.layerY - c.offsetTop; for (k in v.Masses) { var m = v.Masses[k]; if (typeof(m) == "function") continue; var DX = MouseX - m.X; var DY = MouseY - m.Y; if (Math.sqrt((DX*DX) + (DY*DY)) < 5) { DragID = k; DragOffsetX = DX; DragOffsetY = DY; m.Active = false; c.removeEventListener("mousedown", DragStartListener); c.addEventListener("mousemove", DragMoveListener); c.addEventListener("mouseup", DragEndListener); } } } c.addEventListener("mousedown", DragStartListener);