1 /* Copyright (c) 2012 Scott Lembcke and Howling Moon Software
  2  *
  3  * Permission is hereby granted, free of charge, to any person obtaining a copy
  4  * of this software and associated documentation files (the "Software"), to deal
  5  * in the Software without restriction, including without limitation the rights
  6  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7  * copies of the Software, and to permit persons to whom the Software is
  8  * furnished to do so, subject to the following conditions:
  9  *
 10  * The above copyright notice and this permission notice shall be included in
 11  * all copies or substantial portions of the Software.
 12  *
 13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 18  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 19  * SOFTWARE.
 20  */
 21 
 22 /** A CCSprite subclass that is bound to a physics body.
 23  It works with:
 24  - Chipmunk: Preprocessor macro CC_ENABLE_CHIPMUNK_INTEGRATION should be defined
 25  - Objective-Chipmunk: Preprocessor macro CC_ENABLE_CHIPMUNK_INTEGRATION should be defined
 26  - Box2d: Preprocessor macro CC_ENABLE_BOX2D_INTEGRATION should be defined
 27 
 28  Features and Limitations:
 29  - Scale and Skew properties are ignored.
 30  - Position and rotation are going to updated from the physics body
 31  - If you update the rotation or position manually, the physics body will be updated
 32  - You can't eble both Chipmunk support and Box2d support at the same time. Only one can be enabled at compile time
 33  */
 34 (function () {
 35     var box2dAPI = {
 36         _ignoreBodyRotation:false,
 37         _body:null,
 38         _PTMRatio:32,
 39         _rotation:1,
 40         setBody:function (body) {
 41             this._body = body;
 42         },
 43         getBody:function () {
 44             return this._body;
 45         },
 46         setPTMRatio:function (r) {
 47             this._PTMRatio = r;
 48         },
 49         getPTMRatio:function () {
 50             return this._PTMRatio;
 51         },
 52         getPosition:function () {
 53             var pos = this._body.GetPosition();
 54             return cc.p(pos.x * this._PTMRatio, pos.y * this._PTMRatio);
 55         },
 56         setPosition:function (p) {
 57             var angle = this._body.GetAngle();
 58             this._body.setTransform(Box2D.b2Vec2(p.x / this._PTMRatio, p.y / this._PTMRatio), angle);
 59             this.setNodeDirty();
 60         },
 61         getRotation:function () {
 62             return (this._ignoreBodyRotation ? cc.RADIANS_TO_DEGREES(this._rotationRadians) : cc.RADIANS_TO_DEGREES(this._body.GetAngle()));
 63         },
 64         setRotation:function (r) {
 65             if (this._ignoreBodyRotation) {
 66                 this._rotation = r;
 67             }
 68             else {
 69                 var p = this._body.GetPosition();
 70                 this._body.SetTransform(p, cc.DEGREES_TO_RADIANS(r));
 71             }
 72             this.setNodeDirty();
 73         },
 74         _syncPosition:function () {
 75             var pos = this._body.GetPosition();
 76             this._position = cc.p(pos.x * this._PTMRatio, pos.y * this._PTMRatio);
 77             this._rotationRadians = this._rotation * (Math.PI / 180);
 78         },
 79         _syncRotation:function () {
 80             this._rotationRadians = this._body.GetAngle();
 81         },
 82         visit:function () {
 83             if (this._body && this._PTMRatio) {
 84                 this._syncPosition();
 85                 if (!this._ignoreBodyRotation)
 86                     this._syncRotation();
 87             }
 88             else {
 89                 cc.log("PhysicsSprite body or PTIMRatio was not set");
 90             }
 91             this._super();
 92         }
 93     };
 94     var chipmunkAPI = {
 95         _ignoreBodyRotation:false,
 96         _body:null, //physics body
 97         _rotation:1,
 98         setBody:function (body) {
 99             this._body = body;
100         },
101         getBody:function () {
102             return this._body;
103         },
104         getPosition:function () {
105             return {x:this._body.p.x, y:this._body.p.y};
106         },
107         setPosition:function (pos) {
108             this._body.p.x = pos.x;
109             this._body.p.y = pos.y;
110             //this._syncPosition();
111         },
112         _syncPosition:function () {
113             if(this._position.x != this._body.p.x || this._position.y != this._body.p.y){
114                 this._position = {x:this._body.p.x, y:this._body.p.y};
115                 this.setNodeDirty();
116             }
117         },
118         getRotation:function () {
119             return this._ignoreBodyRotation ? cc.RADIANS_TO_DEGREES(this._rotationRadians) : -cc.RADIANS_TO_DEGREES(this._body.a)
120         },
121         setRotation:function (r) {
122             if (this._ignoreBodyRotation) {
123                 this._super(r);
124             }
125             else {
126                 this._body.a = -cc.DEGREES_TO_RADIANS(r);
127                 //this._syncRotation();
128             }
129         },
130         _syncRotation:function () {
131             if(this._rotationRadians != -this._body.a){
132                 this._rotationRadians = -this._body.a;
133                 this.setNodeDirty();
134             }
135         },
136         visit:function (ctx) {
137             if (this._body) {
138                 this._syncPosition();
139                 if (!this._ignoreBodyRotation)
140                     this._syncRotation();
141             }
142             else {
143                 cc.log("PhysicsSprite body was not set");
144             }
145             this._super(ctx);
146         }
147     };
148     cc.PhysicsSprite = cc.Sprite.extend(chipmunkAPI);
149 
150     /**
151      * Create a PhysicsSprite with filename and rect
152      * @constructs
153      * @param {String} fileName
154      * @param {cc.Rect} rect
155      * @return {cc.Sprite}
156      * @example
157      * //create a sprite with filename
158      * var sprite1 = cc.Sprite.create("HelloHTML5World.png");
159      *
160      * //create a sprite with filename and rect
161      * var sprite2 = cc.PhysicsSprite.create("HelloHTML5World.png",cc.rect(0,0,480,320));
162      */
163     cc.PhysicsSprite.create = function (fileName, rect) {
164         var argnum = arguments.length;
165         var sprite = new cc.PhysicsSprite();
166         if (argnum === 0) {
167             if (sprite.init())
168                 return sprite;
169             return null;
170         } else if (argnum < 2) {
171             /** Creates an sprite with an image filename.
172              The rect used will be the size of the image.
173              The offset will be (0,0).
174              */
175             if (sprite && sprite.initWithFile(fileName)) {
176                 return sprite;
177             }
178             return null;
179         } else {
180             /** Creates an sprite with an CCBatchNode and a rect
181              */
182             if (sprite && sprite.initWithFile(fileName, rect)) {
183                 return sprite;
184             }
185             return null;
186         }
187     };
188 
189     /**
190      * Creates a PhysicsSprite with a sprite frame name
191      * @param {String} spriteFrame name
192      * @return {cc.Sprite}
193      * @example
194      *
195      * //create a PhysicsSprite with a sprite frame
196      * var sprite = cc.PhysicsSprite.createWithSpriteFrameName('grossini_dance_01.png');
197      */
198     cc.PhysicsSprite.createWithSpriteFrameName = function (spriteFrameName) {
199         var spriteFrame = null;
200         if (typeof(spriteFrameName) == 'string') {
201             spriteFrame = cc.SpriteFrameCache.getInstance().getSpriteFrame(spriteFrameName);
202             if (!spriteFrame) {
203                 cc.log("Invalid spriteFrameName: " + spriteFrameName);
204                 return null;
205             }
206         } else {
207             cc.log("Invalid argument. Expecting string.");
208             return null;
209         }
210         var sprite = new cc.PhysicsSprite();
211         if (sprite && sprite.initWithSpriteFrame(spriteFrame)) {
212             return sprite;
213         }
214         return null;
215     };
216 
217     /**
218      * Creates a sprite with a sprite frame.
219      * @param {cc.SpriteFrame} spriteFrame
220      * @return {cc.Sprite}
221      * @example
222      * //get a sprite frame
223      * var spriteFrame = cc.SpriteFrameCache.getInstance().getSpriteFrame("grossini_dance_01.png");
224      *
225      * //create a sprite with a sprite frame
226      * var sprite = cc.Sprite.createWithSpriteFrameName(spriteFrame);
227      */
228     cc.PhysicsSprite.createWithSpriteFrame = function (spriteFrame) {
229         var sprite = new cc.PhysicsSprite();
230         if (sprite && sprite.initWithSpriteFrame(spriteFrame)) {
231             return sprite;
232         }
233         return null;
234     };
235 
236 
237 })();
238