/** * Socket to Me World * * TODO object collisions * DONE grab, throw, freeze * TODO balls!! * TODO momentum response for object collisions * TODO fixed objects * TODO atmospherics: air pressure/friction DONE, wind * TODO projectiles */ jQuery.fn.move = function(params) { var radius = function(obj) { if(obj.isSphere == true) { return radius = obj.width/2; } return NaN } // TODO verify iot works var distance = function(a,b) { return (a > b) ? a - b : b - a; } var hasCollision = function(obj0, obj1) { var boolean = false; var position0 = $(obj0).position(); var position1 = $(obj1).position(); if ((obj0.isSphere == true) && (obj1.isSphere == true)) { var distX = distance(position0.left,position1.left); var distY = distance(position0.top,position1.top); radii = obj0.width + obj1.width/2; boolean = radii > Math.sqrt((distX*distX) + (distY*distY)); } else { } return boolean; }; var doPhysics = function(obj) { // var number = 0; var objPosition = $(obj).position(); //hits the side edge of the world if (((objPosition.left <= 0) && (obj.xVelocity < 0)) || ((objPosition.left + obj.width >= obj.parent.width) && (obj.xVelocity > 0))) { obj.xVelocity = 0 - obj.xVelocity; } else { /* $(obj.parent).children().each(function() { var collision = hasCollision(this, obj); if (collision == true) { } //TODO collisions not working var position = $(this).position(); if (obj == this) { //do nothing } else { // if they are in the same space, they could horizontally collide var maxDist = obj.height < this.height ? obj.height : this.height; var actualDist = objPosition.top < position.top ? position.top - objPosition.top: objPosition.top - position.top; if (actualDist < maxDist) { // game one if ((objPosition.left < (position.left + this.width)) && (obj.xVelocity > 0)) { obj.xVelocity = 0 - obj.xVelocity; } else if (((objPosition.left + obj.width) > position.left) && (obj.xVelocity < 0)) { obj.xVelocity = 0 - obj.xVelocity; } } } }); */ } //hits the top or bottom edge of the world if (((objPosition.top <= 0)&&(obj.yVelocity < 0)) || ((objPosition.top + obj.height >= obj.parent.height) && (obj.yVelocity > 0))) { obj.yVelocity = 0 - obj.yVelocity; //number += 2; } //apply atmospheric slowing force obj.yVelocity = ((100 - obj.parent.density) * obj.yVelocity)/100 obj.xVelocity = ((100 - obj.parent.density) * obj.xVelocity)/100 //apply gravity to velocity obj.yVelocity = obj.yVelocity + (obj.parent.gravity /obj.parent.frameRate); // clean up dross for smoother garbage collection, perhaps // return obj; // see if this is required or not }; /** * STEP FRAMES */ var stepFrame = function(obj) { if (obj.isPaused == false) { doPhysics(obj); // handle collisions var position = $(obj).position(); obj.style.top = Math.round(position.top+ Math.round(obj.yVelocity)) + "px"; obj.style.left = Math.round(position.left+Math.round(obj.xVelocity)) + "px"; if (obj.parent.debug == true) { $(obj.positionBox).html(obj.style.left + ',' + obj.style.top + '
(' + (Math.round(obj.xVelocity*1000)/1000) + ',' + (Math.round(obj.yVelocity*1000)/1000) +')' ); } } setTimeout(function() { stepFrame(obj) },1000/obj.parent.frameRate); }; /** * INITIALISE EACH OBJECT ANIMATION */ this.each(function() { stepFrame(this); }); } jQuery.fn.atom = function(params) { //setup; this.each(function(i) { var position = $(this).position(); this.parent = params.parent; this.width = $(this).innerWidth(); this.height = $(this).innerHeight(); this.isSphere = $(this).hasClass('ball') ? true : false ; this.xVelocity = (Math.random()*10.0) -5; //hard coded? this.yVelocity = (Math.random()*10.0) -5; //keep physical position, but be absolutely positioned this.style.top = Math.round(position.top) + "px"; this.style.left = Math.round(position.left) + "px"; //maybe random pos var topPos = Math.round(Math.random() * (this.parent.height - this.height)); var leftPos = Math.round(Math.random() * (this.parent.width - this.width)); this.style.top = topPos + "px"; this.style.left = leftPos + "px"; this.isPaused = false; if (this.parent.interactive == true) { //TODO add grab and release actions } if (this.parent.debug == true) { this.positionBox = $('
').appendTo(this); $(this.positionBox).html(this.style.left + ',' + this.style.top + ' (' + this.xVelocity + ',' + this.yVelocity +')' ); $(this.positionBox).attr('class', 'positionBox'); } /* $(this).mouseover( function(e) { if (this.override == null) { this.isPaused = true; } }); $(this).mouseout( function(e) { this.isPaused = false; } ); */ $(this).bind('mousedown',function(e){ if (this.fling == null) { this.fling = {}; this.fling.position = $(this).position(); this.fling.startDrag = new Date(); } this.isPaused = true; }); $(this).bind('drag',function(e){ if (this.parent.debug == true) { $(this.positionBox).html(this.style.left + ',' + this.style.top + ' (' + this.xVelocity + ',' + this.yVelocity +')' ); } //if we're dragging, then we want to listen for a release $(this).bind('mouseup',function(e){ if (this.fling != null) { var elapsedTime = new Date() - this.fling.startDrag; var flingFactor = this.parent.flingFactor; var newPosition = $(this).position(); var xFactor = newPosition.left - this.fling.position.left ; var yFactor = newPosition.top - this.fling.position.top this.xVelocity = xFactor*flingFactor/elapsedTime; this.yVelocity = yFactor*flingFactor/elapsedTime; this.fling = null; } this.isPaused = false; $(this).unbind('mouseup'); }); // listen for drag events that take it out of the world var objPosition = $(this).position(); if ((objPosition.left <= 0) || (objPosition.left + this.width >= this.parent.width) || (objPosition.top <= 0) || (objPosition.top + this.height >= this.parent.height)) { $(this).trigger('dragend'); } }); }); this.each( function(i) { this.style.position="absolute"; this.style.padding = 0; this.style.margin = 0; } ); } jQuery.fn.world = function(params) { this.start = function() { $(this).children().move({parent:this}); }; // setup params this.each(function(i){ //set params this.frameRate = 30; // per sec; this.bounce = 0.5; // gravity of the world. this.gravity = 1.0; // gravity of the world. this.density = 0.01; // friction slows motion down in all directions this.interactive = true; // can you grab em and throw em? this.collide = false; // do worlds collide? this.erode = false; // do worlds hurt each other this.width = $(this).outerWidth(); // width of the universe this.height = $(this).outerHeight(); // height of the universe this.flingFactor = 20; this.debug = false; // whether to put diagnostics on the screen //override params if (params) { if( params.frameRate) this.frameRate = params.frameRate; if( params.bounce) this.bounce = params.bounce; if( params.gravity) this.gravity = params.gravity; if( params.density) this.density = params.density; if( params.interactive) this.interactive = params.interactive; if( params.collide) this.collide = params.collide; if( params.erode) this.erode = params.erode; if( params.flingFactor) this.flingFactor = params.flingFactor; if( params.debug) this.debug = params.debug; } $(this).children().atom({parent:this}); this.width = $(this).outerWidth(); this.height = $(this).outerHeight(); }); return this; }