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