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