"http://cs.kenji-special.info/#pen/bNJLpg"
Bootstrap 3.3.0 Snippet by sergioaclo

<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css"> <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.0/js/bootstrap.min.js"></script> <script src="//code.jquery.com/jquery-1.11.1.min.js"></script> <!------ Include the above in your HEAD tag ----------> <canvas id="c"></canvas>
http://cs.kenji-special.info/#pen/bNJLpg
var floor; var ctx; var balls = []; window.onload = function(){ var canvas = document.getElementById('c'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; ctx = canvas.getContext('2d'); floor = new Floor(window.innerWidth/2 - 60, window.innerHeight/2 - 50, 100, 100); //_mass, _rad, _pos, _vel for(var ii = 0; ii < 1200; ii++){ var random = Math.random(); var vel = new Vector2(); if(random < .25) vel.set(100 + 100 * Math.random(), 0); else if(random < .5) vel.set(100 + 100 * Math.random(), 0); else if(random < .75) vel.set(0, -100 - 100 * Math.random()); else vel.set(0, 100 + 100 * Math.random()); var ball = new Ball( 1,1, new Vector2(window.innerWidth * (Math.random() + Math.random() )/2, window.innerHeight * (Math.random() + Math.random()) /2), vel); balls.push(ball) } loop(); } function loop () { this.ctx.fillStyle = "rgba(255, 255, 255, .08)"; this.ctx.fillRect(0, 0, window.innerWidth, window.innerHeight); floor.update(); for(var ii = 0; ii < balls.length; ii++){ balls[ii].update(); } floor.draw(ctx); for(var ii = 0; ii < balls.length; ii++){ balls[ii].draw(ctx); floor.getClosestPoints(balls[ii], ctx); } requestAnimationFrame(loop); } var CONSTANTS = { gravity : 10, timeStep : 1 / 30, }; // -------------------------------- var Vector2 = function(obj) { var v = new Float32Array(2); if (obj) { if (arguments.length == 1) { v[0] = obj[0]; v[1] = obj[1]; } else if (arguments.length == 2) { v[0] = arguments[0]; v[1] = arguments[1]; } }else{ v[0] = 0; v[1] = 0; } this.elements = v; }; Vector2.prototype.copy = function() { var vec = new Vector2(this.elements); return vec; }; Vector2.prototype.subtract = function(vec) { if (vec && typeof vec === 'object') { this.elements[0] = this.elements[0] - vec.elements[0]; this.elements[1] = this.elements[1] - vec.elements[1]; } return this; }; Vector2.prototype.set = function(x, y) { this.x = x; this.y = y; return this; } Vector2.prototype.subtractMultipledVector = function( value, vector) { this.x -= value * vector.x; this.y -= value * vector.y; return this; } Vector2.prototype.addMultipledVector = function( value, vector) { this.x += value * vector.x; this.y += value * vector.y; return this; } Vector2.prototype.multiply = function(value) { if (value && typeof value === 'number') { this.elements[0] = this.elements[0] * value; this.elements[1] = this.elements[1] * value; } return this; }; /** * @function * @desc add vector * * @param {Vector2} vec */ Vector2.prototype.add = function(vec) { if (vec && typeof vec === 'object') { this.elements[0] = this.elements[0] + vec.elements[0]; this.elements[1] = this.elements[1] + vec.elements[1]; } return this; }; // ============================= /** * @function * @desc get the length of the vector * * @return {Number} */ Vector2.prototype.getLength = function() { return Math.sqrt( this.x * this.x + this.y * this.y ); } /** * @function * @desc get the normalized vector * * @return {Vector2} */ Vector2.prototype.getNormal = function() { var length = this.getLength(); return new Vector2( this.x / length, this.y / length ); } /** * @function * @desc get the vector compare with vector of minVec to see which is smaller * * @param {Vector2} minVec * @return {Vector2} */ Vector2.prototype.min = function( minVec ) { if(this.x > minVec.x) this.x = minVec.x; if(this.y > minVec.y) this.y = minVec.y; return this; } /** * @function * @desc get the vector compared with the vector of maxVector to see which is bigger * * @param {Vector2} maxVec * @return {Vector2} */ Vector2.prototype.max = function( maxVec ) { if(this.x < maxVec.x) this.x = maxVec.x; if(this.y < maxVec.y) this.y = maxVec.y; return this; } /** * @function * @desc get the vector compare with vector between minVec and maxVec * * @param {Vector2} minVec * @param {Vector2} maxVec */ Vector2.prototype.clamp = function( minVec, maxVec ) { return this.max(minVec).min(maxVec); } /** * @function * @desc * @see http://mathworld.wolfram.com/RotationMatrix.html * * @param {Number} theta */ Vector2.prototype.rotate = function(theta) { var rotatedX = this.x * Math.cos(theta) - this.y * Math.sin(theta); var rotatedY = this.x * Math.sin(theta) + this.y * Math.cos(theta); return this.set(rotatedX, rotatedY) }; // ============================= function Matrix () { this.cos = 0.0; this.sin = 0.0; this.pos = new Vector2(); this.ang = 0.0; } Matrix.prototype = { set: function(a, x, y) { this.cos = Math.cos(a); this.sin = Math.sin(a); this.ang = a; this.pos.x = x; this.pos.y = y; return this; } } // ============================= Object.defineProperty(Vector2.prototype, 'x', { get: function() { return this.elements[0]; }, set: function(val) { this.elements[0] = val; } }); Object.defineProperty(Vector2.prototype, 'y', { get: function() { return this.elements[1]; }, set: function(val) { this.elements[1] = val; } }); var RigidBody = function( mass, width, height, pos, vel ) { //if(!instanceOf velVector) this.velVector = this.mass = mass; this.width = width; this.height = height; this.pos = pos; this.vel = vel; this.force = new Vector2(0, 0); } RigidBody.prototype.update = function(dt) { // -------------------- //this.vel.x += this.force.x / this.mass; //this.vel.y += this.force.y / this.mass; // ==================== this.pos.x += this.vel.x /30; this.pos.y += this.vel.y /30; // ==================== this.force.set(0, 0); }; RigidBody.prototype.setForce = function( xx, yy) { this.force.x += xx; this.force.x += xx; }; RigidBody.prototype.setGravity = function() { this.force.y += this.mass * CONSTANTS.gravity; }; RigidBody.prototype.getClosestPoints = function(rb) { console.error("===== NO getClosestPoints IN RigidBody ====="); } // =============================== var Floor = function(x, y, wid, hig) { RigidBody.call(this, 0, wid, hig, new Vector2(x + wid/2, y + hig/2), new Vector2(0, 0)); this.matrix = new Matrix(); this.theta = 0; this.matrix.set(this.theta, 0, 0); this.halfExtendMinus = new Vector2( -wid/2, -hig/2 ); this.halfExtendPlus = new Vector2( wid/2, hig/2 ); } Floor.prototype = Object.create(RigidBody.prototype); Floor.prototype.constructor = Floor; Floor.prototype.update = function() { this.theta += Math.PI/60; } Floor.prototype.draw = function(ctx) { /* ctx.save(); ctx.strokeStyle = "#000000"; ctx.beginPath(); ctx.translate(this.pos.x, this.pos.y); ctx.rotate(this.theta); ctx.strokeRect(-this.width/2, -this.height/2, this.width, this.height); ctx.restore(); */ } Floor.prototype.debugDraw = function(ctx) { } Floor.prototype.getClosestPoints = function(ball, ctx) { var rectangelA = this; var ballB = ball; var xPos = ballB.pos.x - rectangelA.pos.x; var yPos = ballB.pos.y - rectangelA.pos.y; var delta = new Vector2(); delta.set(xPos, yPos); var rotatedDeltaX = delta.x * this.matrix.cos + delta.y * this.matrix.sin; var rotatedDeltaY = -delta.x * this.matrix.sin + delta.y * this.matrix.cos; var rotatedVector = new Vector2( rotatedDeltaX, rotatedDeltaY ); var dClamped = rotatedVector.clamp(this.halfExtendMinus, this.halfExtendPlus); var clamped = dClamped.rotate(this.theta); var clamedP = this.pos.copy().add(clamped); var d = new Vector2( ballB.pos.x - clamedP.x, ballB.pos.y - clamedP.y); var n = d.getNormal(); var na = clamedP; var pb = ballB.pos.copy().subtractMultipledVector(ballB.radius, n); var dist = d.getLength() - ballB.radius; var dis = Math.sqrt(window.innerWidth * window.innerWidth + window.innerHeight * window.innerHeight); opacity = .02 * (1 - dist/dis); if(opacity < 0) opacity = 0; ctx.strokeStyle = "rgba(0, 0, 0, " + opacity + ")"; ctx.beginPath(); ctx.moveTo( clamedP.x, clamedP.y); ctx.lineTo( clamedP.x + d.x, clamedP.y + d.y); ctx.stroke(); }; // ------------------------------------- var Ball = function( _mass, _rad, _pos, _vel ) { RigidBody.call(this, _mass, _rad, _rad, _pos, _vel); this.radius = _rad; }; Ball.prototype = Object.create(Ball.prototype); Ball.prototype.constructor = Ball; Ball.prototype.update = function( dt ) { RigidBody.prototype.update.call(this, dt); } Ball.prototype.draw = function(ctx) { this.changePosAndVel() }; Ball.prototype.changePosAndVel = function() { if(this.vel.x > 0){ if(this.pos.x > window.innerWidth + 0){ this.pos.x = -50 - 50 * Math.random(); this.pos.y = window.innerHeight * (Math.random() + Math.random())/2; } }else if(this.vel.x < 0){ if(this.pos.x < 0){ this.pos.x = window.innerWidth + 50 * (Math.random() + Math.random())/2; this.pos.y = window.innerHeight * Math.random(); } }else if(this.vel.y > 0){ if(this.pos.y > window.innerHeight + 50){ this.pos.x = window.innerWidth * (Math.random() + Math.random())/2; this.pos.y = -50 - 50 * Math.random(); } }else if(this.vel.y < 0){ if(this.pos.y < 0){ this.pos.x = window.innerWidth * Math.random(); this.pos.y = window.innerHeight + 50 + 50 * (Math.random() + Math.random())/2; } } } Ball.prototype.getClosestPoints = function(rBody) { var contacts; var ballA = this; if(rBody instanceof Ball){ var ballB = rBody; var delata = new Vector2( ballA.x - ballB.x, ballA.y - ballB.y ); var n; if( delata.getLength() ){ n = delata.getNormal(); }else{ n = new Vector2(1, 0); } // generate closes points var pa = new Vector2(); pa.x = ballA.pos.x + n.x * this.radius; pa.y = ballA.pos.y + n.y * this.radius; var pb = new Vector2(); pb.x = ballB.pos.x - n.x * this.radius; pb.y = ballB.pos.y - n.y * this.radius; // getdistance var dist = delata.getLength() - (ballA.radius + ballB.radius); }else if(rBody instanceof Floor){ var rectangleB = rBody; }else{ console.error("===== NO getClosestPoints IN Ball ====="); } return contacts; }

Related: See More


Questions / Comments: