Created
February 12, 2012 16:53
-
-
Save keiya/1809622 to your computer and use it in GitHub Desktop.
physical simulator on dom
This 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 characters
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <meta http-equiv="X-UA-Compatible" content="IE=edge" /> | |
| <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> | |
| <title>phyjics</title> | |
| <meta name="viewport" content="initial-scale=0.9, minimum-scale=0.9, maximum-scale=1.1" /> | |
| <meta name="apple-mobile-web-app-capable" content="yes" /> | |
| <meta name="apple-mobile-web-app-status-bar-style" content="black" /> | |
| <script src="http://cdn.keiyac.org/common/jquery/jquery.min.js" type="text/javascript"></script> | |
| <script src="ph.js" defer></script> | |
| <style type="text/css"> | |
| .collision { | |
| border: 1px solid #f00; | |
| } | |
| .wall-a { | |
| position:absolute; | |
| bottom: 120px; | |
| left: 100px; | |
| width: 800px; | |
| height: 50px; | |
| background-color: #ccc; | |
| border:1px solid #111; | |
| } | |
| .ball-a { | |
| position:absolute; | |
| top: 100px; | |
| right: 190px; | |
| width: 100px; | |
| height: 100px; | |
| background-color: #ccc; | |
| border:1px solid #111; | |
| } | |
| .ball-b { | |
| position:absolute; | |
| top: 0px; | |
| left: 190px; | |
| width: 100px; | |
| height: 100px; | |
| background-color: #ccc; | |
| border:1px solid #111; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div | |
| class='collision-a wall-a editable' | |
| data-mass='10' | |
| data-acc-x='0' | |
| data-acc-y='0' | |
| data-iv-x='0' | |
| data-iv-y='0' | |
| data-fixed='1' | |
| > | |
| </div> | |
| <div | |
| class='collision-a ball-b editable' | |
| data-mass='10' | |
| data-acc-x='0' | |
| data-acc-y='9.81' | |
| data-iv-x='0' | |
| data-iv-y='0' | |
| > | |
| </div> | |
| <pre id='dbg'></pre> | |
| <script> | |
| function dbg(text) { | |
| $('#dbg').append(text+"\n"); | |
| } | |
| window.requestAnimationFrame = (function(){ | |
| return window.requestAnimationFrame || | |
| window.webkitRequestAnimationFrame || | |
| window.mozRequestAnimationFrame || | |
| window.oRequestAnimationFrame || | |
| window.msRequestAnimationFrame || | |
| function(callback, element){ | |
| window.setTimeout(callback, 1000 / 60); | |
| }; | |
| })(); | |
| $(document).ready(function(){ | |
| // phjics init | |
| // inherit from Objects | |
| var ObjClassA = function () { | |
| this._constructor('.collision-a'); | |
| } | |
| ObjClassA.prototype = new Objects(); | |
| // instance | |
| var coll_a = new ObjClassA(); | |
| //var coll_a = new Objects('.collision-a'); | |
| var pos = coll_a.getPositionAll(); | |
| var lastClock = +new Date(); | |
| function mainLoop() { | |
| var currClock = +new Date(); | |
| // coll_a.applyGravity((currClock-lastClock)/1000); | |
| coll_a.collisionChk(); | |
| coll_a.applyVector((currClock-lastClock)/1000); | |
| coll_a.setPosition(); | |
| lastClock = currClock; | |
| requestAnimationFrame(mainLoop); | |
| } | |
| mainLoop(); | |
| // Interface | |
| var coll_a = new Objects('.collision-a'); | |
| }); | |
| </script> | |
| </body> | |
| </html> |
This 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 characters
| // keiyac | |
| // 2012.02.12 | |
| // 2012.02.16 | |
| // physical constants | |
| const G = 6.67; | |
| const g = 9.81; | |
| // pseudo constructor | |
| var Objects = function (selector) { | |
| this._constructor(selector); | |
| } | |
| // methods | |
| Objects.prototype = { | |
| _constructor : function(selector) { | |
| var objs = []; | |
| var _this = this; | |
| $(selector).each(function(){ | |
| var obj = {}; | |
| obj.pos = _this.getPosition(this); | |
| obj.mass = parseFloat($(this).attr('data-mass')); | |
| var regionEndsX = (obj.pos.x + obj.pos.width)/2; | |
| var barycenterOfsX = obj.pos.width/2; | |
| var barycenterOfsY = obj.pos.height/2; | |
| var barycenterAbsX = obj.pos.x + barycenterOfsX; | |
| var barycenterAbsY = obj.pos.y + barycenterOfsY; | |
| obj.absBarycenter = {x:barycenterOfsX,y:barycenterOfsY}; | |
| obj.offsetBarycenter = {x:barycenterAbsX,y:barycenterOfsY}; | |
| obj.acceleration = {}; | |
| obj.acceleration.x = parseFloat($(this).attr('data-acc-x')); | |
| obj.acceleration.y = parseFloat($(this).attr('data-acc-y')); | |
| obj.velocity = {}; | |
| obj.velocity.x = parseFloat($(this).attr('data-iv-x')); | |
| obj.velocity.y = parseFloat($(this).attr('data-iv-y')); | |
| obj.fixed = parseInt($(this).attr('data-fixed')); | |
| obj.dom = this; | |
| objs.push(obj); | |
| }); | |
| $(selector+',editable').click(function(){ | |
| }); | |
| this.objs = objs; | |
| }, | |
| dumpObj : function() { | |
| console.dir(this.objs); | |
| }, | |
| getPositionAll : function() { | |
| var _this = this; | |
| var positions = []; | |
| $.each(this.objs,function(){ | |
| positions.push(_this.getPosition(this.dom)); | |
| }); | |
| return positions; | |
| }, | |
| getPosition : function(selection) { | |
| var pos = {}; | |
| pos.width= $(selection).width(); | |
| pos.height = $(selection).height(); | |
| var offset = $(selection).offset(); | |
| pos.x = parseFloat(offset.left); | |
| pos.y = parseFloat(offset.top); | |
| return pos; | |
| }, | |
| setPosition : function() { | |
| $.each(this.objs,function(){ | |
| $(this.dom).css({'left':this.pos.x,'top':this.pos.y}); | |
| }); | |
| }, | |
| collisionChk : function() { | |
| //$.each(_this.objs,function(){ | |
| skip: for (i in this.objs) { | |
| //var obj_a = this; | |
| var obj_a = this.objs[i]; | |
| //$.each(_this.objs,function(){ | |
| for (j in this.objs) { | |
| // var obj_b = this; | |
| var obj_b = this.objs[j]; | |
| if (obj_a !== obj_b) { | |
| // vertices | |
| var objectA = {}; | |
| var objectB = {}; | |
| objectA.A = {}; | |
| objectA.B = {}; | |
| objectA.C = {}; | |
| objectA.D = {}; | |
| objectB.A = {}; | |
| objectB.B = {}; | |
| objectB.C = {}; | |
| objectB.D = {}; | |
| objectA.A.x = obj_a.pos.x; // top left | |
| objectA.B.x = obj_a.pos.x + obj_a.pos.width; // top right | |
| objectA.C.x = obj_a.pos.x; // bottom left | |
| objectA.D.x = obj_a.pos.x + obj_a.pos.width; // bottom right | |
| objectA.A.y = obj_a.pos.y; // top left | |
| objectA.B.y = obj_a.pos.y + obj_a.pos.height; // bottom left | |
| objectA.C.y = obj_a.pos.y; // top right | |
| objectA.D.y = obj_a.pos.y + obj_a.pos.height; // bottom right | |
| objectB.A.x = obj_b.pos.x; // top left | |
| objectB.B.x = obj_b.pos.x + obj_b.pos.width; // top right | |
| objectB.C.x = obj_b.pos.x; // bottom left | |
| objectB.D.x = obj_b.pos.x + obj_b.pos.width; //bottom right | |
| objectB.A.y = obj_b.pos.y; // top left | |
| objectB.B.y = obj_b.pos.y + obj_b.pos.height; // bottom left | |
| objectB.C.y = obj_b.pos.y; // top right | |
| objectB.D.y = obj_b.pos.y + obj_b.pos.height; // bottom right | |
| var combination = [ | |
| ['A','B'], | |
| ['A','C'], | |
| ['D','B'], | |
| ['D','C'], | |
| ]; | |
| nextObj: for (lineA in combination) { | |
| startVertexNameA = combination[[lineA]][0]; | |
| endVertexNameA = combination[[lineA]][1]; | |
| for (lineB in combination) { | |
| startVertexNameB = combination[[lineB]][0]; | |
| endVertexNameB = combination[[lineB]][1]; | |
| var collision = this._isCrossLine( | |
| objectA[startVertexNameA].x, objectA[startVertexNameA].y, | |
| objectA[endVertexNameA].x, objectA[endVertexNameA].y, | |
| objectB[startVertexNameB].x, objectB[startVertexNameB].y, | |
| objectB[endVertexNameB].x, objectB[endVertexNameB].y | |
| ) | |
| if (collision) { | |
| //;//console.log(collision); | |
| this.applyCollision(obj_a,obj_b); | |
| //this.objs[i] = obj[0]; | |
| //this.objs[j] = obj[1]; | |
| break skip; | |
| } | |
| } | |
| } | |
| } | |
| //}); | |
| // }); | |
| } | |
| } | |
| }, | |
| applyCollision : function(a,b) { | |
| var t; | |
| var vx = (b.pos.x - a.pos.x); | |
| var vy = (b.pos.y - a.pos.y); | |
| t = -(vx * a.velocity.x + vy * a.velocity.y) / (vx * vx + vy * vy); | |
| var arx = a.velocity.x + vx * t; | |
| var ary = a.velocity.y + vy * t; | |
| t = -(-vy * a.velocity.x + vx * a.velocity.y) / (vy * vy + vx * vx); | |
| var amx = a.velocity.x - vy * t; | |
| var amy = a.velocity.y + vx * t; | |
| t = -(vx * b.velocity.x + vy * b.velocity.y) / (vx * vx + vy * vy); | |
| var brx = b.velocity.x + vx * t; | |
| var bry = b.velocity.y + vy * t; | |
| t = -(-vy * b.velocity.x + vx * b.velocity.y) / (vy * vy + vx * vx); | |
| var bmx = b.velocity.x - vy * t; | |
| var bmy = b.velocity.y + vx * t; | |
| var e = 0.9; | |
| if (a.fixed != 1) { | |
| a.velocity.x = (a.mass * amx + b.mass * bmx + bmx * e * b.mass - amx * e * b.mass) / (a.mass + b.mass); | |
| a.velocity.y = (a.mass * amy + b.mass * bmy + bmy * e * b.mass - amy * e * b.mass) / (a.mass + b.mass); | |
| a.acceleration.x = amx; | |
| a.acceleration.y = amy; | |
| } | |
| if (b.fixed != 1) { | |
| b.velocity.x = - e * (bmx - amx) + a.velocity.x; | |
| b.velocity.y = - e * (bmy - amy) + a.velocity.y; | |
| b.acceleration.x = amx; | |
| b.acceleration.y = bmy; | |
| } | |
| /* | |
| a.velocity.x = a.velocity.x + arx; | |
| a.velocity.y = a.velocity.y + ary; | |
| b.velocity.x = b.velocity.x + brx; | |
| b.velocity.y = b.velocity.y + bry; | |
| */ | |
| }, | |
| applyGravity : function(t) { | |
| for (idx in this.objs) { | |
| //var z = -0.5*g*t*t + Math.sin() * t; | |
| var delta_z = 0.5*g*t*t; | |
| if (this.objs[idx]['pos']['y'] < $(window).height() - this.objs[idx]['pos']['height']) | |
| this.objs[idx]['pos']['y'] += delta_z; | |
| } | |
| }, | |
| applyVector : function(dt) { | |
| for (idx in this.objs) { | |
| this.objs[idx]['velocity']['x'] += this.objs[idx]['acceleration']['x'] * dt; | |
| this.objs[idx]['velocity']['y'] += this.objs[idx]['acceleration']['y'] * dt; | |
| var x = this.objs[idx]['velocity']['x'] * dt; | |
| var y = this.objs[idx]['velocity']['y'] * dt; | |
| // if (this.objs[idx]['pos']['y'] < $(window).height() - this.objs[idx]['pos']['height']) { | |
| this.objs[idx]['pos']['y'] += y; | |
| // } | |
| this.objs[idx]['pos']['x'] += x; | |
| } | |
| }, | |
| _isCrossLine : function( | |
| x1,y1, | |
| x2,y2, | |
| x3,y3, | |
| x4,y4 | |
| ) { | |
| if (((x1-x2)*(y3-y1) + (y1-y2)*(x1-x3)) * | |
| ((x1-x2)*(y4-y1) + (y1-y2)*(x1-x4)) < 0 ) { | |
| if (((x3-x4)*(y1-y3) + (y3-y4)*(x3-x1)) * | |
| ((x3-x4)*(y2-y3) + (y3-y4)*(x3-x2)) < 0 ) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment