From 3bddc3172165312ef1deeda180125ff7cd30ddfc Mon Sep 17 00:00:00 2001 From: Ronen Date: Fri, 2 Oct 2015 13:56:37 +0300 Subject: [PATCH] updated build to version 1.3 and updated docs --- README.md | 40 +++++++++++++++++++++++++++++++++++++--- dist/sscd.1.3.js | 14 +++++++++++--- dist/sscd.1.3.min.js | 2 +- 3 files changed, 49 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 0573584..7ec445b 100644 --- a/README.md +++ b/README.md @@ -271,13 +271,40 @@ var collide_with = world.pick_object(player_shape); // if object found, use repel to prevent penetration if (collide_with) { - collide_with.repel(player_shape, 1, 1); + collide_with.repel(player_shape, 10, 5); // here we will set the position of the player sprite to match its collision body.. } ``` -As you can see repel() is very simple. First param is which shape or vector to push outside, second param is pushing force, and last param is how many iterations of repel to run, while in every iteration we check if shapes still collide and push if they do. +As you can see repel() is very simple. + +First param is which shape or vector to push outside, second param is pushing force, and last param is how many iterations of repel to run (every iteration will check if the shapes still collide and will only push if they do). +You can play with the force and number of iterations to balance between performance and accuracy. Weak force with lots of iterations will be smoother but more processing, strong force with few iterations will be faster but less accurate and more rough. + +#### repel both ways + +repel() accept two additional params: factor_self and factor_other. +factor_self is a multiplier for the repelling force to apply on self while repelling. By default factor_self is 0, meaning the object doing the repelling will not be affected and will only push the other. +factor_other is the multiplier for repelling the other object, which defaults to 1. + +So if you want to do a repelling force that will move both objects away from each other equally, you can simply do: + +```javascript + +monster.repel(player_shape, 10, 5, 1, 1); + +``` + +You can also use these factors to simulate mass differences: + +```javascript + +var monster_mass = 120; +var player_mass = 80; +monster.repel(player_shape, 10, 5, player_mass / monster_mass, monster_mass / player_mass); + +``` Note that while this method is good enough to get you started, for a serious game you'd probably want to implement a better penetration resolving algorithm. @@ -287,7 +314,7 @@ SSCD is very memory-efficient, and should not pose any problems. However, note that the world grid does not clean itself automatically, meaning that if you move objects around over time you will get some empty world chunks. Those empty grid chunks are left by design; they take really small amount of memory and by leaving them in memory its quicker to move objects back into them. -If this insignificant memory waste really bother you, you can tell the collision world to cleanup any unused grid chunks by calling: +If this insignificant memory waste really bother you, you can tell the collision world to clean-up any unused grid chunks by calling: ```javascript world.cleanup(); @@ -312,6 +339,13 @@ world.cleanup(); - Added performance examples. Note: building this version before attempting to become npm compliance. + +### 1.3 + +- Fixed potential bug that vector of (0, 0) turns NaN on normalize. This caused issues when trying to prevent penetration between two objects with the same center. +- Fixed some javascript warnings etc. +- Made fully npm compatible. +- Added factor_self & factor_other to repel(), which make it possible for objects to repel each other simultaneously. ## License SSCD is provided under the zlib-license, and is absolutely free for use for educational & commercial purposes. diff --git a/dist/sscd.1.3.js b/dist/sscd.1.3.js index 9fa9c63..11f44b5 100644 --- a/dist/sscd.1.3.js +++ b/dist/sscd.1.3.js @@ -1184,16 +1184,23 @@ SSCD.Shape.prototype = { // obj: object or vector to repeal (must have move() function). // force: force factor, the bigger this is the stronger / faster the repealing will be. default to 1. // iterations: max iterations of repeal-and-test-again routines. default to 1. + // factor_self: factor to multiply force that will apply on this shape. default to 0. + // factor_other: factor to multiply force that will apply on this shape. default to 1. // NOTE: this function assume there's collision on start, meaning first iteration of repeal will ALWAYS happen. // return: total movement due to repeling (vector) - repel: function(obj, force, iterations) + repel: function(obj, force, iterations, factor_self, factor_other) { // set defaults force = force || 1; iterations = iterations || 1; + if (factor_self === undefined) factor_self = 0; + if (factor_other === undefined) factor_other = 1; - // get direction vector + // get push vectors + var push_vector_other, push_vector_self; var push_vector = this.get_repel_direction(obj).multiply_scalar_self(force); + if (factor_other) push_vector_other = push_vector.multiply_scalar(factor_other); + if (factor_self) push_vector_self = push_vector.multiply_scalar(factor_self * -1); // for return value var ret = SSCD.Vector.ZERO.clone(); @@ -1206,7 +1213,8 @@ SSCD.Shape.prototype = { iterations--; // do pushing - obj.move(push_vector); + if (push_vector_other) obj.move(push_vector_other); + if (push_vector_self) this.move(push_vector_self); ret.add_self(push_vector); // check if still colliding diff --git a/dist/sscd.1.3.min.js b/dist/sscd.1.3.min.js index 72b24f6..d835a77 100644 --- a/dist/sscd.1.3.min.js +++ b/dist/sscd.1.3.min.js @@ -1 +1 @@ -var SSCD=SSCD||{};SSCD.VERSION=1.3,SSCD.World=function(t){t=t||{},t.grid_size=t.grid_size||512,t.grid_error=void 0!==t.grid_error?t.grid_error:2,this.__grid={},this.__params=t,this.__all_shapes={},this.__collision_tags={},this.__next_coll_tag=0},SSCD.World.prototype={__create_collision_tag:function(t){if(this.__collision_tags[t])throw new SSCD.IllegalActionError("Collision tag named '"+t+"' already exist!");this.__collision_tags[t]=1<this.__params.grid_error||Math.abs(i.position.y-t.__last_insert_aabb.position.y)>this.__params.grid_error||Math.abs(i.size.x-t.__last_insert_aabb.size.x)>this.__params.grid_error||Math.abs(i.size.y-t.__last_insert_aabb.size.y)>this.__params.grid_error)&&(this.remove(t),this.add(t))},pick_object:function(t,i){var _=[];return this.test_collision(t,i,_,1)?_[0]:null},test_collision:function(t,i,_,e){return i=this.__get_tags_value(i),t instanceof SSCD.Vector?this.__test_collision_point(t,i,_,e):t.is_shape?this.__test_collision_shape(t,i,_,e):void 0},__test_collision_point:function(t,i,_,e){var s=this.__params.grid_size,o=Math.floor(t.x/s),n=Math.floor(t.y/s);if(void 0===this.__grid[o]||void 0===this.__grid[o][n])return!1;for(var r=this.__grid[o][n],a=0,o=0;o=e)return!0}}return a>0},__test_collision_shape:function(t,i,_,e){var s;s=t.__world===this?t.__grid_bounderies:this.__get_grid_range(t);for(var o=0,n={},r=s.min_x;r<=s.max_x;++r)if(void 0!==this.__grid[r])for(var a=s.min_y;a<=s.max_y;++a){var l=this.__grid[r][a];if(void 0!==l)for(var h=0;h=e)return!0}}}return o>0},__do_collision:function(t,i){return t.test_collide_with(i)},render:function(t,i,_,e){i=i||SSCD.Vector.ZERO,void 0===_&&(_=!0),void 0===e&&(e=!0);var s=t.getContext("2d");s.setTransform(1,0,0,1,0,0);for(var o=this.__params.grid_size,n=Math.floor(i.x/o),r=Math.floor(i.y/o),a=n+Math.ceil(t.width/o),l=r+Math.ceil(t.height/o),h=[],c=n;a>=c;++c)for(var S=r;l>=S;++S){var p=void 0;if(this.__grid[c]&&(p=this.__grid[c][S]),_){var u=new SSCD.Vector(c*o,S*o).sub_self(i);s.beginPath(),s.rect(u.x,u.y,o-1,o-1),s.lineWidth="1",s.strokeStyle=void 0===p||0===p.length?"rgba(100, 100, 100, 0.255)":"rgba(255, 0, 0, 0.3)",s.stroke()}if(void 0!==p)for(var f=0;fs?SSCD.Math.distance(t,i):s>1?SSCD.Math.distance(t,_):SSCD.Math.distance(t,{x:i.x+s*(_.x-i.x),y:i.y+s*(_.y-i.y)})},SSCD.Math.line_intersects=function(t,i,_,e){var s,o,n,r;s=i.x-t.x,o=i.y-t.y,n=e.x-_.x,r=e.y-_.y;var a,l;return a=(-o*(t.x-_.x)+s*(t.y-_.y))/(-n*o+s*r),l=(n*(t.y-_.y)-r*(t.x-_.x))/(-n*o+s*r),a>=0&&1>=a&&l>=0&&1>=l?1:0},SSCD.Math.is_on_line=function(t,i,_){return SSCD.Math.distance_to_line(t,i,_)<=5};var SSCD=SSCD||{};SSCD.Vector=function(t,i){this.x=t,this.y=i},SSCD.Vector.prototype={get_name:function(){return"vector"},clone:function(){return new SSCD.Vector(this.x,this.y)},set:function(t){this.x=t.x,this.y=t.y},negative:function(){return this.multiply_scalar(-1)},negative_self:function(){return this.multiply_scalar_self(-1),this},distance_from:function(t){return SSCD.Math.distance(this,t)},angle_from:function(t){return SSCD.Math.angle(this,t)},move:function(t){return this.x+=t.x,this.y+=t.y,this},normalize_self:function(){var t=Math.sqrt(this.x*this.x+this.y*this.y);return 0===t?this:(this.x/=t,this.y/=t,this)},normalize:function(){return this.clone().normalize_self()},add_self:function(t){return this.x+=t.x,this.y+=t.y,this},sub_self:function(t){return this.x-=t.x,this.y-=t.y,this},divide_self:function(t){return this.x/=t.x,this.y/=t.y,this},multiply_self:function(t){return this.x*=t.x,this.y*=t.y,this},add_scalar_self:function(t){return this.x+=t,this.y+=t,this},sub_scalar_self:function(t){return this.x-=t,this.y-=t,this},divide_scalar_self:function(t){return this.x/=t,this.y/=t,this},multiply_scalar_self:function(t){return this.x*=t,this.y*=t,this},add:function(t){return this.clone().add_self(t)},sub:function(t){return this.clone().sub_self(t)},multiply:function(t){return this.clone().multiply_self(t)},divide:function(t){return this.clone().divide_self(t)},add_scalar:function(t){return this.clone().add_scalar_self(t)},sub_scalar:function(t){return this.clone().sub_scalar_self(t)},multiply_scalar:function(t){return this.clone().multiply_scalar_self(t)},divide_scalar:function(t){return this.clone().divide_scalar_self(t)},clamp:function(t,i){return this.xi&&(this.x=i),this.y>i&&(this.y=i),this},from_angle:function(t){return this.x=Math.cos(t),this.y=Math.sin(t),this},apply_self:function(t){return this.x=t(this.x),this.y=t(this.y),this},apply:function(t){return this.clone().apply_self(t)},debug:function(){console.debug(this.x+", "+this.y)}},SSCD.Vector.ZERO=new SSCD.Vector(0,0),SSCD.Vector.ONE=new SSCD.Vector(1,1),SSCD.Vector.UP=new SSCD.Vector(0,-1),SSCD.Vector.DOWN=new SSCD.Vector(0,1),SSCD.Vector.LEFT=new SSCD.Vector(-1,0),SSCD.Vector.RIGHT=new SSCD.Vector(1,0),SSCD.Vector.UP_LEFT=new SSCD.Vector(-1,-1),SSCD.Vector.DOWN_LEFT=new SSCD.Vector(-1,1),SSCD.Vector.UP_RIGHT=new SSCD.Vector(1,-1),SSCD.Vector.DOWN_RIGHT=new SSCD.Vector(1,1);var SSCD=SSCD||{};SSCD.extend=function(t,i){for(var _ in t)i[_]||(i[_]=t[_]);i.__inits=i.__inits||[],t.__init__&&i.__inits.push(t.__init__),i.init=function(){for(var t=0;t0&&(this.position.x-=i,this.size.x+=i);var _=this.position.y-t.y;_>0&&(this.position.y-=_,this.size.y+=_);var e=t.x-(this.position.x+this.size.x);e>0&&(this.size.x+=e);var s=t.y-(this.position.y+this.size.y);s>0&&(this.size.y+=s)},clone:function(){return new SSCD.AABB(this.position,this.size)}};var SSCD=SSCD||{};SSCD.Shape=function(){},SSCD.Shape.prototype={__type:"shape",is_shape:!0,__data:null,__next_id:0,__collision_tags:[],__collision_tags_val:SSCD.World.prototype._ALL_TAGS_VAL,__init__:function(){this.__position=new SSCD.Vector,this.__grid_chunks=[],this.__world=null,this.__grid_bounderies=null,this.__last_insert_aabb=null,this.__id=SSCD.Shape.prototype.__next_id++},get_id:function(){return this.__id},set_collision_tags:function(t){if(null===this.__world)throw new SSCD.IllegalActionError("Can't set tags for a shape that is not inside a collision world!");return this.__collision_tags_val=this.__world.__get_tags_value(t),!t instanceof Array&&(t=[t]),this.__collision_tags=t,this.__update_tags_hook&&this.__update_tags_hook(),this},__update_tags_hook:null,get_collision_tags:function(){return this.__collision_tags},collision_tags_match:function(t){if(isNaN(t)){if(null===this.__world)throw new SSCD.IllegalActionError("If you provide tags as string(s) the shape must be inside a collision world to convert them!");t=this.__world.__get_tags_value(t)}return 0!==(this.__collision_tags_val&t)},test_collide_with:function(t){return SSCD.CollisionManager.test_collision(this,t)},repel:function(t,i,_){i=i||1,_=_||1;for(var e=this.get_repel_direction(t).multiply_scalar_self(i),s=SSCD.Vector.ZERO.clone(),o=!0;o&&_>0;)_--,t.move(e),s.add_self(e),o=this.test_collide_with(t);return s},get_repel_direction:function(t){var i,_=this.get_abs_center();return i=t instanceof SSCD.Vector?t:t.get_abs_center(),i.sub(_).normalize_self()},__get_render_fill_color:function(t){return this.__override_fill_color?this.__override_fill_color:this.__collision_tags_to_color(this.__collision_tags_val,t)},__get_render_stroke_color:function(t){return this.__override_stroke_color?this.__override_stroke_color:this.__collision_tags_to_color(this.__collision_tags_val,t)},set_debug_render_colors:function(t,i){this.__override_fill_color=t,this.__override_stroke_color=i},__override_fill_color:null,__override_stroke_color:null,__collision_tags_to_color:function(t,i){var _=Math.round(255*Math.abs(Math.sin(t))),e=Math.round(255*Math.abs(Math.cos(t))),s=Math.round(_^e);return"rgba("+_+","+e+","+s+","+i+")"},set_data:function(t){return this.__data=t,this},get_data:function(){return this.__data},get_name:function(){return this.__type},render_aabb:function(t,i){var _=this.get_aabb();t.beginPath(),t.rect(_.position.x-i.x,_.position.y-i.y,_.size.x,_.size.y),t.lineWidth="1",t.strokeStyle="rgba(50, 175, 45, 0.5)",t.stroke()},set_position:function(t){return this.__position.x=t.x,this.__position.y=t.y,this.__update_position(),this},get_position:function(){return this.__position.clone()},move:function(t){return this.set_position(this.__position.add(t)),this},__update_position:function(){this.__update_position_hook&&this.__update_position_hook(),this.__aabb&&this.__update_aabb_pos(),this.__update_parent_world()},__update_aabb_pos:function(){this.__aabb.position=this.__position},get_abs_center:function(){var t=this.get_aabb();return t.position.add(t.size.multiply_scalar(.5))},reset_aabb:function(){this.__aabb=void 0},__update_parent_world:function(){this.__world&&this.__world.__update_shape_grid(this)},__update_position_hook:null,render:function(){throw new SSCD.NotImplementedError},build_aabb:function(){throw new SSCD.NotImplementedError},get_aabb:function(){return this.__aabb=this.__aabb||this.build_aabb(),this.__aabb}};var SSCD=SSCD||{};SSCD.Circle=function(t,i){this.init(),this.__radius=i,this.__size=new SSCD.Vector(i,i).multiply_scalar_self(2),this.set_position(t)},SSCD.Circle.prototype={__type:"circle",render:function(t,i){var _=this.__position.sub(i);t.beginPath(),t.arc(_.x,_.y,this.__radius,0,2*Math.PI,!1),t.lineWidth="7",t.strokeStyle=this.__get_render_stroke_color(.75),t.stroke(),t.fillStyle=this.__get_render_fill_color(.35),t.fill()},get_radius:function(){return this.__radius},__update_aabb_pos:function(){this.__aabb.position=this.__position.sub_scalar(this.__radius)},build_aabb:function(){return new SSCD.AABB(this.__position.sub_scalar(this.__radius),this.__size)},get_abs_center:function(){return this.__position.clone()}},SSCD.extend(SSCD.Shape.prototype,SSCD.Circle.prototype);var SSCD=SSCD||{};SSCD.Rectangle=function(t,i){this.init(),this.__size=i,this.set_position(t)},SSCD.Rectangle.prototype={__type:"rectangle",render:function(t,i){var _=this.__position.sub(i);t.beginPath(),t.rect(_.x,_.y,this.__size.x,this.__size.y),t.lineWidth="7",t.strokeStyle=this.__get_render_stroke_color(.75),t.stroke(),t.fillStyle=this.__get_render_fill_color(.35),t.fill()},get_size:function(){return this.__size.clone()},build_aabb:function(){return new SSCD.AABB(this.__position,this.__size)},get_top_left:function(){return this.__top_left_c=this.__top_left_c||this.__position.clone(),this.__top_left_c},get_bottom_left:function(){return this.__bottom_left_c=this.__bottom_left_c||this.__position.add(new SSCD.Vector(0,this.__size.y)),this.__bottom_left_c},get_top_right:function(){return this.__top_right_c=this.__top_right_c||this.__position.add(new SSCD.Vector(this.__size.x,0)),this.__top_right_c},get_bottom_right:function(){return this.__bottom_right_c=this.__bottom_right_c||this.__position.add(new SSCD.Vector(this.__size.x,this.__size.y)),this.__bottom_right_c},get_abs_center:function(){return this.__abs_center_c=this.__abs_center_c||this.__position.add(this.__size.divide_scalar(2)),this.__abs_center_c},__update_position_hook:function(){this.__top_left_c=void 0,this.__top_right_c=void 0,this.__bottom_left_c=void 0,this.__bottom_right_c=void 0,this.__abs_center_c=void 0}},SSCD.extend(SSCD.Shape.prototype,SSCD.Rectangle.prototype);var SSCD=SSCD||{};SSCD.Line=function(t,i){this.init(),this.__dest=i,this.set_position(t)},SSCD.Line.prototype={__type:"line",render:function(t){t.beginPath(),t.moveTo(this.__position.x,this.__position.y);var i=this.__position.add(this.__dest);t.lineTo(i.x,i.y),t.lineWidth="7",t.strokeStyle=this.__get_render_stroke_color(.75),t.stroke()},build_aabb:function(){var t=new SSCD.Vector(0,0);t.x=this.__dest.x>0?this.__position.x:this.__position.x-this.__dest.x,t.y=this.__dest.y>0?this.__position.y:this.__position.y-this.__dest.y;var i=this.__dest.apply(Math.abs);return new SSCD.AABB(t,i)},get_p1:function(){return this.__p1_c=this.__p1_c||this.__position.clone(),this.__p1_c},get_p2:function(){return this.__p2_c=this.__p2_c||this.__position.add(this.__dest),this.__p2_c},__update_position_hook:function(){this.__p1_c=void 0,this.__p2_c=void 0}},SSCD.extend(SSCD.Shape.prototype,SSCD.Line.prototype);var SSCD=SSCD||{};SSCD.LineStrip=function(t,i,_){if(this.init(),this.__points=i,i.length<=1)throw new SSCD.IllegalActionError("Not enough vectors for LineStrip (got to have at least two vectors)");_&&this.__points.push(this.__points[0]),this.set_position(t)},SSCD.LineStrip.prototype={__type:"line-strip",render:function(t){var i=void 0;t.beginPath();for(var _=0;_=t.__position.x&&i.y>=t.__position.y&&i.x<=t.__position.x+t.__size.x&&i.y<=t.__position.y+t.__size.y},_test_collision_vector_line:function(t,i){return SSCD.Math.is_on_line(t,i.get_p1(),i.get_p2())},_test_collision_vector_linestrip:function(t,i){for(var _=i.get_abs_lines(),e=0;e<_.length;++e)if(SSCD.Math.is_on_line(t,_[e][0],_[e][1]))return!0;return!1},_test_collision_circle_line:function(t,i){return SSCD.Math.distance_to_line(t.__position,i.get_p1(),i.get_p2())<=t.__radius},_test_collision_circle_linestrip:function(t,i){for(var _=i.get_abs_lines(),e=0;e<_.length;++e)if(SSCD.Math.distance_to_line(t.__position,_[e][0],_[e][1])<=t.__radius)return!0;return!1},_test_collision_linestrip_line:function(t,i){for(var _=t.get_abs_lines(),e=i.get_p1(),s=i.get_p2(),o=0;o<_.length;++o)if(SSCD.Math.line_intersects(e,s,_[o][0],_[o][1]))return!0;return!1},_test_collision_line_line:function(t,i){return SSCD.Math.line_intersects(t.get_p1(),t.get_p2(),i.get_p1(),i.get_p2())},_test_collision_rect_line:function(t,i){var _=i.get_p1(),e=i.get_p2();if(SSCD.CollisionManager._test_collision_rect_vector(t,_)||SSCD.CollisionManager._test_collision_rect_vector(t,e))return!0;var s=t.get_top_left(),o=t.get_bottom_left();if(SSCD.Math.line_intersects(_,e,s,o))return!0;var n=t.get_top_right(),r=t.get_bottom_right();return SSCD.Math.line_intersects(_,e,n,r)?!0:SSCD.Math.line_intersects(_,e,s,n)?!0:SSCD.Math.line_intersects(_,e,o,r)?!0:!1},_test_collision_rect_linestrip:function(t,i){for(var _=i.get_abs_points(),e=0;e<_.length;++e)if(this._test_collision_rect_vector(t,_[e]))return!0;for(var s=t.get_top_left(),o=t.get_bottom_left(),n=t.get_top_right(),r=t.get_bottom_right(),a=i.get_abs_lines(),e=0;e_.x?[i.get_top_left(),i.get_bottom_left()]:[i.get_top_right(),i.get_bottom_right()]),o.push(s.y>_.y?[i.get_top_left(),i.get_top_right()]:[i.get_bottom_left(),i.get_bottom_right()]);for(var n=0;n_.right||e.right<_.left||e.top>_.bottom||e.bottom<_.top)}},SSCD.UnsupportedShapes=function(t,i){this.name="Unsupported Shapes",this.message="Unsupported shapes collision test! '"+t.get_name()+"' <-> '"+i.get_name()+"'."},SSCD.UnsupportedShapes.prototype=Error.prototype,"undefined"!=typeof exports&&(exports.sscd=SSCD); \ No newline at end of file +var SSCD=SSCD||{};SSCD.VERSION=1.3,SSCD.World=function(t){t=t||{},t.grid_size=t.grid_size||512,t.grid_error=void 0!==t.grid_error?t.grid_error:2,this.__grid={},this.__params=t,this.__all_shapes={},this.__collision_tags={},this.__next_coll_tag=0},SSCD.World.prototype={__create_collision_tag:function(t){if(this.__collision_tags[t])throw new SSCD.IllegalActionError("Collision tag named '"+t+"' already exist!");this.__collision_tags[t]=1<this.__params.grid_error||Math.abs(i.position.y-t.__last_insert_aabb.position.y)>this.__params.grid_error||Math.abs(i.size.x-t.__last_insert_aabb.size.x)>this.__params.grid_error||Math.abs(i.size.y-t.__last_insert_aabb.size.y)>this.__params.grid_error)&&(this.remove(t),this.add(t))},pick_object:function(t,i){var _=[];return this.test_collision(t,i,_,1)?_[0]:null},test_collision:function(t,i,_,e){return i=this.__get_tags_value(i),t instanceof SSCD.Vector?this.__test_collision_point(t,i,_,e):t.is_shape?this.__test_collision_shape(t,i,_,e):void 0},__test_collision_point:function(t,i,_,e){var s=this.__params.grid_size,o=Math.floor(t.x/s),n=Math.floor(t.y/s);if(void 0===this.__grid[o]||void 0===this.__grid[o][n])return!1;for(var r=this.__grid[o][n],a=0,o=0;o=e)return!0}}return a>0},__test_collision_shape:function(t,i,_,e){var s;s=t.__world===this?t.__grid_bounderies:this.__get_grid_range(t);for(var o=0,n={},r=s.min_x;r<=s.max_x;++r)if(void 0!==this.__grid[r])for(var a=s.min_y;a<=s.max_y;++a){var l=this.__grid[r][a];if(void 0!==l)for(var h=0;h=e)return!0}}}return o>0},__do_collision:function(t,i){return t.test_collide_with(i)},render:function(t,i,_,e){i=i||SSCD.Vector.ZERO,void 0===_&&(_=!0),void 0===e&&(e=!0);var s=t.getContext("2d");s.setTransform(1,0,0,1,0,0);for(var o=this.__params.grid_size,n=Math.floor(i.x/o),r=Math.floor(i.y/o),a=n+Math.ceil(t.width/o),l=r+Math.ceil(t.height/o),h=[],c=n;a>=c;++c)for(var S=r;l>=S;++S){var p=void 0;if(this.__grid[c]&&(p=this.__grid[c][S]),_){var u=new SSCD.Vector(c*o,S*o).sub_self(i);s.beginPath(),s.rect(u.x,u.y,o-1,o-1),s.lineWidth="1",s.strokeStyle=void 0===p||0===p.length?"rgba(100, 100, 100, 0.255)":"rgba(255, 0, 0, 0.3)",s.stroke()}if(void 0!==p)for(var f=0;fs?SSCD.Math.distance(t,i):s>1?SSCD.Math.distance(t,_):SSCD.Math.distance(t,{x:i.x+s*(_.x-i.x),y:i.y+s*(_.y-i.y)})},SSCD.Math.line_intersects=function(t,i,_,e){var s,o,n,r;s=i.x-t.x,o=i.y-t.y,n=e.x-_.x,r=e.y-_.y;var a,l;return a=(-o*(t.x-_.x)+s*(t.y-_.y))/(-n*o+s*r),l=(n*(t.y-_.y)-r*(t.x-_.x))/(-n*o+s*r),a>=0&&1>=a&&l>=0&&1>=l?1:0},SSCD.Math.is_on_line=function(t,i,_){return SSCD.Math.distance_to_line(t,i,_)<=5};var SSCD=SSCD||{};SSCD.Vector=function(t,i){this.x=t,this.y=i},SSCD.Vector.prototype={get_name:function(){return"vector"},clone:function(){return new SSCD.Vector(this.x,this.y)},set:function(t){this.x=t.x,this.y=t.y},negative:function(){return this.multiply_scalar(-1)},negative_self:function(){return this.multiply_scalar_self(-1),this},distance_from:function(t){return SSCD.Math.distance(this,t)},angle_from:function(t){return SSCD.Math.angle(this,t)},move:function(t){return this.x+=t.x,this.y+=t.y,this},normalize_self:function(){var t=Math.sqrt(this.x*this.x+this.y*this.y);return 0===t?this:(this.x/=t,this.y/=t,this)},normalize:function(){return this.clone().normalize_self()},add_self:function(t){return this.x+=t.x,this.y+=t.y,this},sub_self:function(t){return this.x-=t.x,this.y-=t.y,this},divide_self:function(t){return this.x/=t.x,this.y/=t.y,this},multiply_self:function(t){return this.x*=t.x,this.y*=t.y,this},add_scalar_self:function(t){return this.x+=t,this.y+=t,this},sub_scalar_self:function(t){return this.x-=t,this.y-=t,this},divide_scalar_self:function(t){return this.x/=t,this.y/=t,this},multiply_scalar_self:function(t){return this.x*=t,this.y*=t,this},add:function(t){return this.clone().add_self(t)},sub:function(t){return this.clone().sub_self(t)},multiply:function(t){return this.clone().multiply_self(t)},divide:function(t){return this.clone().divide_self(t)},add_scalar:function(t){return this.clone().add_scalar_self(t)},sub_scalar:function(t){return this.clone().sub_scalar_self(t)},multiply_scalar:function(t){return this.clone().multiply_scalar_self(t)},divide_scalar:function(t){return this.clone().divide_scalar_self(t)},clamp:function(t,i){return this.xi&&(this.x=i),this.y>i&&(this.y=i),this},from_angle:function(t){return this.x=Math.cos(t),this.y=Math.sin(t),this},apply_self:function(t){return this.x=t(this.x),this.y=t(this.y),this},apply:function(t){return this.clone().apply_self(t)},debug:function(){console.debug(this.x+", "+this.y)}},SSCD.Vector.ZERO=new SSCD.Vector(0,0),SSCD.Vector.ONE=new SSCD.Vector(1,1),SSCD.Vector.UP=new SSCD.Vector(0,-1),SSCD.Vector.DOWN=new SSCD.Vector(0,1),SSCD.Vector.LEFT=new SSCD.Vector(-1,0),SSCD.Vector.RIGHT=new SSCD.Vector(1,0),SSCD.Vector.UP_LEFT=new SSCD.Vector(-1,-1),SSCD.Vector.DOWN_LEFT=new SSCD.Vector(-1,1),SSCD.Vector.UP_RIGHT=new SSCD.Vector(1,-1),SSCD.Vector.DOWN_RIGHT=new SSCD.Vector(1,1);var SSCD=SSCD||{};SSCD.extend=function(t,i){for(var _ in t)i[_]||(i[_]=t[_]);i.__inits=i.__inits||[],t.__init__&&i.__inits.push(t.__init__),i.init=function(){for(var t=0;t0&&(this.position.x-=i,this.size.x+=i);var _=this.position.y-t.y;_>0&&(this.position.y-=_,this.size.y+=_);var e=t.x-(this.position.x+this.size.x);e>0&&(this.size.x+=e);var s=t.y-(this.position.y+this.size.y);s>0&&(this.size.y+=s)},clone:function(){return new SSCD.AABB(this.position,this.size)}};var SSCD=SSCD||{};SSCD.Shape=function(){},SSCD.Shape.prototype={__type:"shape",is_shape:!0,__data:null,__next_id:0,__collision_tags:[],__collision_tags_val:SSCD.World.prototype._ALL_TAGS_VAL,__init__:function(){this.__position=new SSCD.Vector,this.__grid_chunks=[],this.__world=null,this.__grid_bounderies=null,this.__last_insert_aabb=null,this.__id=SSCD.Shape.prototype.__next_id++},get_id:function(){return this.__id},set_collision_tags:function(t){if(null===this.__world)throw new SSCD.IllegalActionError("Can't set tags for a shape that is not inside a collision world!");return this.__collision_tags_val=this.__world.__get_tags_value(t),!t instanceof Array&&(t=[t]),this.__collision_tags=t,this.__update_tags_hook&&this.__update_tags_hook(),this},__update_tags_hook:null,get_collision_tags:function(){return this.__collision_tags},collision_tags_match:function(t){if(isNaN(t)){if(null===this.__world)throw new SSCD.IllegalActionError("If you provide tags as string(s) the shape must be inside a collision world to convert them!");t=this.__world.__get_tags_value(t)}return 0!==(this.__collision_tags_val&t)},test_collide_with:function(t){return SSCD.CollisionManager.test_collision(this,t)},repel:function(t,i,_,e,s){i=i||1,_=_||1,void 0===e&&(e=0),void 0===s&&(s=1);var o,n,r=this.get_repel_direction(t).multiply_scalar_self(i);s&&(o=r.multiply_scalar(s)),e&&(n=r.multiply_scalar(-1*e));for(var a=SSCD.Vector.ZERO.clone(),l=!0;l&&_>0;)_--,o&&t.move(o),n&&this.move(n),a.add_self(r),l=this.test_collide_with(t);return a},get_repel_direction:function(t){var i,_=this.get_abs_center();return i=t instanceof SSCD.Vector?t:t.get_abs_center(),i.sub(_).normalize_self()},__get_render_fill_color:function(t){return this.__override_fill_color?this.__override_fill_color:this.__collision_tags_to_color(this.__collision_tags_val,t)},__get_render_stroke_color:function(t){return this.__override_stroke_color?this.__override_stroke_color:this.__collision_tags_to_color(this.__collision_tags_val,t)},set_debug_render_colors:function(t,i){this.__override_fill_color=t,this.__override_stroke_color=i},__override_fill_color:null,__override_stroke_color:null,__collision_tags_to_color:function(t,i){var _=Math.round(255*Math.abs(Math.sin(t))),e=Math.round(255*Math.abs(Math.cos(t))),s=Math.round(_^e);return"rgba("+_+","+e+","+s+","+i+")"},set_data:function(t){return this.__data=t,this},get_data:function(){return this.__data},get_name:function(){return this.__type},render_aabb:function(t,i){var _=this.get_aabb();t.beginPath(),t.rect(_.position.x-i.x,_.position.y-i.y,_.size.x,_.size.y),t.lineWidth="1",t.strokeStyle="rgba(50, 175, 45, 0.5)",t.stroke()},set_position:function(t){return this.__position.x=t.x,this.__position.y=t.y,this.__update_position(),this},get_position:function(){return this.__position.clone()},move:function(t){return this.set_position(this.__position.add(t)),this},__update_position:function(){this.__update_position_hook&&this.__update_position_hook(),this.__aabb&&this.__update_aabb_pos(),this.__update_parent_world()},__update_aabb_pos:function(){this.__aabb.position=this.__position},get_abs_center:function(){var t=this.get_aabb();return t.position.add(t.size.multiply_scalar(.5))},reset_aabb:function(){this.__aabb=void 0},__update_parent_world:function(){this.__world&&this.__world.__update_shape_grid(this)},__update_position_hook:null,render:function(){throw new SSCD.NotImplementedError},build_aabb:function(){throw new SSCD.NotImplementedError},get_aabb:function(){return this.__aabb=this.__aabb||this.build_aabb(),this.__aabb}};var SSCD=SSCD||{};SSCD.Circle=function(t,i){this.init(),this.__radius=i,this.__size=new SSCD.Vector(i,i).multiply_scalar_self(2),this.set_position(t)},SSCD.Circle.prototype={__type:"circle",render:function(t,i){var _=this.__position.sub(i);t.beginPath(),t.arc(_.x,_.y,this.__radius,0,2*Math.PI,!1),t.lineWidth="7",t.strokeStyle=this.__get_render_stroke_color(.75),t.stroke(),t.fillStyle=this.__get_render_fill_color(.35),t.fill()},get_radius:function(){return this.__radius},__update_aabb_pos:function(){this.__aabb.position=this.__position.sub_scalar(this.__radius)},build_aabb:function(){return new SSCD.AABB(this.__position.sub_scalar(this.__radius),this.__size)},get_abs_center:function(){return this.__position.clone()}},SSCD.extend(SSCD.Shape.prototype,SSCD.Circle.prototype);var SSCD=SSCD||{};SSCD.Rectangle=function(t,i){this.init(),this.__size=i,this.set_position(t)},SSCD.Rectangle.prototype={__type:"rectangle",render:function(t,i){var _=this.__position.sub(i);t.beginPath(),t.rect(_.x,_.y,this.__size.x,this.__size.y),t.lineWidth="7",t.strokeStyle=this.__get_render_stroke_color(.75),t.stroke(),t.fillStyle=this.__get_render_fill_color(.35),t.fill()},get_size:function(){return this.__size.clone()},build_aabb:function(){return new SSCD.AABB(this.__position,this.__size)},get_top_left:function(){return this.__top_left_c=this.__top_left_c||this.__position.clone(),this.__top_left_c},get_bottom_left:function(){return this.__bottom_left_c=this.__bottom_left_c||this.__position.add(new SSCD.Vector(0,this.__size.y)),this.__bottom_left_c},get_top_right:function(){return this.__top_right_c=this.__top_right_c||this.__position.add(new SSCD.Vector(this.__size.x,0)),this.__top_right_c},get_bottom_right:function(){return this.__bottom_right_c=this.__bottom_right_c||this.__position.add(new SSCD.Vector(this.__size.x,this.__size.y)),this.__bottom_right_c},get_abs_center:function(){return this.__abs_center_c=this.__abs_center_c||this.__position.add(this.__size.divide_scalar(2)),this.__abs_center_c},__update_position_hook:function(){this.__top_left_c=void 0,this.__top_right_c=void 0,this.__bottom_left_c=void 0,this.__bottom_right_c=void 0,this.__abs_center_c=void 0}},SSCD.extend(SSCD.Shape.prototype,SSCD.Rectangle.prototype);var SSCD=SSCD||{};SSCD.Line=function(t,i){this.init(),this.__dest=i,this.set_position(t)},SSCD.Line.prototype={__type:"line",render:function(t){t.beginPath(),t.moveTo(this.__position.x,this.__position.y);var i=this.__position.add(this.__dest);t.lineTo(i.x,i.y),t.lineWidth="7",t.strokeStyle=this.__get_render_stroke_color(.75),t.stroke()},build_aabb:function(){var t=new SSCD.Vector(0,0);t.x=this.__dest.x>0?this.__position.x:this.__position.x-this.__dest.x,t.y=this.__dest.y>0?this.__position.y:this.__position.y-this.__dest.y;var i=this.__dest.apply(Math.abs);return new SSCD.AABB(t,i)},get_p1:function(){return this.__p1_c=this.__p1_c||this.__position.clone(),this.__p1_c},get_p2:function(){return this.__p2_c=this.__p2_c||this.__position.add(this.__dest),this.__p2_c},__update_position_hook:function(){this.__p1_c=void 0,this.__p2_c=void 0}},SSCD.extend(SSCD.Shape.prototype,SSCD.Line.prototype);var SSCD=SSCD||{};SSCD.LineStrip=function(t,i,_){if(this.init(),this.__points=i,i.length<=1)throw new SSCD.IllegalActionError("Not enough vectors for LineStrip (got to have at least two vectors)");_&&this.__points.push(this.__points[0]),this.set_position(t)},SSCD.LineStrip.prototype={__type:"line-strip",render:function(t){var i=void 0;t.beginPath();for(var _=0;_=t.__position.x&&i.y>=t.__position.y&&i.x<=t.__position.x+t.__size.x&&i.y<=t.__position.y+t.__size.y},_test_collision_vector_line:function(t,i){return SSCD.Math.is_on_line(t,i.get_p1(),i.get_p2())},_test_collision_vector_linestrip:function(t,i){for(var _=i.get_abs_lines(),e=0;e<_.length;++e)if(SSCD.Math.is_on_line(t,_[e][0],_[e][1]))return!0;return!1},_test_collision_circle_line:function(t,i){return SSCD.Math.distance_to_line(t.__position,i.get_p1(),i.get_p2())<=t.__radius},_test_collision_circle_linestrip:function(t,i){for(var _=i.get_abs_lines(),e=0;e<_.length;++e)if(SSCD.Math.distance_to_line(t.__position,_[e][0],_[e][1])<=t.__radius)return!0;return!1},_test_collision_linestrip_line:function(t,i){for(var _=t.get_abs_lines(),e=i.get_p1(),s=i.get_p2(),o=0;o<_.length;++o)if(SSCD.Math.line_intersects(e,s,_[o][0],_[o][1]))return!0;return!1},_test_collision_line_line:function(t,i){return SSCD.Math.line_intersects(t.get_p1(),t.get_p2(),i.get_p1(),i.get_p2())},_test_collision_rect_line:function(t,i){var _=i.get_p1(),e=i.get_p2();if(SSCD.CollisionManager._test_collision_rect_vector(t,_)||SSCD.CollisionManager._test_collision_rect_vector(t,e))return!0;var s=t.get_top_left(),o=t.get_bottom_left();if(SSCD.Math.line_intersects(_,e,s,o))return!0;var n=t.get_top_right(),r=t.get_bottom_right();return SSCD.Math.line_intersects(_,e,n,r)?!0:SSCD.Math.line_intersects(_,e,s,n)?!0:SSCD.Math.line_intersects(_,e,o,r)?!0:!1},_test_collision_rect_linestrip:function(t,i){for(var _=i.get_abs_points(),e=0;e<_.length;++e)if(this._test_collision_rect_vector(t,_[e]))return!0;for(var s=t.get_top_left(),o=t.get_bottom_left(),n=t.get_top_right(),r=t.get_bottom_right(),a=i.get_abs_lines(),e=0;e_.x?[i.get_top_left(),i.get_bottom_left()]:[i.get_top_right(),i.get_bottom_right()]),o.push(s.y>_.y?[i.get_top_left(),i.get_top_right()]:[i.get_bottom_left(),i.get_bottom_right()]);for(var n=0;n_.right||e.right<_.left||e.top>_.bottom||e.bottom<_.top)}},SSCD.UnsupportedShapes=function(t,i){this.name="Unsupported Shapes",this.message="Unsupported shapes collision test! '"+t.get_name()+"' <-> '"+i.get_name()+"'."},SSCD.UnsupportedShapes.prototype=Error.prototype,"undefined"!=typeof exports&&(exports.sscd=SSCD); \ No newline at end of file