1 /****************************************************************************
  2  Copyright (c) 2011-2012 cocos2d-x.org
  3  Copyright (c) 2013-2014 Chukong Technologies Inc.
  4 
  5  http://www.cocos2d-x.org
  6 
  7  Permission is hereby granted, free of charge, to any person obtaining a copy
  8  of this software and associated documentation files (the "Software"), to deal
  9  in the Software without restriction, including without limitation the rights
 10  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 11  copies of the Software, and to permit persons to whom the Software is
 12  furnished to do so, subject to the following conditions:
 13 
 14  The above copyright notice and this permission notice shall be included in
 15  all copies or substantial portions of the Software.
 16 
 17  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 18  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 19  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 20  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 21  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 22  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 23  THE SOFTWARE.
 24  ****************************************************************************/
 25 
 26 /**
 27  * @ignore
 28  */
 29 ccs.PT_RATIO = 32;
 30 
 31 /**
 32  * Base class for ccs.ColliderFilter
 33  * @class
 34  * @extends ccs.Class
 35  */
 36 ccs.ColliderFilter = ccs.Class.extend(/** @lends ccs.ColliderFilter# */{
 37     _collisionType: 0,
 38     _group: 0,
 39     _categoryBits: 0,
 40     _groupIndex: 0,
 41     _maskBits: 0,
 42 
 43     ctor: function (collisionType, group) {
 44         this._collisionType = collisionType || 0;
 45         this._group = group || 0;
 46     },
 47 
 48     updateShape: function (shape) {
 49         if(shape instanceof cp.Shape){
 50             shape.collision_type = this._collisionType;
 51             shape.group = this._group;
 52         }else if(shape instanceof Box2D.b2FilterData){
 53             var filter = new Box2D.b2FilterData();
 54             filter.categoryBits = this._categoryBits;
 55             filter.groupIndex = this._groupIndex;
 56             filter.maskBits = this._maskBits;
 57 
 58             shape.SetFilterData(filter);
 59         }
 60     }
 61 });
 62 
 63 /**
 64  * Base class for ccs.ColliderBody
 65  * @class
 66  * @extends ccs.Class
 67  *
 68  * @property {ccs.ContourData}      contourData     - The contour data of collider body
 69  * @property {ccs.Shape}            shape           - The shape of collider body
 70  * @property {ccs.ColliderFilter}   colliderFilter  - The collider filter of collider body
 71  *
 72  */
 73 ccs.ColliderBody = ccs.Class.extend(/** @lends ccs.ColliderBody# */{
 74     shape: null,
 75     coutourData: null,
 76     colliderFilter: null,
 77     _calculatedVertexList: null,
 78     ctor: function (contourData) {
 79         this.shape = null;
 80         this.coutourData = contourData;
 81         this.colliderFilter = new ccs.ColliderFilter();
 82         if (ccs.ENABLE_PHYSICS_SAVE_CALCULATED_VERTEX) {
 83             this._calculatedVertexList = [];
 84         }
 85     },
 86 
 87     /**
 88      * contourData getter
 89      * @returns {ccs.ContourData}
 90      */
 91     getContourData: function () {
 92         return this.coutourData;
 93     },
 94 
 95     /**
 96      * colliderFilter setter
 97      * @param {ccs.ColliderFilter} colliderFilter
 98      */
 99     setColliderFilter: function (colliderFilter) {
100         this.colliderFilter = colliderFilter;
101     },
102 
103     /**
104      * get calculated vertex list
105      * @returns {Array}
106      */
107     getCalculatedVertexList: function () {
108         return this._calculatedVertexList;
109     },
110 
111     setB2Fixture: function(fixture){
112         this._fixture = fixture;
113     },
114 
115     getB2Fixture: function(){
116         return this._fixture;
117     },
118 
119     /**
120      * shape getter
121      * @param {ccs.Shape} shape
122      */
123     setShape: function (shape) {
124         this.shape = shape;
125     },
126 
127     /**
128      * shape setter
129      * @return {ccs.Shape}
130      */
131     getShape: function () {
132         return this.shape;
133     },
134 
135     /**
136      * contourData setter
137      * @param {ccs.ContourData} contourData
138      */
139     setContourData: function (contourData) {
140         this.coutourData = contourData;
141     },
142 
143     /**
144      * colliderFilter getter
145      * @returns {ccs.ColliderFilter}
146      */
147     getColliderFilter: function () {
148         return this.colliderFilter;
149     }
150 });
151 
152 /**
153  * Base class for ccs.ColliderDetector
154  * @class
155  * @extends ccs.Class
156  *
157  * @property {ccs.ColliderFilter}   colliderFilter  - The collider filter of the collider detector
158  * @property {Boolean}              active          - Indicate whether the collider detector is active
159  * @property {Object}               body            - The collider body
160  */
161 ccs.ColliderDetector = ccs.Class.extend(/** @lends ccs.ColliderDetector# */{
162     _colliderBodyList: null,
163     _bone: null,
164     _body: null,
165     _active: false,
166     _filter: null,
167     helpPoint: cc.p(0, 0),
168     ctor: function () {
169         this._colliderBodyList = [];
170         this._bone = null;
171         this._body = null;
172         this._active = false;
173         this._filter = null;
174     },
175     init: function (bone) {
176         this._colliderBodyList.length = 0;
177         if (bone)
178             this._bone = bone;
179         this._filter = new ccs.ColliderFilter();
180         return true;
181     },
182 
183     /**
184      *  add contourData
185      * @param {ccs.ContourData} contourData
186      */
187     addContourData: function (contourData) {
188         var colliderBody = new ccs.ColliderBody(contourData);
189         this._colliderBodyList.push(colliderBody);
190 
191         if (ccs.ENABLE_PHYSICS_SAVE_CALCULATED_VERTEX) {
192             var calculatedVertexList = colliderBody.getCalculatedVertexList();
193             var vertexList = contourData.vertexList;
194             for (var i = 0; i < vertexList.length; i++) {
195                 var newVertex = new ccs.ContourVertex2(0, 0);
196                 calculatedVertexList.push(newVertex);
197             }
198         }
199     },
200 
201     /**
202      * add contourData
203      * @param {Array} contourDataList
204      */
205     addContourDataList: function (contourDataList) {
206         for (var i = 0; i < contourDataList.length; i++) {
207             this.addContourData(contourDataList[i]);
208         }
209     },
210 
211     /**
212      * remove contourData
213      * @param contourData
214      */
215     removeContourData: function (contourData) {
216         var eraseList = [], i, locBodyList = this._colliderBodyList;
217         for (i = 0; i < locBodyList.length; i++) {
218             var body = locBodyList[i];
219             if (body && body.getContourData() == contourData)
220                 eraseList.push(body);
221         }
222 
223         for (i=0; i<eraseList.length; i++)
224             cc.arrayRemoveObject(locBodyList, eraseList[i]);
225     },
226 
227     /**
228      * remove all body
229      */
230     removeAll: function () {
231         this._colliderBodyList.length = 0;
232     },
233 
234     setActive: function (active) {
235         if (this._active == active)
236             return;
237         this._active = active;
238 
239         var locBody = this._body;
240         var locShape;
241         if (locBody) {
242             var colliderBody = null;
243             if (this._active) {
244                 for (var i = 0; i < this._colliderBodyList.length; i++) {
245                     colliderBody = this._colliderBodyList[i];
246                     locShape = colliderBody.getShape();
247                     locBody.space.addShape(locShape);
248                 }
249             } else {
250                 for (var i = 0; i < this._colliderBodyList.length; i++) {
251                     colliderBody = this._colliderBodyList[i];
252                     locShape = colliderBody.getShape();
253                     locBody.space.removeShape(locShape);
254                 }
255             }
256         }
257     },
258 
259     getActive: function () {
260         return this._active;
261     },
262 
263     getColliderBodyList: function(){
264         return this._colliderBodyList;
265     },
266 
267     /**
268      * set colliderFilter
269      * @param {ccs.ColliderFilter} filter
270      */
271     setColliderFilter: function (filter) {
272         this._filter = filter;
273         var locBodyList = this._colliderBodyList;
274         for(var i=0; i< locBodyList.length; i++){
275             var colliderBody = locBodyList[i];
276             colliderBody.setColliderFilter(filter);
277             if (colliderBody.getShape())
278                 colliderBody.getColliderFilter().updateShape(colliderBody.getShape());
279         }
280     },
281 
282     /**
283      * get colliderFilter
284      * @returns {ccs.ColliderFilter}
285      */
286     getColliderFilter: function () {
287         return this._filter;
288     },
289 
290     updateTransform: function (t) {
291         if (!this._active)
292             return;
293 
294         var colliderBody = null;
295         var locBody = this._body;
296         var locHelpPoint = this.helpPoint;
297         for (var i = 0; i < this._colliderBodyList.length; i++) {
298 
299             colliderBody = this._colliderBodyList[i];
300             var contourData = colliderBody.getContourData();
301 
302             //default physics engine: Chipmunk
303             var shape = null;
304             if (locBody) {
305                 //Box2d shape = (b2PolygonShape *)colliderBody->getB2Fixture()->GetShape();
306                 shape = colliderBody.getShape();
307             }
308 
309             var vs = contourData.vertexList;
310             var cvs = colliderBody.getCalculatedVertexList();
311 
312             for (var j = 0; j < vs.length; j++) {
313                 locHelpPoint.x = vs[j].x;
314                 locHelpPoint.y = vs[j].y;
315                 locHelpPoint = cc.pointApplyAffineTransform(locHelpPoint, t);
316 
317                 if (ccs.ENABLE_PHYSICS_SAVE_CALCULATED_VERTEX) {
318                     var v = cc.p(0, 0);
319                     v.x = locHelpPoint.x;
320                     v.y = locHelpPoint.y;
321                     cvs[j] = v;
322                 }
323 
324                 if (shape) {
325                     shape.verts[j * 2] = locHelpPoint.x;
326                     shape.verts[j * 2 + 1] = locHelpPoint.y;
327                 }
328             }
329             if (shape) {
330                 for (var j = 0; j < vs.length; j++) {
331                     var b = shape.verts[(j + 1) % shape.verts.length];
332                     var n = cp.v.normalize(cp.v.perp(cp.v.sub(b, shape.verts[j])));
333 
334                     shape.axes[j].n = n;
335                     shape.axes[j].d = cp.v.dot(n, shape.verts[j]);
336 //                    var b = shape.verts[(i + 1) % shape.numVerts];
337 //                    var n = cp.v.normalize(cp.v.perp(cp.v.sub(b, shape.verts[i])));
338 //
339 //                    shape.planes[i].n = n;
340 //                    shape.planes[i].d = cp.v.dot(n, shape.verts[i]);
341                 }
342             }
343         }
344     },
345 
346     setBody: function (body) {
347         this._body = body;
348         var colliderBody, locBodyList = this._colliderBodyList;
349         for (var i = 0; i < locBodyList.length; i++) {
350             colliderBody = locBodyList[i];
351             var contourData = colliderBody.getContourData(), verts = [];
352             var vs = contourData.vertexList;
353             for (var j = 0; j < vs.length; j++) {
354                 var v = vs[j];
355                 verts.push(v.x);
356                 verts.push(v.y);
357             }
358             var shape = new cp.PolyShape(this._body, verts, cp.vzero);
359             shape.sensor = true;
360             shape.data = this._bone;
361             if (this._active)
362                 this._body.space.addShape(shape);
363             colliderBody.setShape(shape);
364             colliderBody.getColliderFilter().updateShape(shape);
365         }
366     },
367 
368     getBody: function () {
369         return this._body;
370     }
371 });
372 
373 var _p = ccs.ColliderDetector.prototype;
374 
375 // Extended properties
376 /** @expose */
377 _p.colliderFilter;
378 cc.defineGetterSetter(_p, "colliderFilter", _p.getColliderFilter, _p.setColliderFilter);
379 /** @expose */
380 _p.active;
381 cc.defineGetterSetter(_p, "active", _p.getActive, _p.setActive);
382 /** @expose */
383 _p.body;
384 cc.defineGetterSetter(_p, "body", _p.getBody, _p.setBody);
385 
386 _p = null;
387 
388 ccs.ColliderDetector.create = function (bone) {
389     var colliderDetector = new ccs.ColliderDetector();
390     if (colliderDetector && colliderDetector.init(bone))
391         return colliderDetector;
392     return null;
393 };