├── .gitignore ├── AndEngine └── PhysicsEditorShapeLibrary.java ├── README.md ├── axmol ├── PhysicsShapeCache.cpp └── PhysicsShapeCache.h ├── cocos2d-x ├── PhysicsShapeCache.cpp └── PhysicsShapeCache.h ├── cocos2d ├── PhysicsShapeCache.h └── PhysicsShapeCache.m ├── gdx-pe-loader ├── README.md ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src │ ├── main │ └── java │ │ └── com │ │ └── codeandweb │ │ └── physicseditor │ │ ├── BodyDefNode.java │ │ ├── BodyNode.java │ │ ├── CircleNode.java │ │ ├── FixtureNode.java │ │ ├── MetadataNode.java │ │ ├── PhysicsShapeCache.java │ │ ├── PolygonNode.java │ │ └── Utility.java │ └── test │ ├── java │ └── com │ │ └── codeandweb │ │ └── physicseditor │ │ ├── BodyNodeTest.java │ │ ├── CircleNodeTest.java │ │ ├── FixtureNodeTest.java │ │ ├── Fixtures.java │ │ ├── MetadataNodeTest.java │ │ ├── PolygonNodeTest.java │ │ └── ShapeCacheTest.java │ └── resources │ ├── bugs.pes │ └── bugs.xml ├── generic-box2d-plist-cocos2d-x ├── GB2ShapeCache-x.cpp └── GB2ShapeCache-x.h ├── generic-box2d-plist ├── GB2ShapeCache.h └── GB2ShapeCache.mm ├── generic-chipmunk-plist ├── GCpShapeCache.h └── GCpShapeCache.m └── objective-chipmunk-plist ├── GCpShapeCache.h └── GCpShapeCache.m /.gitignore: -------------------------------------------------------------------------------- 1 | gdx-pe-loader/local.properties 2 | gdx-pe-loader/.idea 3 | gdx-pe-loader/build 4 | gdx-pe-loader/.gradle 5 | -------------------------------------------------------------------------------- /AndEngine/PhysicsEditorShapeLibrary.java: -------------------------------------------------------------------------------- 1 | package com.example.PhysicsEditorExample; 2 | 3 | /** 4 | * PhysicsEditor Importer Library 5 | * 6 | * Usage: 7 | * - Create an instance of this class 8 | * - Use the "open" method to load an XML file from PhysicsEditor 9 | * - Invoke "createBody" to create bodies from library. 10 | * 11 | * by Adrian Nilsson (ade at ade dot se) 12 | * BIG IRON GAMES (bigirongames.org) 13 | * Date: 2011-08-30 14 | * Time: 11:51 15 | */ 16 | 17 | import android.content.Context; 18 | import com.badlogic.gdx.math.Vector2; 19 | import com.badlogic.gdx.physics.box2d.Body; 20 | import com.badlogic.gdx.physics.box2d.BodyDef; 21 | import com.badlogic.gdx.physics.box2d.FixtureDef; 22 | import com.badlogic.gdx.physics.box2d.PolygonShape; 23 | import org.anddev.andengine.entity.shape.IShape; 24 | import org.anddev.andengine.extension.physics.box2d.PhysicsFactory; 25 | import org.anddev.andengine.extension.physics.box2d.PhysicsWorld; 26 | import org.anddev.andengine.extension.physics.box2d.util.constants.PhysicsConstants; 27 | import org.anddev.andengine.opengl.texture.atlas.bitmap.source.InternalStorageFileBitmapTextureAtlasSource; 28 | import org.anddev.andengine.util.constants.Constants; 29 | import org.xml.sax.Attributes; 30 | import org.xml.sax.SAXException; 31 | import org.xml.sax.helpers.DefaultHandler; 32 | 33 | import javax.xml.parsers.SAXParser; 34 | import javax.xml.parsers.SAXParserFactory; 35 | import java.util.ArrayList; 36 | import java.util.HashMap; 37 | 38 | public class PhysicsEditorShapeLibrary { 39 | private HashMap shapes = new HashMap(); 40 | private float pixelToMeterRatio = PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT; 41 | 42 | public PhysicsEditorShapeLibrary() { 43 | //Default constructor 44 | } 45 | public PhysicsEditorShapeLibrary(float pixelToMeterRatio) { 46 | this.pixelToMeterRatio = pixelToMeterRatio; 47 | } 48 | 49 | /** 50 | * Read shapes from an XML file and add to library. 51 | * Path is relative to your assets folder so if your file is in 52 | * "assets/shapes/shapes.xml", the path should be "shapes/shapes.xml" 53 | * @param context 54 | * @param xmlFile 55 | */ 56 | public void open(Context context, String xmlFile) { 57 | append(context, xmlFile, this.pixelToMeterRatio); 58 | } 59 | 60 | /** 61 | * If you wish, you may access the template data and create custom bodies. 62 | * Be advised that vertex positions are pre-adjusted for Box2D coordinates (pixel to meter ratio). 63 | * @param key 64 | * @return 65 | */ 66 | public BodyTemplate get(String key) { 67 | return this.shapes.get(key); 68 | } 69 | 70 | /** 71 | * Create a Box2D Body with a shape from the library. 72 | * @param name name of the shape (usually filename of the image, without extension) 73 | * @param pShape the AndEngine shape you will be associating the body with (physics connector is not created here). 74 | * @param pPhysicsWorld the AndEngine Box2D physics world object. 75 | * @return 76 | */ 77 | public Body createBody(String name, IShape pShape, PhysicsWorld pPhysicsWorld) { 78 | BodyTemplate bodyTemplate = this.shapes.get(name); 79 | 80 | final BodyDef boxBodyDef = new BodyDef(); 81 | boxBodyDef.type = bodyTemplate.isDynamic ? BodyDef.BodyType.DynamicBody : BodyDef.BodyType.StaticBody; 82 | 83 | final float[] sceneCenterCoordinates = pShape.getSceneCenterCoordinates(); 84 | boxBodyDef.position.x = sceneCenterCoordinates[Constants.VERTEX_INDEX_X] / this.pixelToMeterRatio; 85 | boxBodyDef.position.y = sceneCenterCoordinates[Constants.VERTEX_INDEX_Y] / this.pixelToMeterRatio; 86 | 87 | final Body boxBody = pPhysicsWorld.createBody(boxBodyDef); 88 | 89 | for(FixtureTemplate fixtureTemplate : bodyTemplate.fixtureTemplates) { 90 | for(int i = 0; i < fixtureTemplate.polygons.length; i++) { 91 | final PolygonShape polygonShape = new PolygonShape(); 92 | final FixtureDef fixtureDef = fixtureTemplate.fixtureDef; 93 | 94 | polygonShape.set(fixtureTemplate.polygons[i].vertices); 95 | 96 | fixtureDef.shape = polygonShape; 97 | boxBody.createFixture(fixtureDef); 98 | polygonShape.dispose(); 99 | } 100 | } 101 | 102 | return boxBody; 103 | } 104 | 105 | private void append(Context context, String name, float pixelToMeterRatio) { 106 | SAXParserFactory factory = SAXParserFactory.newInstance(); 107 | try { 108 | SAXParser parser = factory.newSAXParser(); 109 | ShapeLoader handler = new ShapeLoader(shapes, pixelToMeterRatio); 110 | parser.parse(context.getAssets().open(name), handler); 111 | } catch (Exception e) { 112 | e.printStackTrace(); 113 | } 114 | } 115 | 116 | protected static class ShapeLoader extends DefaultHandler { 117 | public static final String TAG_BODY = "body"; 118 | public static final String TAG_FIXTURE = "fixture"; 119 | public static final String TAG_POLYGON = "polygon"; 120 | public static final String TAG_VERTEX = "vertex"; 121 | public static final String TAG_NAME = "name"; 122 | public static final String TAG_X = "x"; 123 | public static final String TAG_Y = "y"; 124 | public static final String TAG_DENSITY = "density"; 125 | public static final String TAG_RESTITUTION = "restitution"; 126 | public static final String TAG_FRICTION = "friction"; 127 | public static final String TAG_FILTER_CATEGORY_BITS = "filter_categoryBits"; 128 | public static final String TAG_FILTER_GROUP_INDEX = "filter_groupIndex"; 129 | public static final String TAG_FILTER_MASK_BITS = "filter_maskBits"; 130 | public static final String TAG_ISDYNAMIC = "dynamic"; 131 | public static final String TAG_ISSENSOR = "isSensor"; 132 | 133 | private float pixelToMeterRatio; 134 | private StringBuilder builder; 135 | private HashMap shapes; 136 | private BodyTemplate currentBody; 137 | private ArrayList currentPolygonVertices = new ArrayList(); 138 | private ArrayList currentFixtures = new ArrayList(); 139 | private ArrayList currentPolygons = new ArrayList(); 140 | 141 | 142 | 143 | protected ShapeLoader(HashMap shapes, float pixelToMeterRatio) { 144 | this.shapes = shapes; 145 | this.pixelToMeterRatio = pixelToMeterRatio; 146 | } 147 | 148 | @Override 149 | public void characters(char[] ch, int start, int length) throws SAXException { 150 | super.characters(ch, start, length); 151 | builder.append(ch, start, length); 152 | } 153 | 154 | @Override 155 | public void endElement(String uri, String localName, String name) throws SAXException { 156 | super.endElement(uri, localName, name); 157 | 158 | if (localName.equalsIgnoreCase(TAG_POLYGON)) { 159 | currentPolygons.add(new PolygonTemplate(currentPolygonVertices)); 160 | } else if (localName.equalsIgnoreCase(TAG_FIXTURE)) { 161 | currentFixtures.get(currentFixtures.size()-1).setPolygons(currentPolygons); 162 | } else if (localName.equalsIgnoreCase(TAG_BODY)) { 163 | currentBody.setFixtures(currentFixtures); 164 | shapes.put(currentBody.name, currentBody); 165 | } 166 | 167 | builder.setLength(0); 168 | } 169 | 170 | @Override 171 | public void startDocument() throws SAXException { 172 | super.startDocument(); 173 | builder = new StringBuilder(); 174 | } 175 | 176 | @Override 177 | public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { 178 | super.startElement(uri, localName, name, attributes); 179 | builder.setLength(0); 180 | if (localName.equalsIgnoreCase(TAG_BODY)) { 181 | this.currentFixtures.clear(); 182 | this.currentBody = new BodyTemplate(); 183 | this.currentBody.name = attributes.getValue(TAG_NAME); 184 | this.currentBody.isDynamic = attributes.getValue(TAG_ISDYNAMIC).equalsIgnoreCase("true"); 185 | } else if (localName.equalsIgnoreCase(TAG_FIXTURE)) { 186 | FixtureTemplate fixture = new FixtureTemplate(); 187 | currentPolygons.clear(); 188 | float restitution = Float.parseFloat(attributes.getValue(TAG_RESTITUTION)); 189 | float friction = Float.parseFloat(attributes.getValue(TAG_FRICTION)); 190 | float density = Float.parseFloat(attributes.getValue(TAG_DENSITY)); 191 | short category = parseShort(attributes.getValue(TAG_FILTER_CATEGORY_BITS)); 192 | short groupIndex = parseShort(attributes.getValue(TAG_FILTER_GROUP_INDEX)); 193 | short maskBits = parseShort(attributes.getValue(TAG_FILTER_MASK_BITS)); 194 | boolean isSensor = attributes.getValue(TAG_ISSENSOR).equalsIgnoreCase("true"); 195 | fixture.fixtureDef = PhysicsFactory.createFixtureDef(density, restitution, friction, isSensor, category, maskBits, groupIndex); 196 | currentFixtures.add(fixture); 197 | } else if (localName.equalsIgnoreCase(TAG_POLYGON)) { 198 | currentPolygonVertices.clear(); 199 | } else if (localName.equalsIgnoreCase(TAG_VERTEX)) { 200 | currentPolygonVertices.add(new Vector2(Float.parseFloat(attributes.getValue(TAG_X)) / this.pixelToMeterRatio, Float.parseFloat(attributes.getValue(TAG_Y)) / this.pixelToMeterRatio)); 201 | } 202 | } 203 | } 204 | private static short parseShort(String val) { 205 | int intVal = Integer.parseInt(val); 206 | short ret = (short)(intVal & 65535); 207 | return (short)intVal; 208 | } 209 | private static class BodyTemplate { 210 | public String name; 211 | public boolean isDynamic = true; 212 | public FixtureTemplate[] fixtureTemplates; 213 | public void setFixtures(ArrayList fixtureTemplates) { 214 | this.fixtureTemplates = fixtureTemplates.toArray(new FixtureTemplate[fixtureTemplates.size()]); 215 | } 216 | } 217 | private static class FixtureTemplate { 218 | public PolygonTemplate[] polygons; 219 | public FixtureDef fixtureDef; 220 | public void setPolygons(ArrayList polygonTemplates) { 221 | polygons = polygonTemplates.toArray(new PolygonTemplate[polygonTemplates.size()]); 222 | } 223 | } 224 | private static class PolygonTemplate { 225 | public Vector2[] vertices; 226 | public PolygonTemplate(ArrayList vectorList) { 227 | vertices = vectorList.toArray(new Vector2[vectorList.size()]); 228 | } 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PhysicsEditor-Loaders 2 | ===================== 3 | 4 | Shape cache classes for various frameworks. 5 | Use these classes to load the plist/xml file written by 6 | PhysicsEditor 7 | 8 | ## Supported by CodeAndWeb 9 | 10 | | Framework | Exporter in PhysicsEditor| Loader | Example / Tutorial | 11 | |-----------|--------------------------|---------|--------------------| 12 | | cocos2d (ObjC), built-in Chipmunk | cocos2d | cocos2d | [Tutorial](https://www.codeandweb.com/physicseditor/tutorials/cocos2d-physics-tutorial) | 13 | | [cocos2d-x](http://www.cocos2d-x.org) (v3.*, built-in Chipmunk) | cocos2d-x | cocos2d-x | [Demo project](https://github.com/CodeAndWeb/PhysicsEditor-Cocos2d-x) | 14 | | [LibGDX](https://libgdx.badlogicgames.com) | LibGDX | gdx-pe-loader | [Tutorial](https://www.codeandweb.com/texturepacker/tutorials/libgdx-physics) 15 | | [CoronaSDK](https://coronalabs.com/corona-sdk) | CoronaSDK | *not required* | [Tutorial](https://www.codeandweb.com/physicseditor/tutorials/getting-started-with-coronasdk-and-physicseditor-tutorial) | 16 | | Box2d + ObjC | Box2D generic (PLIST) | generic-box2d-plist | | 17 | | Chipmunk + ObjC | Chipmunk generic PLIST | generic-chipmunk-plist || 18 | | Objective Chipmunk + ObjC | Chipmunk generic PLIST | objective-chipmunk-plist || 19 | 20 | 21 | ## 3rd party, unsupported 22 | 23 | | Framework | Exporter in PhysicsEditor | Loader | Example / Tutorial | 24 | |-----------|---------------------------|--------|--------------------| 25 | | AndEngine | AndEndgine (XML) | AndEngine | [Demo project](https://github.com/CodeAndWeb/PhysicsEditor-AndEngine) | 26 | | Box2d + cocos2d-x V2.* | Box2D generic (PLIST) | generic-box2d-plist-cocos2d-x | | 27 | 28 | -------------------------------------------------------------------------------- /axmol/PhysicsShapeCache.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // PhysicsShapeCache.cpp 3 | // 4 | // Shape cache for Axmol Game Engine with built-in physics classes. 5 | // 6 | // Loads physics sprites created with https://www.codeandweb.com/physicseditor 7 | // 8 | // Copyright (c) 2023 CodeAndWeb GmbH. All rights reserved. 9 | // https://www.codeandweb.com 10 | // 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to deal 13 | // in the Software without restriction, including without limitation the rights 14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | // copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | // THE SOFTWARE. 28 | // 29 | 30 | #include "PhysicsShapeCache.h" 31 | 32 | 33 | PhysicsShapeCache::PhysicsShapeCache() 34 | { 35 | } 36 | 37 | 38 | PhysicsShapeCache::~PhysicsShapeCache() 39 | { 40 | removeAllShapes(); 41 | } 42 | 43 | 44 | PhysicsShapeCache *PhysicsShapeCache::getInstance() 45 | { 46 | static PhysicsShapeCache instance; 47 | return &instance; 48 | } 49 | 50 | 51 | bool PhysicsShapeCache::addShapesWithFile(const std::string &plist) 52 | { 53 | float scaleFactor = Director::getInstance()->getContentScaleFactor(); 54 | return addShapesWithFile(plist, scaleFactor); 55 | } 56 | 57 | 58 | bool PhysicsShapeCache::addShapesWithFile(const std::string &plist, float scaleFactor) 59 | { 60 | AXASSERT(bodiesInFile.find(plist) == bodiesInFile.end(), "file already loaded"); 61 | 62 | ValueMap dict = FileUtils::getInstance()->getValueMapFromFile(plist); 63 | if (dict.empty()) 64 | { 65 | // plist file not found 66 | return false; 67 | } 68 | 69 | ValueMap &metadata = dict["metadata"].asValueMap(); 70 | int format = metadata["format"].asInt(); 71 | if (format != 1) 72 | { 73 | AXASSERT(format == 1, "format not supported!"); 74 | return false; 75 | } 76 | 77 | ValueMap &bodydict = dict.at("bodies").asValueMap(); 78 | 79 | std::vector bodies(bodydict.size()); 80 | int num=0; 81 | 82 | for (auto iter = bodydict.cbegin(); iter != bodydict.cend(); ++iter) 83 | { 84 | const ValueMap &bodyData = iter->second.asValueMap(); 85 | std::string bodyName = iter->first; 86 | BodyDef *bodyDef = new BodyDef(); 87 | bodies[num++] = bodyDef; 88 | bodyDefs.insert(std::make_pair(bodyName, bodyDef)); 89 | bodyDef->anchorPoint = PointFromString(bodyData.at("anchorpoint").asString()); 90 | bodyDef->isDynamic = bodyData.at("is_dynamic").asBool(); 91 | bodyDef->affectedByGravity = bodyData.at("affected_by_gravity").asBool(); 92 | bodyDef->allowsRotation = bodyData.at("allows_rotation").asBool(); 93 | bodyDef->linearDamping = bodyData.at("linear_damping").asFloat(); 94 | bodyDef->angularDamping = bodyData.at("angular_damping").asFloat(); 95 | bodyDef->velocityLimit = bodyData.at("velocity_limit").asFloat(); 96 | bodyDef->angularVelocityLimit = bodyData.at("angular_velocity_limit").asFloat(); 97 | 98 | const ValueVector &fixtureList = bodyData.at("fixtures").asValueVector(); 99 | for (auto &fixtureitem : fixtureList) 100 | { 101 | FixtureData *fd = new FixtureData(); 102 | bodyDef->fixtures.push_back(fd); 103 | auto &fixturedata = fixtureitem.asValueMap(); 104 | fd->density = fixturedata.at("density").asFloat(); 105 | fd->restitution = fixturedata.at("restitution").asFloat(); 106 | fd->friction = fixturedata.at("friction").asFloat(); 107 | fd->tag = fixturedata.at("tag").asInt(); 108 | fd->group = fixturedata.at("group").asInt(); 109 | fd->categoryMask = fixturedata.at("category_mask").asInt(); 110 | fd->collisionMask = fixturedata.at("collision_mask").asInt(); 111 | fd->contactTestMask = fixturedata.at("contact_test_mask").asInt(); 112 | 113 | std::string fixtureType = fixturedata.at("fixture_type").asString(); 114 | if (fixtureType == "POLYGON") 115 | { 116 | fd->fixtureType = FIXTURE_POLYGON; 117 | const ValueVector &polygonsArray = fixturedata.at("polygons").asValueVector(); 118 | for (auto &polygonitem : polygonsArray) 119 | { 120 | Polygon *poly = new Polygon(); 121 | fd->polygons.push_back(poly); 122 | auto &polygonArray = polygonitem.asValueVector(); 123 | poly->numVertices = (int)polygonArray.size(); 124 | auto *vertices = poly->vertices = new Point[poly->numVertices]; 125 | int vindex = 0; 126 | for (auto &pointString : polygonArray) 127 | { 128 | auto offset = PointFromString(pointString.asString()); 129 | vertices[vindex].x = offset.x / scaleFactor; 130 | vertices[vindex].y = offset.y / scaleFactor; 131 | vindex++; 132 | } 133 | } 134 | } 135 | else if (fixtureType == "CIRCLE") 136 | { 137 | fd->fixtureType = FIXTURE_CIRCLE; 138 | const ValueMap &circleData = fixturedata.at("circle").asValueMap(); 139 | fd->radius = circleData.at("radius").asFloat() / scaleFactor; 140 | fd->center = PointFromString(circleData.at("position").asString()) / scaleFactor; 141 | } 142 | else 143 | { 144 | // unknown type 145 | return false; 146 | } 147 | 148 | } 149 | } 150 | 151 | bodiesInFile[plist] = bodies; 152 | 153 | return true; 154 | } 155 | 156 | 157 | PhysicsShapeCache::BodyDef *PhysicsShapeCache::getBodyDef(const std::string &name) 158 | { 159 | try 160 | { 161 | return bodyDefs.at(name); 162 | } 163 | catch(std::out_of_range&) 164 | { 165 | } 166 | 167 | try 168 | { 169 | return bodyDefs.at(name.substr(0, name.rfind('.'))); // remove file suffix and try again... 170 | } 171 | catch(std::out_of_range&) 172 | { 173 | } 174 | 175 | return nullptr; 176 | } 177 | 178 | 179 | void PhysicsShapeCache::setBodyProperties(PhysicsBody *body, BodyDef *bd) 180 | { 181 | body->setGravityEnable(bd->affectedByGravity); 182 | body->setDynamic(bd->isDynamic); 183 | body->setRotationEnable(bd->allowsRotation); 184 | body->setLinearDamping(bd->linearDamping); 185 | body->setAngularDamping(bd->angularDamping); 186 | body->setVelocityLimit(bd->velocityLimit); 187 | body->setAngularVelocityLimit(bd->angularVelocityLimit); 188 | } 189 | 190 | 191 | void PhysicsShapeCache::setShapeProperties(PhysicsShape *shape, FixtureData *fd) 192 | { 193 | shape->setGroup(fd->group); 194 | shape->setCategoryBitmask(fd->categoryMask); 195 | shape->setCollisionBitmask(fd->collisionMask); 196 | shape->setContactTestBitmask(fd->contactTestMask); 197 | shape->setTag(fd->tag); 198 | } 199 | 200 | 201 | PhysicsBody *PhysicsShapeCache::createBodyWithName(const std::string &name) 202 | { 203 | BodyDef *bd = getBodyDef(name); 204 | if (!bd) 205 | { 206 | AXLOG("WARNING: PhysicsBody with name \"%s\", not found!", name.c_str()); 207 | return nullptr; // body not found 208 | } 209 | PhysicsBody *body = PhysicsBody::create(); 210 | setBodyProperties(body, bd); 211 | 212 | for (auto fd : bd->fixtures) 213 | { 214 | PhysicsMaterial material(fd->density, fd->restitution, fd->friction); 215 | if (fd->fixtureType == FIXTURE_CIRCLE) 216 | { 217 | auto shape = PhysicsShapeCircle::create(fd->radius, material, fd->center); 218 | setShapeProperties(shape, fd); 219 | body->addShape(shape); 220 | } 221 | else if (fd->fixtureType == FIXTURE_POLYGON) 222 | { 223 | for (auto polygon : fd->polygons) 224 | { 225 | auto shape = PhysicsShapePolygon::create(polygon->vertices, polygon->numVertices, material, fd->center); 226 | setShapeProperties(shape, fd); 227 | body->addShape(shape); 228 | } 229 | } 230 | } 231 | return body; 232 | } 233 | 234 | 235 | bool PhysicsShapeCache::setBodyOnSprite(const std::string &name, Sprite *sprite) 236 | { 237 | PhysicsBody *body = createBodyWithName(name); 238 | if (body) 239 | { 240 | sprite->setPhysicsBody(body); 241 | sprite->setAnchorPoint(getBodyDef(name)->anchorPoint); 242 | } 243 | return body != nullptr; 244 | } 245 | 246 | 247 | void PhysicsShapeCache::removeShapesWithFile(const std::string &plist) 248 | { 249 | auto bodies = bodiesInFile.at(plist); 250 | 251 | for (auto iter = bodies.begin(); iter != bodies.end(); ++iter) 252 | { 253 | safeDeleteBodyDef(*iter); 254 | } 255 | 256 | bodiesInFile.erase(plist); 257 | 258 | return; 259 | } 260 | 261 | 262 | void PhysicsShapeCache::removeAllShapes() 263 | { 264 | for (auto iter = bodyDefs.cbegin(); iter != bodyDefs.cend(); ++iter) 265 | { 266 | safeDeleteBodyDef(iter->second); 267 | } 268 | bodyDefs.clear(); 269 | bodiesInFile.clear(); 270 | } 271 | 272 | 273 | void PhysicsShapeCache::safeDeleteBodyDef(BodyDef *bodyDef) 274 | { 275 | for (auto fixturedata : bodyDef->fixtures) 276 | { 277 | for (auto polygon : fixturedata->polygons) 278 | { 279 | AX_SAFE_DELETE_ARRAY(polygon->vertices); 280 | AX_SAFE_DELETE(polygon); 281 | } 282 | fixturedata->polygons.clear(); 283 | AX_SAFE_DELETE(fixturedata); 284 | } 285 | bodyDef->fixtures.clear(); 286 | AX_SAFE_DELETE(bodyDef); 287 | } 288 | -------------------------------------------------------------------------------- /axmol/PhysicsShapeCache.h: -------------------------------------------------------------------------------- 1 | // 2 | // PhysicsShapeCache.h 3 | // 4 | // Shape cache for Axmol Game Engine with built-in physics classes. 5 | // 6 | // Loads physics sprites created with https://www.codeandweb.com/physicseditor 7 | // 8 | // Copyright (c) 2023 CodeAndWeb GmbH. All rights reserved. 9 | // https://www.codeandweb.com 10 | // 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to deal 13 | // in the Software without restriction, including without limitation the rights 14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | // copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | // THE SOFTWARE. 28 | // 29 | 30 | #ifndef __PhysicsShapeCache_h__ 31 | #define __PhysicsShapeCache_h__ 32 | #include "axmol.h" 33 | 34 | USING_NS_AX; 35 | 36 | 37 | class PhysicsShapeCache 38 | { 39 | public: 40 | 41 | /** 42 | * Get pointer to the PhysicsShapeCache singleton instance 43 | * 44 | * @return PhysicsShapeCache* 45 | */ 46 | static PhysicsShapeCache *getInstance(); 47 | 48 | /** 49 | * Adds all physics shapes from a plist file. 50 | * Shapes are scaled by contentScaleFactor 51 | * 52 | * @param plist name of the shape definitions file to load 53 | * 54 | * @retval true if ok 55 | * @retval false on error 56 | */ 57 | bool addShapesWithFile(const std::string &plist); 58 | 59 | /** 60 | * Adds all physics shapes from a plist file. 61 | * 62 | * @param plist name of the shape definitions file to load 63 | * @param scaleFactor scale factor to apply for all shapes 64 | * 65 | * @retval true if ok 66 | * @retval false on error 67 | */ 68 | bool addShapesWithFile(const std::string &plist, float scaleFactor); 69 | 70 | /** 71 | * Removes all shapes loaded from the given file 72 | * 73 | * @param plist name of the body definitions file 74 | */ 75 | void removeShapesWithFile(const std::string &plist); 76 | 77 | /** 78 | * Removes all shapes 79 | */ 80 | void removeAllShapes(); 81 | 82 | /** 83 | * Creates a PhysicsBody with the given name 84 | * 85 | * @param name name of the body to create 86 | * 87 | * @return new PhysicsBody 88 | * @retval nullptr if body is not found 89 | */ 90 | PhysicsBody *createBodyWithName(const std::string &name); 91 | 92 | /** 93 | * Creates a new PhysicsBody and attaches it to the given sprite 94 | * 95 | * @param name name of the body to attach 96 | * @param sprite sprite to attach the body to 97 | * 98 | * @retval true if body was attached to the sprite 99 | * @retval false if body was not found 100 | */ 101 | bool setBodyOnSprite(const std::string &name, Sprite *sprite); 102 | 103 | private: 104 | typedef enum 105 | { 106 | FIXTURE_POLYGON, 107 | FIXTURE_CIRCLE 108 | } FixtureType; 109 | 110 | 111 | class Polygon 112 | { 113 | public: 114 | Point* vertices; 115 | int numVertices; 116 | }; 117 | 118 | 119 | class FixtureData 120 | { 121 | public: 122 | FixtureType fixtureType; 123 | 124 | float density; 125 | float restitution; 126 | float friction; 127 | 128 | int tag; 129 | int group; 130 | int categoryMask; 131 | int collisionMask; 132 | int contactTestMask; 133 | 134 | // for circles 135 | Point center; 136 | float radius; 137 | 138 | 139 | std::vector polygons; 140 | }; 141 | 142 | 143 | class BodyDef 144 | { 145 | public: 146 | Point anchorPoint; 147 | std::vector fixtures; 148 | 149 | bool isDynamic; 150 | bool affectedByGravity; 151 | bool allowsRotation; 152 | 153 | float linearDamping; 154 | float angularDamping; 155 | float velocityLimit; 156 | float angularVelocityLimit; 157 | }; 158 | 159 | PhysicsShapeCache(); 160 | ~PhysicsShapeCache(); 161 | void safeDeleteBodyDef(BodyDef *bodyDef); 162 | BodyDef *getBodyDef(const std::string &name); 163 | void setBodyProperties(PhysicsBody *body, BodyDef *bd); 164 | void setShapeProperties(PhysicsShape *shape, FixtureData *fd); 165 | 166 | std::map bodyDefs; 167 | std::map> bodiesInFile; 168 | }; 169 | 170 | 171 | #endif // __PhysicsShapeCache_h 172 | -------------------------------------------------------------------------------- /cocos2d-x/PhysicsShapeCache.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // PhysicsShapeCache.cpp 3 | // 4 | // Shape cache for Cocos2d-x (v3.x) with built-in physics classes. 5 | // 6 | // Loads physics sprites created with https://www.codeandweb.com/physicseditor 7 | // 8 | // Copyright (c) 2015 CodeAndWeb GmbH. All rights reserved. 9 | // https://www.codeandweb.com 10 | // 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to deal 13 | // in the Software without restriction, including without limitation the rights 14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | // copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | // THE SOFTWARE. 28 | // 29 | 30 | #include "PhysicsShapeCache.h" 31 | 32 | 33 | PhysicsShapeCache::PhysicsShapeCache() 34 | { 35 | } 36 | 37 | 38 | PhysicsShapeCache::~PhysicsShapeCache() 39 | { 40 | removeAllShapes(); 41 | } 42 | 43 | 44 | PhysicsShapeCache *PhysicsShapeCache::getInstance() 45 | { 46 | static PhysicsShapeCache instance; 47 | return &instance; 48 | } 49 | 50 | 51 | bool PhysicsShapeCache::addShapesWithFile(const std::string &plist) 52 | { 53 | float scaleFactor = Director::getInstance()->getContentScaleFactor(); 54 | return addShapesWithFile(plist, scaleFactor); 55 | } 56 | 57 | 58 | bool PhysicsShapeCache::addShapesWithFile(const std::string &plist, float scaleFactor) 59 | { 60 | CCASSERT(bodiesInFile.find(plist) == bodiesInFile.end(), "file already loaded"); 61 | 62 | ValueMap dict = FileUtils::getInstance()->getValueMapFromFile(plist); 63 | if (dict.empty()) 64 | { 65 | // plist file not found 66 | return false; 67 | } 68 | 69 | ValueMap &metadata = dict["metadata"].asValueMap(); 70 | int format = metadata["format"].asInt(); 71 | if (format != 1) 72 | { 73 | CCASSERT(format == 1, "format not supported!"); 74 | return false; 75 | } 76 | 77 | ValueMap &bodydict = dict.at("bodies").asValueMap(); 78 | 79 | std::vector bodies(bodydict.size()); 80 | int num=0; 81 | 82 | for (auto iter = bodydict.cbegin(); iter != bodydict.cend(); ++iter) 83 | { 84 | const ValueMap &bodyData = iter->second.asValueMap(); 85 | std::string bodyName = iter->first; 86 | BodyDef *bodyDef = new BodyDef(); 87 | bodies[num++] = bodyDef; 88 | bodyDefs.insert(std::make_pair(bodyName, bodyDef)); 89 | bodyDef->anchorPoint = PointFromString(bodyData.at("anchorpoint").asString()); 90 | bodyDef->isDynamic = bodyData.at("is_dynamic").asBool(); 91 | bodyDef->affectedByGravity = bodyData.at("affected_by_gravity").asBool(); 92 | bodyDef->allowsRotation = bodyData.at("allows_rotation").asBool(); 93 | bodyDef->linearDamping = bodyData.at("linear_damping").asFloat(); 94 | bodyDef->angularDamping = bodyData.at("angular_damping").asFloat(); 95 | bodyDef->velocityLimit = bodyData.at("velocity_limit").asFloat(); 96 | bodyDef->angularVelocityLimit = bodyData.at("angular_velocity_limit").asFloat(); 97 | 98 | const ValueVector &fixtureList = bodyData.at("fixtures").asValueVector(); 99 | for (auto &fixtureitem : fixtureList) 100 | { 101 | FixtureData *fd = new FixtureData(); 102 | bodyDef->fixtures.push_back(fd); 103 | auto &fixturedata = fixtureitem.asValueMap(); 104 | fd->density = fixturedata.at("density").asFloat(); 105 | fd->restitution = fixturedata.at("restitution").asFloat(); 106 | fd->friction = fixturedata.at("friction").asFloat(); 107 | fd->tag = fixturedata.at("tag").asInt(); 108 | fd->group = fixturedata.at("group").asInt(); 109 | fd->categoryMask = fixturedata.at("category_mask").asInt(); 110 | fd->collisionMask = fixturedata.at("collision_mask").asInt(); 111 | fd->contactTestMask = fixturedata.at("contact_test_mask").asInt(); 112 | 113 | std::string fixtureType = fixturedata.at("fixture_type").asString(); 114 | if (fixtureType == "POLYGON") 115 | { 116 | fd->fixtureType = FIXTURE_POLYGON; 117 | const ValueVector &polygonsArray = fixturedata.at("polygons").asValueVector(); 118 | for (auto &polygonitem : polygonsArray) 119 | { 120 | Polygon *poly = new Polygon(); 121 | fd->polygons.push_back(poly); 122 | auto &polygonArray = polygonitem.asValueVector(); 123 | poly->numVertices = (int)polygonArray.size(); 124 | auto *vertices = poly->vertices = new cocos2d::Point[poly->numVertices]; 125 | int vindex = 0; 126 | for (auto &pointString : polygonArray) 127 | { 128 | auto offset = PointFromString(pointString.asString()); 129 | vertices[vindex].x = offset.x / scaleFactor; 130 | vertices[vindex].y = offset.y / scaleFactor; 131 | vindex++; 132 | } 133 | } 134 | } 135 | else if (fixtureType == "CIRCLE") 136 | { 137 | fd->fixtureType = FIXTURE_CIRCLE; 138 | const ValueMap &circleData = fixturedata.at("circle").asValueMap(); 139 | fd->radius = circleData.at("radius").asFloat() / scaleFactor; 140 | fd->center = PointFromString(circleData.at("position").asString()) / scaleFactor; 141 | } 142 | else 143 | { 144 | // unknown type 145 | return false; 146 | } 147 | 148 | } 149 | } 150 | 151 | bodiesInFile[plist] = bodies; 152 | 153 | return true; 154 | } 155 | 156 | 157 | PhysicsShapeCache::BodyDef *PhysicsShapeCache::getBodyDef(const std::string &name) 158 | { 159 | try 160 | { 161 | return bodyDefs.at(name); 162 | } 163 | catch(std::out_of_range&) 164 | { 165 | } 166 | 167 | try 168 | { 169 | return bodyDefs.at(name.substr(0, name.rfind('.'))); // remove file suffix and try again... 170 | } 171 | catch(std::out_of_range&) 172 | { 173 | } 174 | 175 | return nullptr; 176 | } 177 | 178 | 179 | void PhysicsShapeCache::setBodyProperties(PhysicsBody *body, BodyDef *bd) 180 | { 181 | body->setGravityEnable(bd->affectedByGravity); 182 | body->setDynamic(bd->isDynamic); 183 | body->setRotationEnable(bd->allowsRotation); 184 | body->setLinearDamping(bd->linearDamping); 185 | body->setAngularDamping(bd->angularDamping); 186 | body->setVelocityLimit(bd->velocityLimit); 187 | body->setAngularVelocityLimit(bd->angularVelocityLimit); 188 | } 189 | 190 | 191 | void PhysicsShapeCache::setShapeProperties(PhysicsShape *shape, FixtureData *fd) 192 | { 193 | shape->setGroup(fd->group); 194 | shape->setCategoryBitmask(fd->categoryMask); 195 | shape->setCollisionBitmask(fd->collisionMask); 196 | shape->setContactTestBitmask(fd->contactTestMask); 197 | shape->setTag(fd->tag); 198 | } 199 | 200 | 201 | PhysicsBody *PhysicsShapeCache::createBodyWithName(const std::string &name) 202 | { 203 | BodyDef *bd = getBodyDef(name); 204 | if (!bd) 205 | { 206 | CCLOG("WARNING: PhysicsBody with name \"%s\", not found!", name.c_str()); 207 | return nullptr; // body not found 208 | } 209 | PhysicsBody *body = PhysicsBody::create(); 210 | setBodyProperties(body, bd); 211 | 212 | for (auto fd : bd->fixtures) 213 | { 214 | PhysicsMaterial material(fd->density, fd->restitution, fd->friction); 215 | if (fd->fixtureType == FIXTURE_CIRCLE) 216 | { 217 | auto shape = PhysicsShapeCircle::create(fd->radius, material, fd->center); 218 | setShapeProperties(shape, fd); 219 | body->addShape(shape); 220 | } 221 | else if (fd->fixtureType == FIXTURE_POLYGON) 222 | { 223 | for (auto polygon : fd->polygons) 224 | { 225 | auto shape = PhysicsShapePolygon::create(polygon->vertices, polygon->numVertices, material, fd->center); 226 | setShapeProperties(shape, fd); 227 | body->addShape(shape); 228 | } 229 | } 230 | } 231 | return body; 232 | } 233 | 234 | 235 | bool PhysicsShapeCache::setBodyOnSprite(const std::string &name, Sprite *sprite) 236 | { 237 | PhysicsBody *body = createBodyWithName(name); 238 | if (body) 239 | { 240 | sprite->setPhysicsBody(body); 241 | sprite->setAnchorPoint(getBodyDef(name)->anchorPoint); 242 | } 243 | return body != nullptr; 244 | } 245 | 246 | 247 | void PhysicsShapeCache::removeShapesWithFile(const std::string &plist) 248 | { 249 | auto bodies = bodiesInFile.at(plist); 250 | 251 | for (auto iter = bodies.begin(); iter != bodies.end(); ++iter) 252 | { 253 | safeDeleteBodyDef(*iter); 254 | } 255 | 256 | bodiesInFile.erase(plist); 257 | 258 | return; 259 | } 260 | 261 | 262 | void PhysicsShapeCache::removeAllShapes() 263 | { 264 | for (auto iter = bodyDefs.cbegin(); iter != bodyDefs.cend(); ++iter) 265 | { 266 | safeDeleteBodyDef(iter->second); 267 | } 268 | bodyDefs.clear(); 269 | bodiesInFile.clear(); 270 | } 271 | 272 | 273 | void PhysicsShapeCache::safeDeleteBodyDef(BodyDef *bodyDef) 274 | { 275 | for (auto fixturedata : bodyDef->fixtures) 276 | { 277 | for (auto polygon : fixturedata->polygons) 278 | { 279 | CC_SAFE_DELETE_ARRAY(polygon->vertices); 280 | CC_SAFE_DELETE(polygon); 281 | } 282 | fixturedata->polygons.clear(); 283 | CC_SAFE_DELETE(fixturedata); 284 | } 285 | bodyDef->fixtures.clear(); 286 | CC_SAFE_DELETE(bodyDef); 287 | } 288 | -------------------------------------------------------------------------------- /cocos2d-x/PhysicsShapeCache.h: -------------------------------------------------------------------------------- 1 | // 2 | // PhysicsShapeCache.h 3 | // 4 | // Shape cache for Cocos2d-x (v3.x) with built-in physics classes. 5 | // 6 | // Loads physics sprites created with https://www.codeandweb.com/physicseditor 7 | // 8 | // Copyright (c) 2015 CodeAndWeb GmbH. All rights reserved. 9 | // https://www.codeandweb.com 10 | // 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to deal 13 | // in the Software without restriction, including without limitation the rights 14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | // copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | // THE SOFTWARE. 28 | // 29 | 30 | #ifndef __PhysicsShapeCache_h__ 31 | #define __PhysicsShapeCache_h__ 32 | #include "cocos2d.h" 33 | 34 | USING_NS_CC; 35 | 36 | 37 | class PhysicsShapeCache 38 | { 39 | public: 40 | 41 | /** 42 | * Get pointer to the PhysicsShapeCache singleton instance 43 | * 44 | * @return PhysicsShapeCache* 45 | */ 46 | static PhysicsShapeCache *getInstance(); 47 | 48 | /** 49 | * Adds all physics shapes from a plist file. 50 | * Shapes are scaled by contentScaleFactor 51 | * 52 | * @param plist name of the shape definitions file to load 53 | * 54 | * @retval true if ok 55 | * @retval false on error 56 | */ 57 | bool addShapesWithFile(const std::string &plist); 58 | 59 | /** 60 | * Adds all physics shapes from a plist file. 61 | * 62 | * @param plist name of the shape definitions file to load 63 | * @param scaleFactor scale factor to apply for all shapes 64 | * 65 | * @retval true if ok 66 | * @retval false on error 67 | */ 68 | bool addShapesWithFile(const std::string &plist, float scaleFactor); 69 | 70 | /** 71 | * Removes all shapes loaded from the given file 72 | * 73 | * @param plist name of the body definitions file 74 | */ 75 | void removeShapesWithFile(const std::string &plist); 76 | 77 | /** 78 | * Removes all shapes 79 | */ 80 | void removeAllShapes(); 81 | 82 | /** 83 | * Creates a PhysicsBody with the given name 84 | * 85 | * @param name name of the body to create 86 | * 87 | * @return new PhysicsBody 88 | * @retval nullptr if body is not found 89 | */ 90 | PhysicsBody *createBodyWithName(const std::string &name); 91 | 92 | /** 93 | * Creates a new PhysicsBody and attaches it to the given sprite 94 | * 95 | * @param name name of the body to attach 96 | * @param sprite sprite to attach the body to 97 | * 98 | * @retval true if body was attached to the sprite 99 | * @retval false if body was not found 100 | */ 101 | bool setBodyOnSprite(const std::string &name, Sprite *sprite); 102 | 103 | private: 104 | typedef enum 105 | { 106 | FIXTURE_POLYGON, 107 | FIXTURE_CIRCLE 108 | } FixtureType; 109 | 110 | 111 | class Polygon 112 | { 113 | public: 114 | Point* vertices; 115 | int numVertices; 116 | }; 117 | 118 | 119 | class FixtureData 120 | { 121 | public: 122 | FixtureType fixtureType; 123 | 124 | float density; 125 | float restitution; 126 | float friction; 127 | 128 | int tag; 129 | int group; 130 | int categoryMask; 131 | int collisionMask; 132 | int contactTestMask; 133 | 134 | // for circles 135 | Point center; 136 | float radius; 137 | 138 | 139 | std::vector polygons; 140 | }; 141 | 142 | 143 | class BodyDef 144 | { 145 | public: 146 | Point anchorPoint; 147 | std::vector fixtures; 148 | 149 | bool isDynamic; 150 | bool affectedByGravity; 151 | bool allowsRotation; 152 | 153 | float linearDamping; 154 | float angularDamping; 155 | float velocityLimit; 156 | float angularVelocityLimit; 157 | }; 158 | 159 | PhysicsShapeCache(); 160 | ~PhysicsShapeCache(); 161 | void safeDeleteBodyDef(BodyDef *bodyDef); 162 | BodyDef *getBodyDef(const std::string &name); 163 | void setBodyProperties(PhysicsBody *body, BodyDef *bd); 164 | void setShapeProperties(PhysicsShape *shape, FixtureData *fd); 165 | 166 | std::map bodyDefs; 167 | std::map> bodiesInFile; 168 | }; 169 | 170 | 171 | #endif // __PhysicsShapeCache_h 172 | -------------------------------------------------------------------------------- /cocos2d/PhysicsShapeCache.h: -------------------------------------------------------------------------------- 1 | // 2 | // PhysicsShapeCache.h 3 | // 4 | // Loads physics sprites created with https://www.codeandweb.com/physicseditor 5 | // 6 | // Shape Cache for Cocos2D V3 / Chipmunk 7 | // 8 | // Copyright (c) 2015 CodeAndWeb GmbH. All rights reserved. 9 | // https://www.codeandweb.com 10 | // 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to deal 13 | // in the Software without restriction, including without limitation the rights 14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | // copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | // THE SOFTWARE. 28 | // 29 | 30 | #import 31 | #import "CCPhysicsBody.h" 32 | 33 | /** 34 | * Shape cache 35 | * This class holds the shapes and makes them accessible 36 | * The format can be used on any MacOS/iOS system 37 | */ 38 | @interface PhysicsShapeCache : NSObject 39 | { 40 | NSMutableDictionary *bodyDefs; 41 | } 42 | 43 | + (PhysicsShapeCache *)sharedShapeCache; 44 | 45 | /** 46 | * Adds shapes to the shape cache 47 | * @param plist name of the plist file to load 48 | * @result FALSE in case of error 49 | */ 50 | -(BOOL) addShapesWithFile:(NSString*)plist; 51 | 52 | /** 53 | * Creates a body for the shape with the given name. 54 | * @param name name of the body 55 | * @result new created body 56 | */ 57 | -(CCPhysicsBody *) createBodyWithName:(NSString*)name; 58 | 59 | /** 60 | * Creates a body for the shape with the given name, 61 | * and sets the body on the passed CCNode. It also sets the 62 | * anchor point of the node. 63 | * @param name name of the body 64 | * @param node node on which the body should be set 65 | */ 66 | -(void) setBodyWithName:(NSString *)name onNode:(CCNode *)node; 67 | 68 | /** 69 | * Returns the anchor point of the given sprite 70 | * @param shape name of the shape to get the anchorpoint for 71 | * @return anchorpoint 72 | */ 73 | -(CGPoint) anchorPointForShape:(NSString*)shape; 74 | 75 | @end 76 | -------------------------------------------------------------------------------- /cocos2d/PhysicsShapeCache.m: -------------------------------------------------------------------------------- 1 | // 2 | // PhysicsShapeCache.m 3 | // 4 | // Loads physics sprites created with https://www.codeandweb.com/physicseditor 5 | // 6 | // Shape Cache for Cocos2D V3 / Chipmunk 7 | // 8 | // Copyright (c) 2015 CodeAndWeb GmbH. All rights reserved. 9 | // https://www.codeandweb.com 10 | // 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to deal 13 | // in the Software without restriction, including without limitation the rights 14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | // copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | // THE SOFTWARE. 28 | // 29 | 30 | #import "PhysicsShapeCache.h" 31 | #import "CCPhysicsShape.h" 32 | #import "CCPhysicsBody.h" 33 | 34 | 35 | #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) 36 | # define CGPointFromString_ CGPointFromString 37 | #else 38 | // well - not nice but works for now 39 | static CGPoint CGPointFromString_(NSString* str) 40 | { 41 | NSString* theString = str; 42 | theString = [theString stringByReplacingOccurrencesOfString:@"{ " withString:@""]; 43 | theString = [theString stringByReplacingOccurrencesOfString:@" }" withString:@""]; 44 | NSArray *array = [theString componentsSeparatedByString:@","]; 45 | return CGPointMake([[array objectAtIndex:0] floatValue], [[array objectAtIndex:1] floatValue]); 46 | } 47 | #endif 48 | 49 | 50 | @interface GPolygon : NSObject 51 | { 52 | @public 53 | CGPoint *vertices; 54 | NSUInteger numVertices; 55 | } 56 | @end 57 | 58 | @implementation GPolygon 59 | 60 | -(void) dealloc 61 | { 62 | free(vertices); 63 | } 64 | 65 | @end 66 | 67 | typedef enum 68 | { 69 | GFIXTURE_POLYGON, 70 | GFIXTURE_POLYLINE, 71 | GFIXTURE_CIRCLE 72 | } GFixtureType; 73 | 74 | /** 75 | * Fixture definition 76 | * Holds fixture data 77 | */ 78 | @interface GFixtureData : NSObject 79 | { 80 | @public 81 | 82 | GFixtureType fixtureType; 83 | 84 | CGFloat mass; 85 | CGFloat elasticity; 86 | CGFloat friction; 87 | 88 | CGPoint surfaceVelocity; 89 | 90 | NSString *collisionGroup; 91 | NSString *collisionType; 92 | NSArray *collisionCategories; 93 | NSArray *collisionMask; 94 | 95 | BOOL isSensor; 96 | 97 | // for circles 98 | CGPoint center; 99 | CGFloat radius; 100 | 101 | // for polygons / polyline 102 | NSMutableArray *polygons; 103 | CGFloat cornerRadius; 104 | } 105 | @end 106 | 107 | @implementation GFixtureData 108 | 109 | -(id) init 110 | { 111 | self = [super init]; 112 | if(self) 113 | { 114 | polygons = [[NSMutableArray alloc] init]; 115 | } 116 | return self; 117 | } 118 | 119 | @end 120 | 121 | 122 | 123 | /** 124 | * Body definition 125 | * Holds the body and the anchor point 126 | */ 127 | @interface GBodyDef : NSObject 128 | { 129 | @public 130 | CGPoint anchorPoint; 131 | CCPhysicsBodyType bodyType; 132 | NSMutableArray *fixtures; 133 | BOOL affectedByGravity; 134 | BOOL allowsRotation; 135 | } 136 | @end 137 | 138 | 139 | @implementation GBodyDef 140 | 141 | -(id) init 142 | { 143 | self = [super init]; 144 | if(self) 145 | { 146 | fixtures = [[NSMutableArray alloc] init]; 147 | } 148 | return self; 149 | } 150 | 151 | @end 152 | 153 | 154 | @implementation PhysicsShapeCache 155 | { 156 | NSArray *categoryNames; 157 | CGFloat scaleFactor; 158 | } 159 | 160 | + (PhysicsShapeCache *)sharedShapeCache 161 | { 162 | static PhysicsShapeCache *shapeCache = 0; 163 | if(!shapeCache) 164 | { 165 | shapeCache = [[PhysicsShapeCache alloc] init]; 166 | } 167 | return shapeCache; 168 | } 169 | 170 | -(id) init 171 | { 172 | self = [super init]; 173 | if(self) 174 | { 175 | bodyDefs = [[NSMutableDictionary alloc] init]; 176 | } 177 | return self; 178 | } 179 | 180 | -(CGPoint) anchorPointForShape:(NSString*)shape 181 | { 182 | GBodyDef *bd = [bodyDefs objectForKey:shape]; 183 | assert(bd); 184 | return bd->anchorPoint; 185 | } 186 | 187 | 188 | +(void) setProperties:(GFixtureData *)fixture onShape:(CCPhysicsShape *)shape 189 | { 190 | [shape setMass:fixture->mass]; 191 | [shape setElasticity:fixture->elasticity]; 192 | [shape setFriction:fixture->friction]; 193 | [shape setSurfaceVelocity:fixture->surfaceVelocity]; 194 | [shape setSensor:fixture->isSensor]; 195 | if (fixture->collisionCategories != nil && [fixture->collisionCategories count] > 0) 196 | { 197 | [shape setCollisionCategories:fixture->collisionCategories]; 198 | } 199 | if (fixture->collisionMask != nil && [fixture->collisionMask count] > 0) 200 | { 201 | [shape setCollisionMask:fixture->collisionMask]; 202 | } 203 | if (fixture->collisionGroup != nil) 204 | { 205 | [shape setCollisionGroup:fixture->collisionGroup]; 206 | } 207 | if (fixture->collisionType != nil) 208 | { 209 | [shape setCollisionType:fixture->collisionType]; 210 | } 211 | } 212 | 213 | 214 | -(CCPhysicsBody *) createBodyWithName:(NSString*)name 215 | { 216 | GBodyDef *bd = [bodyDefs objectForKey:name]; 217 | NSAssert(bd != 0, @"Body not found"); 218 | if(!bd) 219 | { 220 | return 0; 221 | } 222 | 223 | NSMutableArray *shapes = [NSMutableArray array]; 224 | // iterate over fixtures 225 | for(GFixtureData *fd in bd->fixtures) 226 | { 227 | if(fd->fixtureType == GFIXTURE_CIRCLE) 228 | { 229 | CCPhysicsShape *shape = [CCPhysicsShape circleShapeWithRadius:fd->radius center:fd->center]; 230 | [PhysicsShapeCache setProperties:fd onShape:shape]; 231 | [shapes addObject:shape]; 232 | } 233 | else if (fd->fixtureType == GFIXTURE_POLYLINE) 234 | { 235 | // first poligon is hull 236 | GPolygon *hull = fd->polygons[0]; 237 | for(int i = 0; i < hull->numVertices; i++) 238 | { 239 | CCPhysicsShape *shape = [CCPhysicsShape pillShapeFrom:hull->vertices[i] to:hull->vertices[(i+1) % hull->numVertices] cornerRadius:fd->cornerRadius]; 240 | [PhysicsShapeCache setProperties:fd onShape:shape]; 241 | [shapes addObject:shape]; 242 | } 243 | } 244 | else 245 | { 246 | NSAssert(fd->fixtureType == GFIXTURE_POLYGON, @"Unknown fixture type"); 247 | // iterate over polygons 248 | for(GPolygon *p in fd->polygons) 249 | { 250 | CCPhysicsShape *shape = [CCPhysicsShape polygonShapeWithPoints:p->vertices count:p->numVertices cornerRadius:fd->cornerRadius]; 251 | [PhysicsShapeCache setProperties:fd onShape:shape]; 252 | [shapes addObject:shape]; 253 | } 254 | } 255 | } 256 | CCPhysicsBody *body =[CCPhysicsBody bodyWithShapes:shapes]; 257 | body.affectedByGravity = bd->affectedByGravity; 258 | body.allowsRotation = bd->allowsRotation; 259 | body.type = bd->bodyType; 260 | return body; 261 | } 262 | 263 | -(void) setBodyWithName:(NSString *)name onNode:(CCNode *)node 264 | { 265 | node.physicsBody = [self createBodyWithName:name]; 266 | node.anchorPoint = [self anchorPointForShape:name]; 267 | } 268 | 269 | -(NSArray *)categoryListFromBitfield:(uint32_t)bits 270 | { 271 | NSMutableArray *names = [NSMutableArray new]; 272 | int nameCount = MIN(32, (int)[categoryNames count]); 273 | for (int i = 0; i < nameCount; i++) 274 | { 275 | if (bits & (1 << i)) 276 | { 277 | [names addObject:[categoryNames objectAtIndex:i]]; 278 | } 279 | } 280 | return names; 281 | } 282 | 283 | -(BOOL) addShapesWithFile:(NSString*)plist 284 | { 285 | NSString *path = [[NSBundle mainBundle] pathForResource:plist 286 | ofType:nil 287 | inDirectory:nil]; 288 | 289 | NSDictionary *dictionary = [NSDictionary dictionaryWithContentsOfFile:path]; 290 | if(!dictionary) 291 | { 292 | return FALSE; 293 | } 294 | 295 | NSDictionary *metadataDict = [dictionary objectForKey:@"metadata"]; 296 | int format = [[metadataDict objectForKey:@"format"] intValue]; 297 | 298 | NSAssert(format == 1, @"Format not supported"); 299 | if(format != 1) 300 | { 301 | return FALSE; 302 | } 303 | 304 | categoryNames = [dictionary objectForKey:@"category_names"]; 305 | scaleFactor = [[dictionary objectForKey:@"scale_factor"] floatValue]; 306 | 307 | NSDictionary *bodyDict = [dictionary objectForKey:@"bodies"]; 308 | 309 | for(NSString *bodyName in bodyDict) 310 | { 311 | // get the body data 312 | NSDictionary *bodyData = [bodyDict objectForKey:bodyName]; 313 | 314 | // create body object 315 | GBodyDef *bodyDef = [[GBodyDef alloc] init]; 316 | 317 | // add the body element to the hash 318 | [bodyDefs setObject:bodyDef forKey:bodyName]; 319 | 320 | // set anchor point 321 | bodyDef->anchorPoint = CGPointFromString_([bodyData objectForKey:@"anchorpoint"]); 322 | bodyDef->affectedByGravity = [[bodyData objectForKey:@"affected_by_gravity"] boolValue]; 323 | bodyDef->allowsRotation = [[bodyData objectForKey:@"allows_rotation"] boolValue]; 324 | bodyDef->bodyType =[[bodyData objectForKey:@"is_static"] boolValue] ? CCPhysicsBodyTypeStatic : CCPhysicsBodyTypeDynamic; 325 | 326 | // iterate through the fixtures 327 | NSArray *fixtureList = [bodyData objectForKey:@"fixtures"]; 328 | 329 | for(NSDictionary *fixtureData in fixtureList) 330 | { 331 | // create fixture 332 | GFixtureData *fd = [[GFixtureData alloc] init]; 333 | if(!fd) 334 | { 335 | return FALSE; 336 | } 337 | 338 | // add the fixture to the body 339 | [bodyDef->fixtures addObject:fd]; 340 | 341 | fd->friction = [[fixtureData objectForKey:@"friction"] floatValue]; 342 | fd->elasticity = [[fixtureData objectForKey:@"elasticity"] floatValue]; 343 | fd->mass = [[fixtureData objectForKey:@"mass"] floatValue]; 344 | fd->surfaceVelocity = CGPointFromString_([fixtureData objectForKey:@"surface_velocity"]); 345 | fd->isSensor = [[fixtureData objectForKey:@"is_sensor"] boolValue]; 346 | fd->cornerRadius = [[fixtureData objectForKey:@"corner_radius"] floatValue]; 347 | fd->collisionType = [fixtureData objectForKey:@"collision_type"]; 348 | if ([fd->collisionType length] == 0) 349 | { 350 | fd->collisionType = nil; 351 | } 352 | fd->collisionGroup = [fixtureData objectForKey:@"collision_group"]; 353 | if ([fd->collisionGroup length] == 0) 354 | { 355 | fd->collisionGroup = nil; 356 | } 357 | 358 | uint32_t bits = [[fixtureData objectForKey:@"collision_categories"] unsignedIntValue]; 359 | fd->collisionCategories = [self categoryListFromBitfield:bits]; 360 | bits = [[fixtureData objectForKey:@"collision_mask"] unsignedIntValue]; 361 | fd->collisionMask = [self categoryListFromBitfield:bits]; 362 | 363 | NSString *fixtureType = [fixtureData objectForKey:@"fixture_type"]; 364 | 365 | // read polygon fixtures. One convave fixture may consist of several convex polygons 366 | if([fixtureType isEqual:@"POLYGON"] || [fixtureType isEqual:@"POLYLINE"]) 367 | { 368 | NSArray *polygonsArray = [fixtureData objectForKey:@"polygons"]; 369 | 370 | fd->fixtureType = [fixtureType isEqual:@"POLYGON"] ? GFIXTURE_POLYGON : GFIXTURE_POLYLINE; 371 | 372 | for(NSArray *polygonArray in polygonsArray) 373 | { 374 | GPolygon *poly = [[GPolygon alloc] init]; 375 | if(!poly) 376 | { 377 | return FALSE; 378 | } 379 | 380 | // add the polygon to the fixture 381 | [fd->polygons addObject:poly]; 382 | 383 | // add vertices 384 | poly->numVertices = [polygonArray count]; 385 | CGPoint *vertices = poly->vertices = malloc(sizeof(CGPoint) * poly->numVertices); 386 | if(!vertices) 387 | { 388 | return FALSE; 389 | } 390 | 391 | int vindex=0; 392 | for(NSString *pointString in polygonArray) 393 | { 394 | CGPoint offset = CGPointFromString_(pointString); 395 | vertices[vindex].x = offset.x / scaleFactor; 396 | vertices[vindex].y = offset.y / scaleFactor; 397 | vindex++; 398 | } 399 | 400 | } 401 | } 402 | else if([fixtureType isEqual:@"CIRCLE"]) 403 | { 404 | fd->fixtureType = GFIXTURE_CIRCLE; 405 | 406 | NSDictionary *circleData = [fixtureData objectForKey:@"circle"]; 407 | 408 | fd->radius = [[circleData objectForKey:@"radius"] floatValue] / scaleFactor; 409 | fd->center = CGPointFromString_([circleData objectForKey:@"position"]); 410 | fd->center.x /= scaleFactor; 411 | fd->center.y /= scaleFactor; 412 | } 413 | else 414 | { 415 | // unknown type 416 | assert(0); 417 | } 418 | 419 | } 420 | 421 | } 422 | 423 | return TRUE; 424 | } 425 | 426 | @end 427 | 428 | -------------------------------------------------------------------------------- /gdx-pe-loader/README.md: -------------------------------------------------------------------------------- 1 | # LibGDX/Box2D loader for PhysicsEditor XML file 2 | 3 | A Java library for parsing XML files generated by 4 | [PhysicsEditor](https://www.codeandweb.com/physicseditor) into LibGDX's 5 | [Box2D](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/physics/box2d/package-summary.html) objects. 6 | 7 | 8 | ### Add to project 9 | 10 | You can either add the sources from this subdirectory to you project: [src/main/java/com/codeandweb/physicseditor](src/main/java/com/codeandweb/physicseditor) 11 | 12 | Or you can add the following dependency to you core project of your ```build.gradle``` file: 13 | 14 | project(":core") { 15 | dependencies { 16 | compile "com.codeandweb.physicseditor:gdx-pe-loader:1.1.0" 17 | } 18 | } 19 | 20 | 21 | ### Usage 22 | 23 | Here's an example for loading a body from 24 | [src/test/resources/bugs.xml](src/test/resources/bugs.xml): 25 | 26 | import com.codeandweb.physicseditor.ShapeCache; 27 | ... 28 | 29 | // you need a Box2D world to add the body to 30 | World world = new World(new Vector2(0, -10), true); 31 | 32 | // load the XML file 33 | ShapeCache shapes = new ShapeCache("bugs.xml"); 34 | 35 | // create the body - this will also add it to the physics simulation 36 | Body body = pexml.createBody("bug_0001", world, bodyDef, 1, 1); 37 | 38 | 39 | For more details see our [LibGDX PhysicsEditor tutorial](https://www.codeandweb.com/texturepacker/tutorials/libgdx-physics). 40 | -------------------------------------------------------------------------------- /gdx-pe-loader/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | } 5 | } 6 | 7 | apply plugin: 'java' 8 | apply plugin: 'maven' 9 | apply plugin: 'signing' 10 | 11 | task javadocJar(type: Jar) { 12 | classifier = 'javadoc' 13 | from javadoc 14 | } 15 | 16 | task sourcesJar(type: Jar) { 17 | classifier = 'sources' 18 | from sourceSets.main.allSource 19 | } 20 | 21 | artifacts { 22 | archives javadocJar, sourcesJar 23 | } 24 | 25 | ext { 26 | gdxVersion = '1.9.8' 27 | } 28 | 29 | signing { 30 | sign configurations.archives 31 | } 32 | 33 | 34 | group = "com.codeandweb.physicseditor" 35 | version = "1.1.0" 36 | archivesBaseName = "gdx-pe-loader" 37 | 38 | 39 | sourceCompatibility = 1.6 40 | targetCompatibility = 1.6 41 | 42 | repositories { 43 | jcenter() 44 | mavenCentral() 45 | } 46 | 47 | uploadArchives { 48 | repositories { 49 | mavenDeployer { 50 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } 51 | 52 | repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") { 53 | authentication(userName: ossrhUsername, password: ossrhPassword) 54 | } 55 | 56 | snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") { 57 | authentication(userName: ossrhUsername, password: ossrhPassword) 58 | } 59 | 60 | pom.project { 61 | name 'gdx-pe-loader' 62 | packaging 'jar' 63 | // optionally artifactId can be defined here 64 | description 'LibGDX PhysicsEditor XML loader' 65 | url 'https://www.codeandweb.com/physicseditor' 66 | 67 | scm { 68 | connection 'scm:git:https://github.com/CodeAndWeb/PhysicsEditor-Loaders.git' 69 | developerConnection 'scm:git:https://github.com/CodeAndWeb/PhysicsEditor-Loaders.git' 70 | url 'https://github.com/CodeAndWeb/PhysicsEditor-Loaders' 71 | } 72 | 73 | licenses { 74 | license { 75 | name 'MIT' 76 | url 'https://opensource.org/licenses/mit-license.php' 77 | } 78 | } 79 | 80 | developers { 81 | developer { 82 | id 'codeandweb.com' 83 | name 'Andreas Loew' 84 | email 'dev@codeandweb.com' 85 | } 86 | } 87 | } 88 | } 89 | } 90 | } 91 | 92 | 93 | dependencies { 94 | testCompile group: 'junit', name: 'junit', version: '4.11' 95 | testCompile "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-desktop" 96 | 97 | compile "com.badlogicgames.gdx:gdx-box2d:$gdxVersion" 98 | } 99 | -------------------------------------------------------------------------------- /gdx-pe-loader/gradle.properties: -------------------------------------------------------------------------------- 1 | signing.keyId=00000000 2 | signing.password=xxx 3 | signing.secretKeyRingFile=secring.gpg 4 | 5 | ossrhUsername=codeandweb.com 6 | ossrhPassword=xxx 7 | -------------------------------------------------------------------------------- /gdx-pe-loader/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeAndWeb/PhysicsEditor-Loaders/f1ebe73d7105afe4e8f0d5a8bd1f4b0fb8ab0db5/gdx-pe-loader/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gdx-pe-loader/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Mar 26 10:23:44 PDT 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.9-bin.zip 7 | -------------------------------------------------------------------------------- /gdx-pe-loader/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gdx-pe-loader/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /gdx-pe-loader/src/main/java/com/codeandweb/physicseditor/BodyDefNode.java: -------------------------------------------------------------------------------- 1 | package com.codeandweb.physicseditor; 2 | 3 | import com.badlogic.gdx.utils.Array; 4 | import com.badlogic.gdx.utils.ObjectMap; 5 | import com.badlogic.gdx.utils.XmlReader; 6 | 7 | class BodyDefNode { 8 | 9 | final ObjectMap bodies; 10 | final MetadataNode metadata; 11 | 12 | 13 | BodyDefNode(XmlReader.Element data) { 14 | // load elements 15 | Array bodyElements = data.getChildrenByName("body"); 16 | bodies = new ObjectMap(bodyElements.size * 2); 17 | for (XmlReader.Element elem : bodyElements) { 18 | BodyNode body = new BodyNode(elem); 19 | bodies.put(body.name, body); 20 | } 21 | // load 22 | metadata = new MetadataNode(data.getChildByName("metadata")); 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /gdx-pe-loader/src/main/java/com/codeandweb/physicseditor/BodyNode.java: -------------------------------------------------------------------------------- 1 | package com.codeandweb.physicseditor; 2 | 3 | import com.badlogic.gdx.physics.box2d.Body; 4 | import com.badlogic.gdx.physics.box2d.BodyDef; 5 | import com.badlogic.gdx.physics.box2d.World; 6 | import com.badlogic.gdx.utils.Array; 7 | import com.badlogic.gdx.utils.XmlReader; 8 | 9 | class BodyNode { 10 | 11 | final String name; 12 | final BodyDef bodyDefFromXML; 13 | final Array fixtures; 14 | 15 | BodyNode(XmlReader.Element data) { 16 | // body name 17 | name = data.getAttribute("name"); 18 | 19 | // BodyDef properties 20 | bodyDefFromXML = new BodyDef(); 21 | bodyDefFromXML.allowSleep = data.getChildByName("allow_sleep") != null; 22 | bodyDefFromXML.fixedRotation = data.getChildByName("fixed_rotation") != null; 23 | bodyDefFromXML.bullet = data.getChildByName("is_bullet") != null; 24 | bodyDefFromXML.type = data.getChildByName("is_dynamic") != null ? BodyDef.BodyType.DynamicBody : BodyDef.BodyType.StaticBody; 25 | bodyDefFromXML.linearDamping = data.getFloat("linear_damping"); 26 | bodyDefFromXML.angularDamping = data.getFloat("angular_damping"); 27 | 28 | // child elements 29 | Array fixtureElems = data.getChildrenByName("fixture"); 30 | fixtures = new Array(fixtureElems.size); 31 | for (XmlReader.Element elem : fixtureElems) 32 | fixtures.add(new FixtureNode(elem)); 33 | } 34 | 35 | 36 | Body createBody(World world, float scaleX, float scaleY) { 37 | return createBody(world, bodyDefFromXML, scaleX, scaleY); 38 | } 39 | 40 | 41 | Body createBody(World world, BodyDef bodyDef, float scaleX, float scaleY) { 42 | Body body = world.createBody(bodyDef); 43 | for (FixtureNode fixture : fixtures) 44 | fixture.addToBody(body, scaleX, scaleY); 45 | return body; 46 | } 47 | 48 | void dispose() { 49 | for (FixtureNode fixture : fixtures) { 50 | fixture.dispose(); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /gdx-pe-loader/src/main/java/com/codeandweb/physicseditor/CircleNode.java: -------------------------------------------------------------------------------- 1 | package com.codeandweb.physicseditor; 2 | 3 | import com.badlogic.gdx.utils.XmlReader; 4 | import com.badlogic.gdx.math.Vector2; 5 | import com.badlogic.gdx.physics.box2d.CircleShape; 6 | 7 | class CircleNode { 8 | 9 | private final float x; 10 | private final float y; 11 | private final float r; 12 | 13 | // cache heap objects 14 | private final CircleShape circleShape = new CircleShape(); 15 | private final Vector2 position = new Vector2(); 16 | 17 | CircleNode(XmlReader.Element data) { 18 | x = data.getFloatAttribute("x"); 19 | y = data.getFloatAttribute("y"); 20 | r = data.getFloatAttribute("r"); 21 | } 22 | 23 | CircleShape getCircleShape(float scale) { 24 | position.set(x * scale, y * scale); 25 | circleShape.setRadius(r * scale); 26 | circleShape.setPosition(position); 27 | return circleShape; 28 | } 29 | 30 | void dispose() 31 | { 32 | circleShape.dispose(); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /gdx-pe-loader/src/main/java/com/codeandweb/physicseditor/FixtureNode.java: -------------------------------------------------------------------------------- 1 | package com.codeandweb.physicseditor; 2 | 3 | import com.badlogic.gdx.utils.Array; 4 | import com.badlogic.gdx.utils.XmlReader; 5 | import com.badlogic.gdx.physics.box2d.Body; 6 | import com.badlogic.gdx.physics.box2d.FixtureDef; 7 | 8 | class FixtureNode { 9 | 10 | final FixtureDef fixtureDef; 11 | 12 | private CircleNode circleNode; 13 | private Array polygonNodes; 14 | 15 | FixtureNode(XmlReader.Element data) { 16 | 17 | fixtureDef = new FixtureDef(); 18 | fixtureDef.density = data.getFloat("density"); 19 | fixtureDef.friction = data.getFloat("friction"); 20 | fixtureDef.restitution = data.getFloat("restitution"); 21 | fixtureDef.filter.categoryBits = (short) data.getInt("filter_category_bits"); 22 | fixtureDef.filter.groupIndex = (short) data.getInt("filter_group_index"); 23 | fixtureDef.filter.maskBits = (short) data.getInt("filter_mask_bits"); 24 | fixtureDef.isSensor = data.getChildByName("is_sensor") != null; 25 | 26 | XmlReader.Element circleElem = data.getChildByName("circle"); 27 | circleNode = circleElem != null ? new CircleNode(circleElem) : null; 28 | 29 | Array polygonElems = data.getChildrenByName("polygon"); 30 | polygonNodes = new Array(polygonElems.size); 31 | for (XmlReader.Element elem : polygonElems) 32 | polygonNodes.add(new PolygonNode(elem)); 33 | 34 | } 35 | 36 | 37 | void addToBody(Body body, float scaleX, float scaleY) { 38 | 39 | if (circleNode != null) { 40 | fixtureDef.shape = circleNode.getCircleShape(scaleX); 41 | body.createFixture(fixtureDef); 42 | } 43 | 44 | if (polygonNodes != null) { 45 | for (PolygonNode polyNode : polygonNodes) { 46 | fixtureDef.shape = polyNode.getPolygonShape(scaleX, scaleY); 47 | body.createFixture(fixtureDef); 48 | } 49 | } 50 | } 51 | 52 | 53 | void dispose() { 54 | if (circleNode != null) 55 | circleNode.dispose(); 56 | circleNode = null; 57 | 58 | if (polygonNodes != null) 59 | for (PolygonNode polyNode : polygonNodes) polyNode.dispose(); 60 | polygonNodes = null; 61 | } 62 | 63 | } -------------------------------------------------------------------------------- /gdx-pe-loader/src/main/java/com/codeandweb/physicseditor/MetadataNode.java: -------------------------------------------------------------------------------- 1 | package com.codeandweb.physicseditor; 2 | 3 | import com.badlogic.gdx.utils.XmlReader; 4 | 5 | class MetadataNode { 6 | final int format; 7 | final float ptmRatio; 8 | 9 | MetadataNode(XmlReader.Element data) 10 | { 11 | format = data.getInt("format"); 12 | ptmRatio = data.getFloat("ptm_ratio"); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /gdx-pe-loader/src/main/java/com/codeandweb/physicseditor/PhysicsShapeCache.java: -------------------------------------------------------------------------------- 1 | package com.codeandweb.physicseditor; 2 | 3 | import com.badlogic.gdx.Gdx; 4 | import com.badlogic.gdx.files.FileHandle; 5 | import com.badlogic.gdx.physics.box2d.Body; 6 | import com.badlogic.gdx.physics.box2d.BodyDef; 7 | import com.badlogic.gdx.physics.box2d.World; 8 | import com.badlogic.gdx.utils.SerializationException; 9 | import com.badlogic.gdx.utils.XmlReader; 10 | import java.io.IOException; 11 | 12 | 13 | public class PhysicsShapeCache { 14 | 15 | private BodyDefNode bodyDefNode; 16 | 17 | /** 18 | * Creates a new instance of ShapeCache and loads the passed PhysicsEditor XML file 19 | * containing the body + fixture definitions. 20 | * 21 | * @param file Handle of the XML file 22 | * @throws SerializationException if XML data file cannot be loaded or parsed 23 | */ 24 | public PhysicsShapeCache(FileHandle file) throws SerializationException { 25 | try { 26 | XmlReader reader = new XmlReader(); 27 | XmlReader.Element rootNode = reader.parse(file); 28 | 29 | bodyDefNode = new BodyDefNode(rootNode); 30 | } catch (SerializationException e) { 31 | e.printStackTrace(); 32 | throw new SerializationException("failed to load physics shapes XML", e); 33 | } 34 | } 35 | 36 | /** 37 | * Creates a new instance of ShapeCache and loads the passed PhysicsEditor XML file 38 | * containing the body + fixture definitions. 39 | * 40 | * @param internalPath Internal file path of the XML file 41 | */ 42 | public PhysicsShapeCache(String internalPath) throws SerializationException { 43 | this(Gdx.files.internal(internalPath)); 44 | } 45 | 46 | /** 47 | * Creates a Box2D body, using the fixture definitions loaded from file. 48 | * 49 | * @param name The name of the body exactly as it appears in the XML file. 50 | * @param world The Box2D world to use to create the body. 51 | * @param bodyDef The body's attributes. The body attributes loaded from XML are ignored 52 | * @param scaleX Scale for the fixture widths. 53 | * @param scaleY Scale for the fixture heights, ignored for circles. 54 | * @return A Box2D body. 55 | */ 56 | public Body createBody(String name, World world, BodyDef bodyDef, float scaleX, float scaleY) { 57 | BodyNode bodyNode = bodyDefNode.bodies.get(name); 58 | return bodyNode == null ? null : bodyNode.createBody(world, bodyDef, scaleX, scaleY); 59 | } 60 | 61 | 62 | /** 63 | * Creates a Box2D body, using the body + fixture definitions loaded from file. 64 | * 65 | * @param name The name of the body exactly as it appears in the XML file. 66 | * @param world The Box2D world to use to create the body. 67 | * @param scaleX Scale for the fixture widths. 68 | * @param scaleY Scale for the fixture heights, ignored for circles. 69 | * @return A Box2D body. 70 | */ 71 | public Body createBody(String name, World world, float scaleX, float scaleY) { 72 | BodyNode bodyNode = bodyDefNode.bodies.get(name); 73 | return bodyNode == null ? null : bodyNode.createBody(world, scaleX, scaleY); 74 | } 75 | 76 | /** 77 | * Checks if the supplied body name is present in the XML file. 78 | * 79 | * @param name The name of the body. 80 | * @return Whether or not the name is present. 81 | */ 82 | public boolean contains(String name) { 83 | return bodyDefNode.bodies.get(name) != null; 84 | } 85 | 86 | /** 87 | * Gets the pixels-per-meter ratio. 88 | * 89 | * @return PTM 90 | */ 91 | public float getPTM() { 92 | return bodyDefNode.metadata.ptmRatio; 93 | } 94 | 95 | 96 | /** 97 | * Releases the Shape objects which have been created when loading the XML file. 98 | * To avoid memory leaks you have to call this method if the ShapeCache instance is no longer needed. 99 | */ 100 | public void dispose() { 101 | for (BodyNode body : bodyDefNode.bodies.values()) 102 | body.dispose(); 103 | bodyDefNode.bodies.clear(); 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /gdx-pe-loader/src/main/java/com/codeandweb/physicseditor/PolygonNode.java: -------------------------------------------------------------------------------- 1 | package com.codeandweb.physicseditor; 2 | 3 | import com.badlogic.gdx.utils.XmlReader; 4 | import com.badlogic.gdx.math.Polygon; 5 | import com.badlogic.gdx.physics.box2d.PolygonShape; 6 | 7 | class PolygonNode { 8 | 9 | private final Polygon polygon; 10 | private final PolygonShape polygonShape = new PolygonShape(); // cache heap object 11 | 12 | PolygonNode(XmlReader.Element data) { 13 | float[] vertices = Utility.parseFloatsCSV(data.getText()); 14 | polygon = new Polygon(vertices); 15 | } 16 | 17 | PolygonShape getPolygonShape(float scaleX, float scaleY) { 18 | polygon.setScale(scaleX, scaleY); 19 | polygonShape.set(polygon.getTransformedVertices()); 20 | return polygonShape; 21 | } 22 | 23 | void dispose() 24 | { 25 | polygonShape.dispose(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /gdx-pe-loader/src/main/java/com/codeandweb/physicseditor/Utility.java: -------------------------------------------------------------------------------- 1 | package com.codeandweb.physicseditor; 2 | 3 | /** 4 | * Utility class for static helper methods. 5 | */ 6 | final class Utility { 7 | /** 8 | * Converts a CSV string of floats into an array of floats. Example: 9 | * {@code "1.2, 3.4"} to {@code new float[]{1.2f, 3.4f}}. 10 | * 11 | * @param csv The CSV string to parse. 12 | * @return An array of floats. 13 | */ 14 | static float[] parseFloatsCSV(String csv) { 15 | String[] strings = csv.split("\\s*,\\s*"); 16 | 17 | int length = strings.length; 18 | 19 | float[] floats = new float[length]; 20 | 21 | for (int i = 0; i < length; i++) 22 | floats[i] = Float.parseFloat(strings[i].trim()); 23 | 24 | return floats; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /gdx-pe-loader/src/test/java/com/codeandweb/physicseditor/BodyNodeTest.java: -------------------------------------------------------------------------------- 1 | package com.codeandweb.physicseditor; 2 | 3 | import com.badlogic.gdx.math.Vector2; 4 | import com.badlogic.gdx.physics.box2d.Body; 5 | import com.badlogic.gdx.physics.box2d.BodyDef; 6 | import com.badlogic.gdx.physics.box2d.Fixture; 7 | import com.badlogic.gdx.physics.box2d.World; 8 | import com.badlogic.gdx.utils.Array; 9 | import com.badlogic.gdx.utils.XmlReader; 10 | 11 | import org.junit.Before; 12 | import org.junit.Test; 13 | 14 | import static org.junit.Assert.*; 15 | 16 | public class BodyNodeTest { 17 | private BodyDef bodyDef; 18 | private World world; 19 | 20 | @Before 21 | public void setUp() throws Exception { 22 | bodyDef = new BodyDef(); 23 | world = new World(new Vector2(0, 0), true); 24 | } 25 | 26 | // @Test 27 | // public void getAnchorPoint() throws Exception { 28 | // 29 | // XmlReader xml = new XmlReader(); 30 | // XmlReader.Element elem = xml.parse("1.23, 4.567"); 31 | // BodyNode bodyNode = new BodyNode(elem); 32 | // 33 | // Vector2 anchorPoint = bodyNode.anchorPoint; 34 | // 35 | // assertNotNull(anchorPoint); 36 | // assertEquals(1.23f, anchorPoint.x, 0); 37 | // assertEquals(4.567f, anchorPoint.y, 0); 38 | // } 39 | 40 | @Test 41 | public void testCreateBody() throws Exception { 42 | PhysicsShapeCache shapeCache = Fixtures.load("bugs.xml"); 43 | 44 | Body body = shapeCache.createBody("bug_0001", world, bodyDef, 1, 1); 45 | Array fixtures = body.getFixtureList(); 46 | assertEquals(3, fixtures.size); 47 | 48 | Body body2 = shapeCache.createBody("bug_0001", world, bodyDef, 0.5f, 0.5f); 49 | } 50 | 51 | /** 52 | * This test just makes sure that all of the bodies can be created through 53 | * {@link PhysicsShapeCache} without raising any exceptions. 54 | * 55 | * @throws Exception 56 | */ 57 | @Test 58 | public void testCreateAllBodies() throws Exception { 59 | PhysicsShapeCache shapeCache = Fixtures.load("bugs.xml"); 60 | 61 | shapeCache.createBody("bug_0001", world, bodyDef, 1, 1); 62 | shapeCache.createBody("bug_0002", world, bodyDef, 1, 1); 63 | shapeCache.createBody("bug_0003", world, 1, 1); 64 | shapeCache.createBody("bug_0004", world, 1, 1); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /gdx-pe-loader/src/test/java/com/codeandweb/physicseditor/CircleNodeTest.java: -------------------------------------------------------------------------------- 1 | package com.codeandweb.physicseditor; 2 | 3 | import com.badlogic.gdx.physics.box2d.Box2D; 4 | import com.badlogic.gdx.physics.box2d.CircleShape; 5 | import com.badlogic.gdx.utils.XmlReader; 6 | 7 | import org.junit.Before; 8 | import org.junit.BeforeClass; 9 | import org.junit.Test; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | public class CircleNodeTest { 14 | private CircleNode circleNode; 15 | 16 | @BeforeClass 17 | public static void beforeAll() throws Exception { 18 | Box2D.init(); 19 | } 20 | 21 | @Before 22 | public void setUp() throws Exception { 23 | XmlReader xml = new XmlReader(); 24 | XmlReader.Element elem = xml.parse(""); 25 | circleNode = new CircleNode(elem); 26 | } 27 | 28 | @Test 29 | public void getCircleShape() throws Exception { 30 | CircleShape circleShape = circleNode.getCircleShape(0.5f); 31 | 32 | assertNotNull(circleShape); 33 | assertEquals(5f, circleShape.getRadius(), 0); 34 | assertEquals(50f, circleShape.getPosition().x, 0); 35 | assertEquals(100f, circleShape.getPosition().y, 0); 36 | } 37 | } -------------------------------------------------------------------------------- /gdx-pe-loader/src/test/java/com/codeandweb/physicseditor/FixtureNodeTest.java: -------------------------------------------------------------------------------- 1 | package com.codeandweb.physicseditor; 2 | 3 | import com.badlogic.gdx.physics.box2d.FixtureDef; 4 | import com.badlogic.gdx.utils.XmlReader; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.*; 9 | 10 | public class FixtureNodeTest { 11 | @Test 12 | public void getFixtureDef() throws Exception { 13 | FixtureNode fixtureNode = fakeFixtureNode(true); 14 | FixtureDef fixtureDef = fixtureNode.fixtureDef; 15 | 16 | assertNotNull(fixtureDef); 17 | 18 | assertEquals(0.1f, fixtureDef.density, 0); 19 | assertEquals(0.2f, fixtureDef.friction, 0); 20 | assertEquals(0.3f, fixtureDef.restitution, 0); 21 | assertEquals(1, fixtureDef.filter.categoryBits); 22 | assertEquals(2, fixtureDef.filter.groupIndex); 23 | assertEquals(3, fixtureDef.filter.maskBits); 24 | 25 | assertTrue(fixtureDef.isSensor); 26 | 27 | 28 | fixtureNode = fakeFixtureNode(false); 29 | assertFalse(fixtureNode.fixtureDef.isSensor); 30 | } 31 | 32 | private static FixtureNode fakeFixtureNode(boolean isSensor) { 33 | 34 | XmlReader xml = new XmlReader(); 35 | XmlReader.Element elem = xml.parse( 36 | "" + 37 | " 0.1" + 38 | " 0.2" + 39 | " 0.3" + 40 | " 1" + 41 | " 2" + 42 | " 3" + 43 | (isSensor ? " " : "") + 44 | " " + 45 | ""); 46 | FixtureNode fixtureNode = new FixtureNode(elem); 47 | 48 | return fixtureNode; 49 | } 50 | } -------------------------------------------------------------------------------- /gdx-pe-loader/src/test/java/com/codeandweb/physicseditor/Fixtures.java: -------------------------------------------------------------------------------- 1 | package com.codeandweb.physicseditor; 2 | 3 | import com.badlogic.gdx.files.FileHandle; 4 | import com.badlogic.gdx.physics.box2d.Box2D; 5 | 6 | import java.io.File; 7 | 8 | public final class Fixtures { 9 | private static boolean box2dInitialized = false; 10 | 11 | /** 12 | * Creates a ShapeCache instance from an XML fixture found in the resources path. 13 | * 14 | * @param fixtureName The fixture's file name without a path or extension. 15 | * @return A {@link PhysicsShapeCache} instance. 16 | */ 17 | static PhysicsShapeCache load(String fixtureName) { 18 | initBox2D(); 19 | String filename = String.format("src/test/resources/%s", fixtureName); 20 | return new PhysicsShapeCache(new FileHandle(filename)); 21 | } 22 | 23 | /** 24 | * Initializes Box2D if it hasn't already been. 25 | */ 26 | private static void initBox2D() { 27 | if (!box2dInitialized) { 28 | Box2D.init(); 29 | box2dInitialized = true; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /gdx-pe-loader/src/test/java/com/codeandweb/physicseditor/MetadataNodeTest.java: -------------------------------------------------------------------------------- 1 | package com.codeandweb.physicseditor; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | public class MetadataNodeTest { 8 | @Test 9 | public void testLoadsMetadata() { 10 | PhysicsShapeCache shapeCache = Fixtures.load("bugs.xml"); 11 | 12 | assertEquals(32, shapeCache.getPTM(), 1); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /gdx-pe-loader/src/test/java/com/codeandweb/physicseditor/PolygonNodeTest.java: -------------------------------------------------------------------------------- 1 | package com.codeandweb.physicseditor; 2 | 3 | import com.badlogic.gdx.math.Vector2; 4 | import com.badlogic.gdx.physics.box2d.PolygonShape; 5 | import com.badlogic.gdx.utils.XmlReader; 6 | 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | public class PolygonNodeTest { 13 | private PolygonNode polygonNode; 14 | 15 | @Before 16 | public void setUp() throws Exception { 17 | XmlReader xml = new XmlReader(); 18 | XmlReader.Element elem = xml.parse(" 1.0000, 6.0000 , 19.0000, 6.0000 , 16.0000, 19.0000 , 4.0000, 19.0000 "); 19 | polygonNode = new PolygonNode(elem); 20 | } 21 | 22 | @Test 23 | public void testGetPolygonShapes() throws Exception { 24 | PolygonShape polygonShape = polygonNode.getPolygonShape(1, 1); 25 | 26 | assertNotNull(polygonShape); 27 | 28 | assertEquals(4, polygonShape.getVertexCount()); 29 | 30 | Vector2 vertex = new Vector2(); 31 | 32 | polygonShape.getVertex(0, vertex); 33 | assertEquals(19f, vertex.x, 0); 34 | assertEquals(6f, vertex.y, 0); 35 | 36 | polygonShape.getVertex(1, vertex); 37 | assertEquals(16f, vertex.x, 0); 38 | assertEquals(19f, vertex.y, 0); 39 | 40 | polygonShape.getVertex(2, vertex); 41 | assertEquals(4f, vertex.x, 0); 42 | assertEquals(19f, vertex.y, 0); 43 | 44 | polygonShape.getVertex(3, vertex); 45 | assertEquals(1f, vertex.x, 0); 46 | assertEquals(6f, vertex.y, 0); 47 | 48 | polygonShape = polygonNode.getPolygonShape(0.5f, 0.25f); 49 | 50 | polygonShape.getVertex(0, vertex); 51 | assertEquals(19f * 0.5f, vertex.x, 0); 52 | assertEquals(6f * 0.25f, vertex.y, 0); 53 | } 54 | } -------------------------------------------------------------------------------- /gdx-pe-loader/src/test/java/com/codeandweb/physicseditor/ShapeCacheTest.java: -------------------------------------------------------------------------------- 1 | package com.codeandweb.physicseditor; 2 | 3 | import com.badlogic.gdx.utils.SerializationException; 4 | import org.junit.After; 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.*; 9 | 10 | public class ShapeCacheTest { 11 | private PhysicsShapeCache shapeCache; 12 | 13 | @Before 14 | public void beforeEach() throws Exception { 15 | shapeCache = Fixtures.load("bugs.xml"); 16 | } 17 | 18 | @After 19 | public void afterEach() { 20 | shapeCache.dispose(); 21 | } 22 | 23 | @Test 24 | public void testCreateBody() { 25 | 26 | } 27 | 28 | @Test 29 | public void testLoadsAllBodies() throws Exception { 30 | assertTrue(shapeCache.contains("bug_0001")); 31 | assertTrue(shapeCache.contains("bug_0002")); 32 | assertTrue(shapeCache.contains("bug_0003")); 33 | assertTrue(shapeCache.contains("bug_0004")); 34 | } 35 | 36 | @Test(expected = SerializationException.class) 37 | public void testMissingFile() throws Exception { 38 | Fixtures.load("missing"); 39 | } 40 | 41 | @Test(expected = SerializationException.class) 42 | public void testBrokenFile() throws Exception { 43 | Fixtures.load("bugs.pes"); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /gdx-pe-loader/src/test/resources/bugs.pes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeAndWeb/PhysicsEditor-Loaders/f1ebe73d7105afe4e8f0d5a8bd1f4b0fb8ab0db5/gdx-pe-loader/src/test/resources/bugs.pes -------------------------------------------------------------------------------- /gdx-pe-loader/src/test/resources/bugs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 0 8 | 0 9 | 10 | 11 | 2 12 | 0 13 | 0 14 | 1 15 | 65535 16 | 0 17 | 1.0000, 6.0000, 19.0000, 6.0000, 16.0000, 19.0000, 4.0000, 19.0000 18 | 19 | 20 | 2 21 | 0 22 | 0 23 | 1 24 | 65535 25 | 0 26 | 7.0000, 6.0000, 1.0000, 6.0000, 1.0000, 3.0000, 3.0000, 0.0000, 7.0000, 0.0000 27 | 28 | 29 | 2 30 | 0 31 | 0 32 | 1 33 | 65535 34 | 0 35 | 13.0000, 6.0000, 13.0000, 0.0000, 17.0000, 0.0000, 19.0000, 3.0000, 19.0000, 6.0000 36 | 37 | 38 | 39 | 40 | 41 | 0 42 | 0 43 | 44 | 45 | 2 46 | 0 47 | 0 48 | 1 49 | 65535 50 | 0 51 | 5.0000, 0.0000, 5.0000, 5.0000, 4.0000, 16.0000, 1.0000, 19.0000, 1.0000, 3.0000 52 | 5.0000, 19.0000, 1.0000, 19.0000, 4.0000, 16.0000 53 | 11.0000, 19.0000, 12.0000, 16.0000, 15.0000, 19.0000 54 | 11.0000, 0.0000, 15.0000, 4.0000, 15.0000, 19.0000, 11.0000, 5.0000 55 | 6.0000, 18.0000, 4.0000, 16.0000, 5.0000, 5.0000, 12.0000, 16.0000, 9.4203, 17.9952 56 | 11.0000, 5.0000, 15.0000, 19.0000, 12.0000, 16.0000, 5.0000, 5.0000 57 | 58 | 59 | 60 | 61 | 62 | 0 63 | 0 64 | 65 | 66 | 2 67 | 0 68 | 0 69 | 1 70 | 65535 71 | 0 72 | 73 | 74 | 75 | 76 | 77 | 78 | 0 79 | 0 80 | 81 | 82 | 2 83 | 0 84 | 0 85 | 1 86 | 65535 87 | 0 88 | 89 | 90 | 91 | 2 92 | 0 93 | 0 94 | 1 95 | 65535 96 | 0 97 | 12.0000, 3.0000, 13.0000, 2.0000, 17.0000, 5.0000, 16.0000, 6.0000 98 | 99 | 100 | 2 101 | 0 102 | 0 103 | 1 104 | 65535 105 | 0 106 | 2.0000, 5.0000, 6.0000, 2.0000, 7.0000, 3.0000, 3.0000, 6.0000 107 | 108 | 109 | 2 110 | 0 111 | 0 112 | 1 113 | 65535 114 | 0 115 | 2.0000, 14.0000, 3.0000, 13.0000, 7.0000, 16.0000, 6.0000, 17.0000 116 | 117 | 118 | 2 119 | 0 120 | 0 121 | 1 122 | 65535 123 | 0 124 | 12.0000, 16.0000, 16.0000, 13.0000, 17.0000, 14.0000, 13.0000, 17.0000 125 | 126 | 127 | 128 | 129 | 1 130 | 32 131 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /generic-box2d-plist-cocos2d-x/GB2ShapeCache-x.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // GB2ShapeCache-x.cpp 3 | // 4 | // Loads physics sprites created with https://www.codeandweb.com/physicseditor 5 | // To be used with cocos2d-x 6 | // 7 | // Generic Shape Cache for box2d 8 | // 9 | // Created by Thomas Broquist 10 | // 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to deal 13 | // in the Software without restriction, including without limitation the rights 14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | // copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | // THE SOFTWARE. 28 | //#include "CCNS.h" 29 | 30 | #include "GB2ShapeCache-x.h" 31 | #include "Box2D/Box2D.h" 32 | 33 | USING_NS_CC; 34 | 35 | using namespace cocos2d; 36 | 37 | /** 38 | * Internal class to hold the fixtures 39 | */ 40 | class FixtureDef { 41 | public: 42 | FixtureDef() 43 | : next(NULL) {} 44 | 45 | ~FixtureDef() { 46 | delete next; 47 | delete fixture.shape; 48 | } 49 | 50 | FixtureDef *next; 51 | b2FixtureDef fixture; 52 | int callbackData; 53 | }; 54 | 55 | class BodyDef { 56 | public: 57 | BodyDef() 58 | : fixtures(NULL) {} 59 | 60 | ~BodyDef() { 61 | if (fixtures) 62 | delete fixtures; 63 | } 64 | 65 | FixtureDef *fixtures; 66 | Vec2 anchorPoint; 67 | }; 68 | 69 | static GB2ShapeCache *_sharedGB2ShapeCache = NULL; 70 | 71 | GB2ShapeCache* GB2ShapeCache::sharedGB2ShapeCache(void) { 72 | if (!_sharedGB2ShapeCache) { 73 | _sharedGB2ShapeCache = new GB2ShapeCache(); 74 | _sharedGB2ShapeCache->init(); 75 | } 76 | 77 | return _sharedGB2ShapeCache; 78 | } 79 | 80 | bool GB2ShapeCache::init() { 81 | return true; 82 | } 83 | 84 | void GB2ShapeCache::reset() { 85 | std::map::iterator iter; 86 | for (iter = shapeObjects.begin() ; iter != shapeObjects.end() ; ++iter) { 87 | delete iter->second; 88 | } 89 | shapeObjects.clear(); 90 | } 91 | 92 | void GB2ShapeCache::addFixturesToBody(b2Body *body, const std::string &shape) { 93 | std::map::iterator pos = shapeObjects.find(shape); 94 | assert(pos != shapeObjects.end()); 95 | 96 | BodyDef *so = (*pos).second; 97 | 98 | FixtureDef *fix = so->fixtures; 99 | while (fix) { 100 | body->CreateFixture(&fix->fixture); 101 | fix = fix->next; 102 | } 103 | } 104 | 105 | cocos2d::CCPoint GB2ShapeCache::anchorPointForShape(const std::string &shape) { 106 | std::map::iterator pos = shapeObjects.find(shape); 107 | assert(pos != shapeObjects.end()); 108 | 109 | BodyDef *bd = (*pos).second; 110 | return bd->anchorPoint; 111 | } 112 | 113 | void cocos2d::GB2ShapeCache::addShapesWithFile(const std::string &plist) 114 | { 115 | ValueMap dict = FileUtils::getInstance()->getValueMapFromFile(plist); 116 | if (dict.empty()) 117 | { 118 | return; 119 | } 120 | ValueMap &metadata = dict["metadata"].asValueMap(); 121 | int format = metadata["format"].asInt(); 122 | if (format != 1) 123 | { 124 | CCASSERT(format == 1, "format not supported!"); 125 | } 126 | ptmRatio = metadata["ptm_ratio"].asFloat(); 127 | 128 | ValueMap &bodydict = dict.at("bodies").asValueMap(); 129 | 130 | b2Vec2 vertices[b2_maxPolygonVertices]; 131 | 132 | for (auto iter = bodydict.cbegin(); iter != bodydict.cend(); ++iter) 133 | { 134 | const ValueMap &bodyData = iter->second.asValueMap(); 135 | std::string bodyName = iter->first; 136 | BodyDef *bodyDef = new BodyDef(); 137 | bodyDef->anchorPoint = PointFromString(bodyData.at("anchorpoint").asString()); 138 | const ValueVector &fixtureList = bodyData.at("fixtures").asValueVector(); 139 | FixtureDef **nextFixtureDef = &(bodyDef->fixtures); 140 | 141 | for (auto &fixtureitem : fixtureList) 142 | { 143 | ValueMap fixturedata = fixtureitem.asValueMap(); 144 | b2FixtureDef basicData; 145 | basicData.filter.categoryBits = fixturedata.at("filter_categoryBits").asInt(); 146 | basicData.filter.maskBits = fixturedata.at("filter_maskBits").asInt(); 147 | basicData.filter.groupIndex = fixturedata.at("filter_groupIndex").asInt(); 148 | basicData.friction = fixturedata.at("friction").asFloat(); 149 | basicData.density = fixturedata.at("density").asFloat(); 150 | basicData.restitution = fixturedata.at("restitution").asFloat(); 151 | basicData.isSensor = (bool)fixturedata.at("isSensor").asInt(); 152 | 153 | std::string cb = fixturedata["userdataCbValue"].asString(); 154 | int callbackData = 0; 155 | if (cb.compare("") == 0) 156 | callbackData = std::atoi(cb.c_str()); 157 | std::string fixtureType = fixturedata.at("fixture_type").asString(); 158 | 159 | if (fixtureType == "POLYGON") { 160 | 161 | const ValueVector &polygonsArray = fixturedata["polygons"].asValueVector(); 162 | 163 | for (auto &polygonItem : polygonsArray) 164 | { 165 | FixtureDef *fix = new FixtureDef(); 166 | fix->fixture = basicData; 167 | fix->callbackData = callbackData; 168 | 169 | b2PolygonShape *polyshape = new b2PolygonShape(); 170 | int vindex = 0; 171 | 172 | auto &polygonArray = polygonItem.asValueVector(); 173 | assert(polygonArray.size() <= b2_maxPolygonVertices); 174 | 175 | for (auto &pointString : polygonArray) 176 | { 177 | Vec2 offset = PointFromString(pointString.asString()); 178 | vertices[vindex].x = (offset.x / ptmRatio); 179 | vertices[vindex].y = (offset.y / ptmRatio); 180 | vindex++; 181 | } 182 | 183 | polyshape->Set(vertices, vindex); 184 | fix->fixture.shape = polyshape; 185 | 186 | // create a list 187 | *nextFixtureDef = fix; 188 | nextFixtureDef = &(fix->next); 189 | } 190 | } 191 | else if (fixtureType == "CIRCLE") { 192 | FixtureDef *fix = new FixtureDef(); 193 | fix->fixture = basicData; // copy basic data 194 | fix->callbackData = callbackData; 195 | const ValueMap &circleData = fixturedata.at("circle").asValueMap(); 196 | 197 | b2CircleShape *circleShape = new b2CircleShape(); 198 | 199 | circleShape->m_radius = circleData.at("radius").asFloat() / ptmRatio; 200 | Vec2 p = PointFromString(circleData.at("position").asString()); 201 | circleShape->m_p = b2Vec2(p.x / ptmRatio, p.y / ptmRatio); 202 | fix->fixture.shape = circleShape; 203 | 204 | // create a list 205 | *nextFixtureDef = fix; 206 | nextFixtureDef = &(fix->next); 207 | 208 | } 209 | else { 210 | CCASSERT(0, "Unknown fixtureType"); 211 | } 212 | 213 | // add the body element to the hash 214 | shapeObjects[bodyName] = bodyDef; 215 | } 216 | 217 | } 218 | 219 | } 220 | -------------------------------------------------------------------------------- /generic-box2d-plist-cocos2d-x/GB2ShapeCache-x.h: -------------------------------------------------------------------------------- 1 | // 2 | // GB2ShapeCache-x.h 3 | // 4 | // Loads physics sprites created with https://www.codeandweb.com/physicseditor 5 | // To be used with cocos2d-x 6 | // 7 | // Generic Shape Cache for box2d 8 | // 9 | // Created by Thomas Broquist 10 | // 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to deal 13 | // in the Software without restriction, including without limitation the rights 14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | // copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | // THE SOFTWARE. 28 | // 29 | 30 | #ifndef GB2ShapeCache_x_h 31 | #define GB2ShapeCache_x_h 32 | 33 | #include "cocos2d.h" 34 | 35 | class BodyDef; 36 | class b2Body; 37 | 38 | namespace cocos2d { 39 | class GB2ShapeCache { 40 | public: 41 | // Static interface 42 | static GB2ShapeCache* sharedGB2ShapeCache(void); 43 | 44 | public: 45 | bool init(); 46 | void addShapesWithFile(const std::string &plist); 47 | void addFixturesToBody(b2Body *body, const std::string &shape); 48 | cocos2d::CCPoint anchorPointForShape(const std::string &shape); 49 | void reset(); 50 | float getPtmRatio() { return ptmRatio; } 51 | ~GB2ShapeCache() {} 52 | 53 | private: 54 | std::map shapeObjects; 55 | GB2ShapeCache(void) {} 56 | float ptmRatio; 57 | }; 58 | } 59 | 60 | #endif -------------------------------------------------------------------------------- /generic-box2d-plist/GB2ShapeCache.h: -------------------------------------------------------------------------------- 1 | // 2 | // GB2ShapeCache.h 3 | // 4 | // Loads physics sprites created with https://www.codeandweb.com/physicseditor 5 | // 6 | // Generic Shape Cache for box2d 7 | // 8 | // Copyright (c) 2015 CodeAndWeb GmbH. All rights reserved. 9 | // https://www.codeandweb.com 10 | // 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to deal 13 | // in the Software without restriction, including without limitation the rights 14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | // copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | // THE SOFTWARE. 28 | // 29 | 30 | #import 31 | #import 32 | 33 | /** 34 | * Shape cache 35 | * This class holds the shapes and makes them accessible 36 | * The format can be used on any MacOS/iOS system 37 | */ 38 | @interface GB2ShapeCache : NSObject 39 | { 40 | NSMutableDictionary *shapeObjects_; 41 | float ptmRatio_; 42 | } 43 | 44 | + (GB2ShapeCache *)sharedShapeCache; 45 | 46 | /** 47 | * Adds shapes to the shape cache 48 | * @param plist name of the plist file to load 49 | */ 50 | -(void) addShapesWithFile:(NSString*)plist; 51 | 52 | /** 53 | * Adds fixture data to a body 54 | * @param body body to add the fixture to 55 | * @param shape name of the shape 56 | */ 57 | -(void) addFixturesToBody:(b2Body*)body forShapeName:(NSString*)shape; 58 | 59 | /** 60 | * Returns the anchor point of the given sprite 61 | * @param shape name of the shape to get the anchorpoint for 62 | * @return anchorpoint 63 | */ 64 | -(CGPoint) anchorPointForShape:(NSString*)shape; 65 | 66 | /** 67 | * Returns the ptm ratio 68 | */ 69 | -(float) ptmRatio; 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /generic-box2d-plist/GB2ShapeCache.mm: -------------------------------------------------------------------------------- 1 | // 2 | // GB2ShapeCache.mm 3 | // 4 | // Loads physics sprites created with https://www.codeandweb.com/physicseditor 5 | // 6 | // Generic Shape Cache for box2d 7 | // 8 | // Copyright (c) 2015 CodeAndWeb GmbH. All rights reserved. 9 | // https://www.codeandweb.com 10 | // 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to deal 13 | // in the Software without restriction, including without limitation the rights 14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | // copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | // THE SOFTWARE. 28 | // 29 | 30 | #import "GB2ShapeCache.h" 31 | 32 | #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) 33 | # define CGPointFromString_ CGPointFromString 34 | #else 35 | // well - not nice but works for now 36 | static CGPoint CGPointFromString_(NSString* str) 37 | { 38 | NSString* theString = str; 39 | theString = [theString stringByReplacingOccurrencesOfString:@"{ " withString:@""]; 40 | theString = [theString stringByReplacingOccurrencesOfString:@" }" withString:@""]; 41 | NSArray *array = [theString componentsSeparatedByString:@","]; 42 | return CGPointMake([[array objectAtIndex:0] floatValue], [[array objectAtIndex:1] floatValue]); 43 | } 44 | #endif 45 | 46 | /** 47 | * Internal class to hold the fixtures 48 | */ 49 | class FixtureDef 50 | { 51 | public: 52 | FixtureDef() 53 | : next(0) 54 | {} 55 | 56 | ~FixtureDef() 57 | { 58 | delete next; 59 | delete fixture.shape; 60 | } 61 | 62 | FixtureDef *next; 63 | b2FixtureDef fixture; 64 | int callbackData; 65 | }; 66 | 67 | /** 68 | * Body definition 69 | * Holds the body and the anchor point 70 | */ 71 | @interface BodyDef : NSObject 72 | { 73 | @public 74 | FixtureDef *fixtures; 75 | CGPoint anchorPoint; 76 | } 77 | @end 78 | 79 | 80 | @implementation BodyDef 81 | 82 | -(id) init 83 | { 84 | self = [super init]; 85 | if(self) 86 | { 87 | fixtures = 0; 88 | } 89 | return self; 90 | } 91 | 92 | -(void) dealloc 93 | { 94 | delete fixtures; 95 | [super dealloc]; 96 | } 97 | 98 | @end 99 | 100 | 101 | @implementation GB2ShapeCache 102 | 103 | 104 | + (GB2ShapeCache *)sharedShapeCache 105 | { 106 | static GB2ShapeCache *shapeCache = 0; 107 | if(!shapeCache) 108 | { 109 | shapeCache = [[GB2ShapeCache alloc] init]; 110 | } 111 | return shapeCache; 112 | } 113 | 114 | -(id) init 115 | { 116 | self = [super init]; 117 | if(self) 118 | { 119 | shapeObjects_ = [[NSMutableDictionary alloc] init]; 120 | } 121 | return self; 122 | } 123 | 124 | -(void) dealloc 125 | { 126 | [shapeObjects_ release]; 127 | [super dealloc]; 128 | } 129 | 130 | -(void) addFixturesToBody:(b2Body*)body forShapeName:(NSString*)shape 131 | { 132 | BodyDef *so = [shapeObjects_ objectForKey:shape]; 133 | assert(so); 134 | 135 | FixtureDef *fix = so->fixtures; 136 | while(fix) 137 | { 138 | body->CreateFixture(&fix->fixture); 139 | fix = fix->next; 140 | } 141 | } 142 | 143 | -(CGPoint) anchorPointForShape:(NSString*)shape 144 | { 145 | BodyDef *bd = [shapeObjects_ objectForKey:shape]; 146 | assert(bd); 147 | return bd->anchorPoint; 148 | } 149 | 150 | -(void) addShapesWithFile:(NSString*)plist 151 | { 152 | NSString *path = [[NSBundle mainBundle] pathForResource:plist 153 | ofType:nil 154 | inDirectory:nil]; 155 | 156 | NSDictionary *dictionary = [NSDictionary dictionaryWithContentsOfFile:path]; 157 | 158 | NSDictionary *metadataDict = [dictionary objectForKey:@"metadata"]; 159 | int format = [[metadataDict objectForKey:@"format"] intValue]; 160 | ptmRatio_ = [[metadataDict objectForKey:@"ptm_ratio"] floatValue]; 161 | 162 | NSAssert(format == 1, @"Format not supported"); 163 | 164 | NSDictionary *bodyDict = [dictionary objectForKey:@"bodies"]; 165 | 166 | b2Vec2 vertices[b2_maxPolygonVertices]; 167 | 168 | for(NSString *bodyName in bodyDict) 169 | { 170 | // get the body data 171 | NSDictionary *bodyData = [bodyDict objectForKey:bodyName]; 172 | 173 | // create body object 174 | BodyDef *bodyDef = [[[BodyDef alloc] init] autorelease]; 175 | 176 | bodyDef->anchorPoint = CGPointFromString_([bodyData objectForKey:@"anchorpoint"]); 177 | 178 | // iterate through the fixtures 179 | NSArray *fixtureList = [bodyData objectForKey:@"fixtures"]; 180 | FixtureDef **nextFixtureDef = &(bodyDef->fixtures); 181 | 182 | for(NSDictionary *fixtureData in fixtureList) 183 | { 184 | b2FixtureDef basicData; 185 | 186 | basicData.filter.categoryBits = [[fixtureData objectForKey:@"filter_categoryBits"] intValue]; 187 | basicData.filter.maskBits = [[fixtureData objectForKey:@"filter_maskBits"] intValue]; 188 | basicData.filter.groupIndex = [[fixtureData objectForKey:@"filter_groupIndex"] intValue]; 189 | basicData.friction = [[fixtureData objectForKey:@"friction"] floatValue]; 190 | basicData.density = [[fixtureData objectForKey:@"density"] floatValue]; 191 | basicData.restitution = [[fixtureData objectForKey:@"restitution"] floatValue]; 192 | basicData.isSensor = [[fixtureData objectForKey:@"isSensor"] boolValue]; 193 | int callbackData = [[fixtureData objectForKey:@"userdataCbValue"] intValue]; 194 | 195 | NSString *fixtureType = [fixtureData objectForKey:@"fixture_type"]; 196 | 197 | // read polygon fixtures. One convave fixture may consist of several convex polygons 198 | if([fixtureType isEqual:@"POLYGON"]) 199 | { 200 | NSArray *polygonsArray = [fixtureData objectForKey:@"polygons"]; 201 | 202 | for(NSArray *polygonArray in polygonsArray) 203 | { 204 | FixtureDef *fix = new FixtureDef(); 205 | fix->fixture = basicData; // copy basic data 206 | fix->callbackData = callbackData; 207 | 208 | b2PolygonShape *polyshape = new b2PolygonShape(); 209 | int vindex = 0; 210 | 211 | assert([polygonArray count] <= b2_maxPolygonVertices); 212 | for(NSString *pointString in polygonArray) 213 | { 214 | CGPoint offset = CGPointFromString_(pointString); 215 | vertices[vindex].x = (offset.x / ptmRatio_) ; 216 | vertices[vindex].y = (offset.y / ptmRatio_) ; 217 | vindex++; 218 | } 219 | 220 | polyshape->Set(vertices, vindex); 221 | fix->fixture.shape = polyshape; 222 | 223 | // create a list 224 | *nextFixtureDef = fix; 225 | nextFixtureDef = &(fix->next); 226 | } 227 | } 228 | else if([fixtureType isEqual:@"CIRCLE"]) 229 | { 230 | FixtureDef *fix = new FixtureDef(); 231 | fix->fixture = basicData; // copy basic data 232 | fix->callbackData = callbackData; 233 | 234 | NSDictionary *circleData = [fixtureData objectForKey:@"circle"]; 235 | 236 | b2CircleShape *circleShape = new b2CircleShape(); 237 | circleShape->m_radius = [[circleData objectForKey:@"radius"] floatValue] / ptmRatio_; 238 | CGPoint p = CGPointFromString_([fixtureData objectForKey:@"center"]); 239 | circleShape->m_p = b2Vec2(p.x / ptmRatio_, p.y / ptmRatio_); 240 | fix->fixture.shape = circleShape; 241 | 242 | // create a list 243 | *nextFixtureDef = fix; 244 | nextFixtureDef = &(fix->next); 245 | } 246 | else 247 | { 248 | // unknown type 249 | assert(0); 250 | } 251 | } 252 | 253 | // add the body element to the hash 254 | [shapeObjects_ setObject:bodyDef forKey:bodyName]; 255 | } 256 | } 257 | 258 | -(float) ptmRatio 259 | { 260 | return ptmRatio_; 261 | } 262 | 263 | 264 | @end 265 | 266 | -------------------------------------------------------------------------------- /generic-chipmunk-plist/GCpShapeCache.h: -------------------------------------------------------------------------------- 1 | // 2 | // GCpShapeCache.h 3 | // 4 | // Loads physics sprites created with https://www.codeandweb.com/physicseditor 5 | // 6 | // Generic Shape Cache for Chipmunk 7 | // 8 | // Copyright (c) 2015 CodeAndWeb GmbH. All rights reserved. 9 | // https://www.codeandweb.com 10 | // 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to deal 13 | // in the Software without restriction, including without limitation the rights 14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | // copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | // THE SOFTWARE. 28 | // 29 | 30 | #import 31 | #import "chipmunk.h" 32 | 33 | /** 34 | * Shape cache 35 | * This class holds the shapes and makes them accessible 36 | * The format can be used on any MacOS/iOS system 37 | */ 38 | @interface GCpShapeCache : NSObject 39 | { 40 | NSMutableDictionary *bodyDefs; 41 | } 42 | 43 | + (GCpShapeCache *)sharedShapeCache; 44 | 45 | /** 46 | * Adds shapes to the shape cache 47 | * @param plist name of the plist file to load 48 | * @result FALSE in case of error 49 | */ 50 | -(BOOL) addShapesWithFile:(NSString*)plist; 51 | 52 | /** 53 | * Creates a body with the given name in the given space. 54 | * @param name name of the body 55 | * @param space pointer to the space 56 | * @param data data to set in the body 57 | * @result new created body 58 | */ 59 | -(cpBody*) createBodyWithName:(NSString*)name inSpace:(cpSpace*)space withData:(void*)data; 60 | 61 | /** 62 | * Returns the anchor point of the given sprite 63 | * @param shape name of the shape to get the anchorpoint for 64 | * @return anchorpoint 65 | */ 66 | -(CGPoint) anchorPointForShape:(NSString*)shape; 67 | 68 | @end 69 | -------------------------------------------------------------------------------- /generic-chipmunk-plist/GCpShapeCache.m: -------------------------------------------------------------------------------- 1 | // 2 | // GCpShapeCache.m 3 | // 4 | // Loads physics sprites created with https://www.codeandweb.com/physicseditor 5 | // 6 | // Chipmunk version 7 | // 8 | // Copyright (c) 2015 CodeAndWeb GmbH. All rights reserved. 9 | // https://www.codeandweb.com 10 | // 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to deal 13 | // in the Software without restriction, including without limitation the rights 14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | // copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | // THE SOFTWARE. 28 | // 29 | 30 | #import "GCpShapeCache.h" 31 | 32 | #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) 33 | # define CGPointFromString_ CGPointFromString 34 | #else 35 | // well - not nice but works for now 36 | static CGPoint CGPointFromString_(NSString* str) 37 | { 38 | NSString* theString = str; 39 | theString = [theString stringByReplacingOccurrencesOfString:@"{ " withString:@""]; 40 | theString = [theString stringByReplacingOccurrencesOfString:@" }" withString:@""]; 41 | NSArray *array = [theString componentsSeparatedByString:@","]; 42 | return CGPointMake([[array objectAtIndex:0] floatValue], [[array objectAtIndex:1] floatValue]); 43 | } 44 | #endif 45 | 46 | static cpFloat area(cpVect *vertices, int numVertices) 47 | { 48 | cpFloat area = 0.0f; 49 | 50 | int r = (numVertices-1); 51 | 52 | area += vertices[0].x*vertices[r].y-vertices[r].x*vertices[0].y; 53 | for (int i=0; ianchorPoint; 214 | } 215 | 216 | 217 | -(cpBody*) createBodyWithName:(NSString*)name inSpace:(cpSpace*)space withData:(void*)data 218 | { 219 | GBodyDef *bd = [bodyDefs objectForKey:name]; 220 | NSAssert(bd != 0, @"Body not found"); 221 | if(!bd) 222 | { 223 | return 0; 224 | } 225 | 226 | // create and add body to space 227 | cpBody *body = cpBodyNew(bd->mass, bd->momentum); 228 | 229 | // set the center point 230 | body->p = bd->anchorPoint; 231 | 232 | // set the data 233 | body->data = data; 234 | 235 | // add space to body 236 | cpSpaceAddBody(space, body); 237 | 238 | // iterate over fixtures 239 | for(GFixtureData *fd in bd->fixtures) 240 | { 241 | if(fd->fixtureType == GFIXTURE_CIRCLE) 242 | { 243 | cpShape* shape = cpCircleShapeNew(body, fd->radius, fd->center); 244 | 245 | // set values 246 | shape->e = fd->elasticity; 247 | shape->u = fd->friction; 248 | shape->surface_v = fd->surfaceVelocity; 249 | shape->collision_type = fd->collisionType; 250 | shape->group = fd->group; 251 | shape->layers = fd->layers; 252 | shape->sensor = fd->isSensor; 253 | 254 | // add shape to space 255 | cpSpaceAddShape(space, shape); 256 | } 257 | else 258 | { 259 | // iterate over polygons 260 | for(GPolygon *p in fd->polygons) 261 | { 262 | // create new shape 263 | cpShape* shape = cpPolyShapeNew(body, p->numVertices, p->vertices, CGPointZero); 264 | 265 | // set values 266 | shape->e = fd->elasticity; 267 | shape->u = fd->friction; 268 | shape->surface_v = fd->surfaceVelocity; 269 | shape->collision_type = fd->collisionType; 270 | shape->group = fd->group; 271 | shape->layers = fd->layers; 272 | shape->sensor = fd->isSensor; 273 | 274 | // add shape to space 275 | cpSpaceAddShape(space, shape); 276 | } 277 | } 278 | } 279 | 280 | return body; 281 | } 282 | 283 | 284 | -(BOOL) addShapesWithFile:(NSString*)plist 285 | { 286 | NSString *path = [[NSBundle mainBundle] pathForResource:plist 287 | ofType:nil 288 | inDirectory:nil]; 289 | 290 | NSDictionary *dictionary = [NSDictionary dictionaryWithContentsOfFile:path]; 291 | if(!dictionary) 292 | { 293 | return FALSE; 294 | } 295 | 296 | NSDictionary *metadataDict = [dictionary objectForKey:@"metadata"]; 297 | int format = [[metadataDict objectForKey:@"format"] intValue]; 298 | 299 | NSAssert(format == 1, @"Format not supported"); 300 | if(format != 1) 301 | { 302 | return FALSE; 303 | } 304 | 305 | NSDictionary *bodyDict = [dictionary objectForKey:@"bodies"]; 306 | 307 | for(NSString *bodyName in bodyDict) 308 | { 309 | // get the body data 310 | NSDictionary *bodyData = [bodyDict objectForKey:bodyName]; 311 | 312 | // create body object 313 | GBodyDef *bodyDef = [[[GBodyDef alloc] init] autorelease]; 314 | 315 | // add the body element to the hash 316 | [bodyDefs setObject:bodyDef forKey:bodyName]; 317 | 318 | // set anchor point 319 | bodyDef->anchorPoint = CGPointFromString_([bodyData objectForKey:@"anchorpoint"]); 320 | 321 | // iterate through the fixtures 322 | NSArray *fixtureList = [bodyData objectForKey:@"fixtures"]; 323 | 324 | float totalMass = 0.0f; 325 | cpFloat totalBodyMomentum = 0.0f; 326 | for(NSDictionary *fixtureData in fixtureList) 327 | { 328 | // create fixture 329 | GFixtureData *fd = [[[GFixtureData alloc] init] autorelease]; 330 | if(!fd) 331 | { 332 | return FALSE; 333 | } 334 | 335 | // add the fixture to the body 336 | [bodyDef->fixtures addObject:fd]; 337 | 338 | fd->friction = [[fixtureData objectForKey:@"friction"] floatValue]; 339 | fd->elasticity = [[fixtureData objectForKey:@"elasticity"] floatValue]; 340 | fd->mass = [[fixtureData objectForKey:@"mass"] floatValue]; 341 | fd->surfaceVelocity = CGPointFromString_([fixtureData objectForKey:@"surface_velocity"]); 342 | fd->layers = [[fixtureData objectForKey:@"layers"] intValue]; 343 | fd->group = [[fixtureData objectForKey:@"group"] intValue]; 344 | fd->collisionType = [[fixtureData objectForKey:@"collision_type"] intValue]; 345 | fd->isSensor = [[fixtureData objectForKey:@"fixtureData"] boolValue]; 346 | 347 | NSString *fixtureType = [fixtureData objectForKey:@"fixture_type"]; 348 | 349 | cpFloat totalArea = 0.0f; 350 | 351 | // sum up total mass for the body 352 | totalMass += fd->mass; 353 | 354 | // read polygon fixtures. One convave fixture may consist of several convex polygons 355 | if([fixtureType isEqual:@"POLYGON"]) 356 | { 357 | NSArray *polygonsArray = [fixtureData objectForKey:@"polygons"]; 358 | 359 | fd->fixtureType = GFIXTURE_POLYGON; 360 | 361 | for(NSArray *polygonArray in polygonsArray) 362 | { 363 | GPolygon *poly = [[[GPolygon alloc] init] autorelease]; 364 | if(!poly) 365 | { 366 | return FALSE; 367 | } 368 | 369 | // add the polygon to the fixture 370 | [fd->polygons addObject:poly]; 371 | 372 | // add vertices 373 | poly->numVertices = [polygonArray count]; 374 | cpVect *vertices = poly->vertices = malloc(sizeof(cpVect) * poly->numVertices); 375 | if(!vertices) 376 | { 377 | return FALSE; 378 | } 379 | 380 | int vindex=0; 381 | for(NSString *pointString in polygonArray) 382 | { 383 | CGPoint offset = CGPointFromString_(pointString); 384 | vertices[vindex].x = offset.x ; 385 | vertices[vindex].y = offset.y ; 386 | vindex++; 387 | } 388 | 389 | // calculate area of the polygon (needed to calculate the mass) 390 | poly->area = area(vertices, poly->numVertices); 391 | 392 | // add up all area 393 | totalArea += poly->area; 394 | } 395 | } 396 | else if([fixtureType isEqual:@"CIRCLE"]) 397 | { 398 | fd->fixtureType = GFIXTURE_CIRCLE; 399 | 400 | NSDictionary *circleData = [fixtureData objectForKey:@"circle"]; 401 | 402 | fd->radius = [[circleData objectForKey:@"radius"] floatValue]; 403 | fd->center = CGPointFromString_([fixtureData objectForKey:@"center"]); 404 | totalArea += 3.1415927*fd->radius*fd->radius; 405 | } 406 | else 407 | { 408 | // unknown type 409 | assert(0); 410 | } 411 | 412 | fd->area = totalArea; 413 | 414 | // update sub polygon's masses and momentum 415 | cpFloat totalFixtureMomentum = 0.0f; 416 | 417 | if(totalArea) 418 | { 419 | if(fd->fixtureType == GFIXTURE_CIRCLE) 420 | { 421 | totalFixtureMomentum += cpMomentForCircle(fd->mass, fd->radius, fd->radius, fd->center); 422 | } 423 | else 424 | { 425 | for(GPolygon *p in fd->polygons) 426 | { 427 | // update mass 428 | p->mass = (p->area * fd->mass) / fd->area; 429 | 430 | // calculate momentum 431 | p->momentum = cpMomentForPoly(p->mass, p->numVertices, p->vertices, CGPointZero); 432 | 433 | // calculate total momentum 434 | totalFixtureMomentum += p->momentum; 435 | } 436 | } 437 | } 438 | fd->momentum = totalFixtureMomentum; 439 | totalBodyMomentum = totalFixtureMomentum; 440 | } 441 | 442 | // set bodies total mass 443 | bodyDef->mass = totalMass; 444 | bodyDef->momentum = totalBodyMomentum; 445 | } 446 | 447 | return TRUE; 448 | } 449 | 450 | @end 451 | 452 | -------------------------------------------------------------------------------- /objective-chipmunk-plist/GCpShapeCache.h: -------------------------------------------------------------------------------- 1 | // 2 | // GCpShapeCache.h 3 | // 4 | // Loads physics sprites created with https://www.codeandweb.com/physicseditor 5 | // 6 | // Generic Shape Cache for Chipmunk 7 | // 8 | // Copyright (c) 2015 CodeAndWeb GmbH. All rights reserved. 9 | // https://www.codeandweb.com 10 | // 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to deal 13 | // in the Software without restriction, including without limitation the rights 14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | // copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | // THE SOFTWARE. 28 | // 29 | 30 | #import 31 | #import "ObjectiveChipmunk.h" 32 | 33 | /** 34 | * Shape cache 35 | * This class holds the shapes and makes them accessible 36 | * The format can be used on any MacOS/iOS system 37 | */ 38 | @interface GCpShapeCache : NSObject 39 | { 40 | NSMutableDictionary *bodyDefs; 41 | } 42 | 43 | + (GCpShapeCache *)sharedShapeCache; 44 | 45 | /** 46 | * Adds shapes to the shape cache 47 | * @param plist name of the plist file to load 48 | * @result FALSE in case of error 49 | */ 50 | -(BOOL) addShapesWithFile:(NSString*)plist; 51 | 52 | /** 53 | * Creates a body with the given name in the given space. 54 | * @param name name of the body 55 | * @param space pointer to the space 56 | * @param data data to set in the body and shapes 57 | * @result new created body 58 | */ 59 | -(ChipmunkBody *) createBodyWithName:(NSString*)name inSpace:(NSMutableSet *)space withData:(void*)data; 60 | 61 | /** 62 | * Creates a body with specific collisionType assigned to the 63 | * shapes (eg. [self class] or similar). 64 | * @param name name of the body 65 | * @param space pointer to the space 66 | * @param data data to set in the body 67 | * @param collisionType collisionType to assign to the shapes 68 | * @result new created body 69 | */ 70 | -(ChipmunkBody *) createBodyWithName:(NSString*)name inSpace:(NSMutableSet *)space withData:(void*)data withCollisionType:(id)collisionType; 71 | 72 | /** 73 | * Returns the anchor point of the given sprite 74 | * @param shape name of the shape to get the anchorpoint for 75 | * @return anchorpoint 76 | */ 77 | -(CGPoint) anchorPointForShape:(NSString*)shape; 78 | 79 | @end 80 | -------------------------------------------------------------------------------- /objective-chipmunk-plist/GCpShapeCache.m: -------------------------------------------------------------------------------- 1 | // 2 | // GCpShapeCache.m 3 | // 4 | // Loads physics sprites created with https://www.codeandweb.com/physicseditor 5 | // 6 | // Chipmunk version 7 | // 8 | // Copyright (c) 2015 CodeAndWeb GmbH. All rights reserved. 9 | // https://www.codeandweb.com 10 | // 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to deal 13 | // in the Software without restriction, including without limitation the rights 14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | // copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | // THE SOFTWARE. 28 | // 29 | 30 | #import "GCpShapeCache.h" 31 | 32 | static cpFloat area(cpVect *vertices, int numVertices) 33 | { 34 | cpFloat area = 0.0f; 35 | 36 | int r = (numVertices-1); 37 | 38 | area += vertices[0].x*vertices[r].y-vertices[r].x*vertices[0].y; 39 | for (int i=0; ianchorPoint; 187 | } 188 | 189 | 190 | -(ChipmunkBody *) createBodyWithName:(NSString*)name inSpace:(NSMutableSet *)space withData:(void*)data 191 | { 192 | return [self createBodyWithName:name inSpace:space withData:data withCollisionType:nil]; 193 | } 194 | 195 | -(ChipmunkBody *) createBodyWithName:(NSString*)name inSpace:(NSMutableSet *)space withData:(void*)data withCollisionType:(id)collisionType { 196 | GBodyDef *bd = [bodyDefs objectForKey:name]; 197 | NSAssert(bd != 0, @"Body not found"); 198 | if(!bd) 199 | { 200 | return 0; 201 | } 202 | 203 | // create and add body to space 204 | ChipmunkBody *body = [[ChipmunkBody alloc] initWithMass:bd->mass andMoment:bd->momentum]; 205 | 206 | // set the center point 207 | body.pos = bd->anchorPoint; 208 | 209 | // set the data 210 | body.data = data; 211 | 212 | // add space to body 213 | //cpSpaceAddBody(space, body); 214 | 215 | [space addObject:body]; 216 | 217 | // iterate over fixtures 218 | for(GFixtureData *fd in bd->fixtures) 219 | { 220 | // iterate over polygons 221 | for(GPolygon *p in fd->polygons) 222 | { 223 | // create new shape 224 | ChipmunkShape *shape = [ChipmunkPolyShape polyWithBody:body count:p->numVertices verts:p->vertices offset:CGPointZero]; 225 | 226 | shape.data = data; 227 | shape.elasticity = fd->elasticity; 228 | shape.friction = fd->friction; 229 | shape.surfaceVel = fd->surfaceVelocity; 230 | if (collisionType == nil) { 231 | shape.collisionType = fd->collisionType; 232 | } else { 233 | shape.collisionType = collisionType; 234 | } 235 | shape.group = fd->group; 236 | shape.layers = fd->layers; 237 | shape.sensor = fd->isSensor; 238 | 239 | [space addObject:shape]; 240 | 241 | 242 | // // add shape to space 243 | // cpSpaceAddShape(space, shape); 244 | } 245 | } 246 | 247 | return body; 248 | } 249 | 250 | 251 | -(BOOL) addShapesWithFile:(NSString*)plist 252 | { 253 | NSString *path = [[NSBundle mainBundle] pathForResource:plist 254 | ofType:nil 255 | inDirectory:nil]; 256 | 257 | NSDictionary *dictionary = [NSDictionary dictionaryWithContentsOfFile:path]; 258 | if(!dictionary) 259 | { 260 | return FALSE; 261 | } 262 | 263 | NSDictionary *metadataDict = [dictionary objectForKey:@"metadata"]; 264 | int format = [[metadataDict objectForKey:@"format"] intValue]; 265 | 266 | NSAssert(format == 1, @"Format not supported"); 267 | if(format != 1) 268 | { 269 | return FALSE; 270 | } 271 | 272 | NSDictionary *bodyDict = [dictionary objectForKey:@"bodies"]; 273 | 274 | for(NSString *bodyName in bodyDict) 275 | { 276 | // get the body data 277 | NSDictionary *bodyData = [bodyDict objectForKey:bodyName]; 278 | 279 | // create body object 280 | GBodyDef *bodyDef = [[[GBodyDef alloc] init] autorelease]; 281 | 282 | // add the body element to the hash 283 | [bodyDefs setObject:bodyDef forKey:bodyName]; 284 | 285 | // set anchor point 286 | bodyDef->anchorPoint = CGPointFromString([bodyData objectForKey:@"anchorpoint"]); 287 | 288 | // iterate through the fixtures 289 | NSArray *fixtureList = [bodyData objectForKey:@"fixtures"]; 290 | 291 | float totalMass = 0.0f; 292 | cpFloat totalBodyMomentum = 0.0f; 293 | for(NSDictionary *fixtureData in fixtureList) 294 | { 295 | // create fixture 296 | GFixtureData *fd = [[[GFixtureData alloc] init] autorelease]; 297 | if(!fd) 298 | { 299 | return FALSE; 300 | } 301 | 302 | // add the fixture to the body 303 | [bodyDef->fixtures addObject:fd]; 304 | 305 | fd->friction = [[fixtureData objectForKey:@"friction"] floatValue]; 306 | fd->elasticity = [[fixtureData objectForKey:@"elasticity"] floatValue]; 307 | fd->mass = [[fixtureData objectForKey:@"mass"] floatValue]; 308 | fd->surfaceVelocity = CGPointFromString([fixtureData objectForKey:@"surface_velocity"]); 309 | fd->layers = [[fixtureData objectForKey:@"layers"] intValue]; 310 | fd->group = (cpGroup) [[fixtureData objectForKey:@"group"] intValue]; 311 | fd->collisionType = (cpCollisionType) [[fixtureData objectForKey:@"collision_type"] intValue]; 312 | fd->isSensor = [[fixtureData objectForKey:@"fixtureData"] boolValue]; 313 | 314 | NSString *fixtureType = [fixtureData objectForKey:@"fixture_type"]; 315 | 316 | cpFloat totalArea = 0.0f; 317 | 318 | // sum up total mass for the body 319 | totalMass += fd->mass; 320 | 321 | // read polygon fixtures. One convave fixture may consist of several convex polygons 322 | if([fixtureType isEqual:@"POLYGON"]) 323 | { 324 | NSArray *polygonsArray = [fixtureData objectForKey:@"polygons"]; 325 | 326 | for(NSArray *polygonArray in polygonsArray) 327 | { 328 | GPolygon *poly = [[[GPolygon alloc] init] autorelease]; 329 | if(!poly) 330 | { 331 | return FALSE; 332 | } 333 | 334 | // add the polygon to the fixture 335 | [fd->polygons addObject:poly]; 336 | 337 | // add vertices 338 | poly->numVertices = [polygonArray count]; 339 | cpVect *vertices = poly->vertices = malloc(sizeof(cpVect) * poly->numVertices); 340 | if(!vertices) 341 | { 342 | return FALSE; 343 | } 344 | 345 | int vindex=0; 346 | for(NSString *pointString in polygonArray) 347 | { 348 | CGPoint offset = CGPointFromString(pointString); 349 | vertices[vindex].x = offset.x; 350 | vertices[vindex].y = offset.y; 351 | vindex++; 352 | } 353 | 354 | // calculate area of the polygon (needed to calculate the mass) 355 | poly->area = area(vertices, poly->numVertices); 356 | 357 | // add up all area 358 | totalArea += poly->area; 359 | } 360 | } 361 | else 362 | { 363 | // circles are not yet supported 364 | assert(0); 365 | } 366 | 367 | fd->area = totalArea; 368 | 369 | // update sub polygon's masses and momentum 370 | cpFloat totalFixtureMomentum = 0.0f; 371 | 372 | if(totalArea) 373 | { 374 | for(GPolygon *p in fd->polygons) 375 | { 376 | // update mass 377 | p->mass = (p->area * fd->mass) / fd->area; 378 | 379 | // calculate momentum 380 | p->momentum = cpMomentForPoly(p->mass, p->numVertices, p->vertices, CGPointZero); 381 | 382 | // calculate total momentum 383 | totalFixtureMomentum += p->momentum; 384 | } 385 | } 386 | fd->momentum = totalFixtureMomentum; 387 | totalBodyMomentum = totalFixtureMomentum; 388 | } 389 | 390 | // set bodies total mass 391 | bodyDef->mass = totalMass; 392 | bodyDef->momentum = totalBodyMomentum; 393 | } 394 | 395 | return TRUE; 396 | } 397 | 398 | @end 399 | 400 | --------------------------------------------------------------------------------