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  * Base class for ccs.ColliderFilter
 32  * @class
 33  * @extends ccs.Class
 34  */
 35 ccs.ColliderFilter = ccs.Class.extend(/** @lends ccs.ColliderFilter# */{
 36     _collisionType: 0,
 37     _group: 0,
 38     _categoryBits: 0,
 39     _groupIndex: 0,
 40     _maskBits: 0,
 41     ctor: function (collisionType, group) {
 42         this._collisionType = collisionType || 0;
 43         this._group = group || 0;
 44     },
 45     updateShape: function (shape) {
 46         if(shape instanceof cp.Shape){
 47             shape.collision_type = this._collisionType;
 48             shape.group = this._group;
 49         }else if(shape instanceof Box2D.b2FilterData){
 50 
 51             var filter = new Box2D.b2FilterData();
 52             filter.categoryBits = this._categoryBits;
 53             filter.groupIndex = this._groupIndex;
 54             filter.maskBits = this._maskBits;
 55 
 56             shape.SetFilterData(filter);
 57         }
 58     }
 59 });
 60 /**
 61  * Base class for ccs.ColliderBody
 62  * @class
 63  * @extends ccs.Class
 64  *
 65  * @property {ccs.ContourData}      contourData     - The contour data of collider body
 66  * @property {ccs.Shape}            shape           - The shape of collider body
 67  * @property {ccs.ColliderFilter}   colliderFilter  - The collider filter of collider body
 68  *
 69  */
 70 ccs.ColliderBody = ccs.Class.extend(/** @lends ccs.ColliderBody# */{
 71     shape: null,
 72     coutourData: null,
 73     colliderFilter: null,
 74     _calculatedVertexList: null,
 75     ctor: function (contourData) {
 76         this.shape = null;
 77         this.coutourData = contourData;
 78         this.colliderFilter = new ccs.ColliderFilter();
 79         if (ccs.ENABLE_PHYSICS_SAVE_CALCULATED_VERTEX) {
 80             this._calculatedVertexList = [];
 81         }
 82     },
 83 
 84     /**
 85      * contourData getter
 86      * @returns {ccs.ContourData}
 87      */
 88     getContourData: function () {
 89         return this.coutourData;
 90     },
 91 
 92     /**
 93      * colliderFilter setter
 94      * @param {ccs.ColliderFilter} colliderFilter
 95      */
 96     setColliderFilter: function (colliderFilter) {
 97         this.colliderFilter = colliderFilter;
 98     },
 99 
100     /**
101      * get calculated vertex list
102      * @returns {Array}
103      */
104     getCalculatedVertexList: function () {
105         return this._calculatedVertexList;
106     },
107 
108     setB2Fixture: function(fixture){
109         this._fixture = fixture;
110     },
111 
112     getB2Fixture: function(){
113         return this._fixture;
114     },
115 
116     /**
117      * shape getter
118      * @param {ccs.Shape} shape
119      */
120     setShape: function (shape) {
121         this.shape = shape;
122     },
123 
124     /**
125      * shape setter
126      * @return {ccs.Shape}
127      */
128     getShape: function () {
129         return this.shape;
130     },
131 
132     /**
133      * contourData setter
134      * @param {ccs.ContourData} contourData
135      */
136     setContourData: function (contourData) {
137         this.coutourData = contourData;
138     },
139 
140     /**
141      * colliderFilter getter
142      * @returns {ccs.ColliderFilter}
143      */
144     getColliderFilter: function () {
145         return this.colliderFilter;
146     }
147 });
148 
149 /**
150  * Base class for ccs.ColliderDetector
151  * @class
152  * @extends ccs.Class
153  *
154  * @property {ccs.ColliderFilter}   colliderFilter  - The collider filter of the collider detector
155  * @property {Boolean}              active          - Indicate whether the collider detector is active
156  * @property {Object}               body            - The collider body
157  */
158 ccs.ColliderDetector = ccs.Class.extend(/** @lends ccs.ColliderDetector# */{
159     _colliderBodyList: null,
160     _bone: null,
161     _body: null,
162     _active: false,
163     _filter: null,
164     helpPoint: cc.p(0, 0),
165     ctor: function () {
166         this._colliderBodyList = [];
167         this._bone = null;
168         this._body = null;
169         this._active = false;
170         this._filter = null;
171     },
172     init: function (bone) {
173         this._colliderBodyList.length = 0;
174         if (bone)
175             this._bone = bone;
176         this._filter = new ccs.ColliderFilter();
177         return true;
178     },
179 
180     /**
181      *  add contourData
182      * @param {ccs.ContourData} contourData
183      */
184     addContourData: function (contourData) {
185         var colliderBody = new ccs.ColliderBody(contourData);
186         this._colliderBodyList.push(colliderBody);
187 
188         if (ccs.ENABLE_PHYSICS_SAVE_CALCULATED_VERTEX) {
189             var calculatedVertexList = colliderBody.getCalculatedVertexList();
190             var vertexList = contourData.vertexList;
191             for (var i = 0; i < vertexList.length; i++) {
192                 var newVertex = new ccs.ContourVertex2(0, 0);
193                 calculatedVertexList.push(newVertex);
194             }
195         }
196     },
197 
198     /**
199      * add contourData
200      * @param {Array} contourDataList
201      */
202     addContourDataList: function (contourDataList) {
203         for (var i = 0; i < contourDataList.length; i++) {
204             this.addContourData(contourDataList[i]);
205         }
206     },
207 
208     /**
209      * remove contourData
210      * @param contourData
211      */
212     removeContourData: function (contourData) {
213         var eraseList = [], i, locBodyList = this._colliderBodyList;
214         for (i = 0; i < locBodyList.length; i++) {
215             var body = locBodyList[i];
216             if (body && body.getContourData() == contourData)
217                 eraseList.push(body);
218         }
219 
220         for (i=0; i<eraseList.length; i++)
221             cc.arrayRemoveObject(locBodyList, eraseList[i]);
222     },
223 
224     /**
225      * remove all body
226      */
227     removeAll: function () {
228         this._colliderBodyList.length = 0;
229     },
230 
231     setActive: function (active) {
232         if (this._active == active)
233             return;
234         this._active = active;
235 
236         var locBody = this._body;
237         var locShape;
238         if (locBody) {
239             var colliderBody = null;
240             if (this._active) {
241                 for (var i = 0; i < this._colliderBodyList.length; i++) {
242                     colliderBody = this._colliderBodyList[i];
243                     locShape = colliderBody.getShape();
244                     locBody.space.addShape(locShape);
245                 }
246             } else {
247                 for (var i = 0; i < this._colliderBodyList.length; i++) {
248                     colliderBody = this._colliderBodyList[i];
249                     locShape = colliderBody.getShape();
250                     locBody.space.removeShape(locShape);
251                 }
252             }
253         }
254     },
255 
256     getActive: function () {
257         return this._active;
258     },
259 
260     getColliderBodyList: function(){
261         return this._colliderBodyList;
262     },
263 
264     /**
265      * set colliderFilter
266      * @param {ccs.ColliderFilter} filter
267      */
268     setColliderFilter: function (filter) {
269         this._filter = filter;
270         var locBodyList = this._colliderBodyList;
271         for(var i=0; i< locBodyList.length; i++){
272             var colliderBody = locBodyList[i];
273             colliderBody.setColliderFilter(filter);
274             if (colliderBody.getShape())
275                 colliderBody.getColliderFilter().updateShape(colliderBody.getShape());
276         }
277     },
278 
279     /**
280      * get colliderFilter
281      * @returns {ccs.ColliderFilter}
282      */
283     getColliderFilter: function () {
284         return this._filter;
285     },
286 
287     updateTransform: function (t) {
288         if (!this._active)
289             return;
290 
291         var colliderBody = null;
292         var locBody = this._body;
293         var locHelpPoint = this.helpPoint;
294         for (var i = 0; i < this._colliderBodyList.length; i++) {
295 
296             colliderBody = this._colliderBodyList[i];
297             var contourData = colliderBody.getContourData();
298 
299             //default physics engine: Chipmunk
300             var shape = null;
301             if (locBody) {
302                 //Box2d shape = (b2PolygonShape *)colliderBody->getB2Fixture()->GetShape();
303                 shape = colliderBody.getShape();
304             }
305 
306             var vs = contourData.vertexList;
307             var cvs = colliderBody.getCalculatedVertexList();
308 
309             for (var j = 0; j < vs.length; j++) {
310                 locHelpPoint.x = vs[j].x;
311                 locHelpPoint.y = vs[j].y;
312                 locHelpPoint = cc.pointApplyAffineTransform(locHelpPoint, t);
313 
314                 if (ccs.ENABLE_PHYSICS_SAVE_CALCULATED_VERTEX) {
315                     var v = cc.p(0, 0);
316                     v.x = locHelpPoint.x;
317                     v.y = locHelpPoint.y;
318                     cvs[j] = v;
319                 }
320 
321                 if (shape) {
322                     shape.verts[j * 2] = locHelpPoint.x;
323                     shape.verts[j * 2 + 1] = locHelpPoint.y;
324                 }
325             }
326             if (shape) {
327                 for (var j = 0; j < vs.length; j++) {
328                     var b = shape.verts[(j + 1) % shape.verts.length];
329                     var n = cp.v.normalize(cp.v.perp(cp.v.sub(b, shape.verts[j])));
330 
331                     shape.axes[j].n = n;
332                     shape.axes[j].d = cp.v.dot(n, shape.verts[j]);
333 //                    var b = shape.verts[(i + 1) % shape.numVerts];
334 //                    var n = cp.v.normalize(cp.v.perp(cp.v.sub(b, shape.verts[i])));
335 //
336 //                    shape.planes[i].n = n;
337 //                    shape.planes[i].d = cp.v.dot(n, shape.verts[i]);
338                 }
339             }
340         }
341     },
342 
343     setBody: function (body) {
344         this._body = body;
345         var colliderBody, locBodyList = this._colliderBodyList;
346         for (var i = 0; i < locBodyList.length; i++) {
347             colliderBody = locBodyList[i];
348             var contourData = colliderBody.getContourData(), verts = [];
349             var vs = contourData.vertexList;
350             for (var j = 0; j < vs.length; j++) {
351                 var v = vs[j];
352                 verts.push(v.x);
353                 verts.push(v.y);
354             }
355             var shape = new cp.PolyShape(this._body, verts, cp.vzero);
356             shape.sensor = true;
357             shape.data = this._bone;
358             if (this._active)
359                 this._body.space.addShape(shape);
360             colliderBody.setShape(shape);
361             colliderBody.getColliderFilter().updateShape(shape);
362         }
363     },
364 
365     getBody: function () {
366         return this._body;
367     }
368 });
369 
370 var _p = ccs.ColliderDetector.prototype;
371 
372 // Extended properties
373 /** @expose */
374 _p.colliderFilter;
375 cc.defineGetterSetter(_p, "colliderFilter", _p.getColliderFilter, _p.setColliderFilter);
376 /** @expose */
377 _p.active;
378 cc.defineGetterSetter(_p, "active", _p.getActive, _p.setActive);
379 /** @expose */
380 _p.body;
381 cc.defineGetterSetter(_p, "body", _p.getBody, _p.setBody);
382 
383 _p = null;
384 
385 ccs.ColliderDetector.create = function (bone) {
386     var colliderDetector = new ccs.ColliderDetector();
387     if (colliderDetector && colliderDetector.init(bone))
388         return colliderDetector;
389     return null;
390 };