void PhysicsShapePolygon::updateScale() { cpFloat factorX = _newScaleX / _scaleX; cpFloat factorY = _newScaleY / _scaleY; auto shape = _cpShapes.front(); int count = cpPolyShapeGetCount(shape); cpVect* vects = new cpVect[count]; for(int i=0;i<count;++i) vects[i] = cpPolyShapeGetVert(shape, i); for (int i = 0; i < count; ++i) { vects[i].x *= factorX; vects[i].y *= factorY; } // convert hole to clockwise if (factorX * factorY < 0) { for (int i = 0; i < count / 2; ++i) { cpVect v = vects[i]; vects[i] = vects[count - i - 1]; vects[count - i - 1] = v; } } cpPolyShapeSetVertsRaw(shape, count, vects); CC_SAFE_DELETE_ARRAY(vects); PhysicsShape::updateScale(); }
void PhysicsShapePolygon::getPoints(Vec2* outPoints) const { auto shape = _cpShapes.front(); int count = cpPolyShapeGetCount(shape); cpVect* vecs = new cpVect[count]; for(int i=0;i<count;++i) vecs[i] = cpPolyShapeGetVert(shape, i); PhysicsHelper::cpvs2points(vecs, outPoints, count); CC_SAFE_DELETE_ARRAY(vecs); }
cpVect cpPolyShapeGetVert(const cpShape *shape, int i) { cpAssertHard(shape->klass == &polyClass, "Shape is not a poly shape."); int count = cpPolyShapeGetCount(shape); cpAssertHard(0 <= i && i < count, "Index out of range."); return ((cpPolyShape *)shape)->planes[i + count].v0; }
float PhysicsShapePolygon::calculateArea() { auto shape = _cpShapes.front(); int count = cpPolyShapeGetCount(shape); cpVect* vecs = new cpVect[count]; for(int i=0;i<count;++i) vecs[i] = cpPolyShapeGetVert(shape, i); float area = PhysicsHelper::cpfloat2float(cpAreaForPoly(count, vecs, cpPolyShapeGetRadius(shape))); CC_SAFE_DELETE_ARRAY(vecs); return area; }
Vec2 PhysicsShapePolygon::getCenter() { auto shape = _cpShapes.front(); int count = cpPolyShapeGetCount(shape); cpVect* vecs = new cpVect[count]; for(int i=0;i<count;++i) vecs[i] = cpPolyShapeGetVert(shape, i); Vec2 center = PhysicsHelper::cpv2point(cpCentroidForPoly(count, vecs)); CC_SAFE_DELETE_ARRAY(vecs); return center; }
float PhysicsShapePolygon::calculateDefaultMoment() { if(_mass == PHYSICS_INFINITY) { return PHYSICS_INFINITY; } else { auto shape = _cpShapes.front(); int count = cpPolyShapeGetCount(shape); cpVect* vecs = new cpVect[count]; for(int i=0;i<count;++i) vecs[i] = cpPolyShapeGetVert(shape, i); float moment = PhysicsHelper::cpfloat2float(cpMomentForPoly(_mass, count, vecs, cpvzero, cpPolyShapeGetRadius(shape))); CC_SAFE_DELETE_ARRAY(vecs); return moment; } }
void Slice::ClipPoly(cpSpace *space, cpShape *shape, cpVect n, cpFloat dist) { cpBody *body = cpShapeGetBody(shape); int count = cpPolyShapeGetCount(shape); int clippedCount = 0; cpVect *clipped = (cpVect *)alloca((count + 1)*sizeof(cpVect)); for(int i=0, j=count-1; i<count; j=i, i++){ cpVect a = cpBodyLocalToWorld(body, cpPolyShapeGetVert(shape, j)); cpFloat a_dist = cpvdot(a, n) - dist; if(a_dist < 0.0){ clipped[clippedCount] = a; clippedCount++; } cpVect b = cpBodyLocalToWorld(body, cpPolyShapeGetVert(shape, i)); cpFloat b_dist = cpvdot(b, n) - dist; if(a_dist*b_dist < 0.0f){ cpFloat t = cpfabs(a_dist)/(cpfabs(a_dist) + cpfabs(b_dist)); clipped[clippedCount] = cpvlerp(a, b, t); clippedCount++; } } cpVect centroid = cpCentroidForPoly(clippedCount, clipped); cpFloat mass = cpAreaForPoly(clippedCount, clipped, 0.0f)*DENSITY; cpFloat moment = cpMomentForPoly(mass, clippedCount, clipped, cpvneg(centroid), 0.0f); cpBody *new_body = cpSpaceAddBody(space, cpBodyNew(mass, moment)); cpBodySetPosition(new_body, centroid); cpBodySetVelocity(new_body, cpBodyGetVelocityAtWorldPoint(body, centroid)); cpBodySetAngularVelocity(new_body, cpBodyGetAngularVelocity(body)); cpTransform transform = cpTransformTranslate(cpvneg(centroid)); cpShape *new_shape = cpSpaceAddShape(space, cpPolyShapeNew(new_body, clippedCount, clipped, transform, 0.0)); // Copy whatever properties you have set on the original shape that are important cpShapeSetFriction(new_shape, cpShapeGetFriction(shape)); }
int PhysicsShapePolygon::getPointsCount() const { return cpPolyShapeGetCount(_cpShapes.front()); }
cpBool Buoyancy::WaterPreSolve(cpArbiter *arb, cpSpace *space, void *ptr) { CP_ARBITER_GET_SHAPES(arb, water, poly); cpBody *body = cpShapeGetBody(poly); // Get the top of the water sensor bounding box to use as the water level. cpFloat level = cpShapeGetBB(water).t; // Clip the polygon against the water level int count = cpPolyShapeGetCount(poly); int clippedCount = 0; #ifdef _MSC_VER // MSVC is pretty much the only compiler in existence that doesn't support variable sized arrays. cpVect clipped[10]; #else cpVect clipped[count + 1]; #endif for(int i=0, j=count-1; i<count; j=i, i++){ cpVect a = cpBodyLocalToWorld(body, cpPolyShapeGetVert(poly, j)); cpVect b = cpBodyLocalToWorld(body, cpPolyShapeGetVert(poly, i)); if(a.y < level){ clipped[clippedCount] = a; clippedCount++; } cpFloat a_level = a.y - level; cpFloat b_level = b.y - level; if(a_level*b_level < 0.0f){ cpFloat t = cpfabs(a_level)/(cpfabs(a_level) + cpfabs(b_level)); clipped[clippedCount] = cpvlerp(a, b, t); clippedCount++; } } // Calculate buoyancy from the clipped polygon area cpFloat clippedArea = cpAreaForPoly(clippedCount, clipped, 0.0f); cpFloat displacedMass = clippedArea*FLUID_DENSITY; cpVect centroid = cpCentroidForPoly(clippedCount, clipped); cpDataPointer data = ptr; DrawPolygon(clippedCount, clipped, 0.0f, RGBAColor(0, 0, 1, 1), RGBAColor(0, 0, 1, 0.1f), data); DrawDot(5, centroid, RGBAColor(0, 0, 1, 1), data); cpFloat dt = cpSpaceGetCurrentTimeStep(space); cpVect g = cpSpaceGetGravity(space); // Apply the buoyancy force as an impulse. cpBodyApplyImpulseAtWorldPoint(body, cpvmult(g, -displacedMass*dt), centroid); // Apply linear damping for the fluid drag. cpVect v_centroid = cpBodyGetVelocityAtWorldPoint(body, centroid); cpFloat k = k_scalar_body(body, centroid, cpvnormalize(v_centroid)); cpFloat damping = clippedArea*FLUID_DRAG*FLUID_DENSITY; cpFloat v_coef = cpfexp(-damping*dt*k); // linear drag // cpFloat v_coef = 1.0/(1.0 + damping*dt*cpvlength(v_centroid)*k); // quadratic drag cpBodyApplyImpulseAtWorldPoint(body, cpvmult(cpvsub(cpvmult(v_centroid, v_coef), v_centroid), 1.0/k), centroid); // Apply angular damping for the fluid drag. cpVect cog = cpBodyLocalToWorld(body, cpBodyGetCenterOfGravity(body)); cpFloat w_damping = cpMomentForPoly(FLUID_DRAG*FLUID_DENSITY*clippedArea, clippedCount, clipped, cpvneg(cog), 0.0f); cpBodySetAngularVelocity(body, cpBodyGetAngularVelocity(body)*cpfexp(-w_damping*dt/cpBodyGetMoment(body))); return cpTrue; }