static void setUpVerts(cpPolyShape *poly, int numVerts, cpVect *verts, cpVect offset) { // Fail if the user attempts to pass a concave poly, or a bad winding. cpAssertHard(cpPolyValidate(verts, numVerts), "Polygon is concave or has a reversed winding. Consider using cpConvexHull() or CP_CONVEX_HULL()."); poly->numVerts = numVerts; poly->verts = (cpVect *)cpcalloc(2*numVerts, sizeof(cpVect)); poly->planes = (cpSplittingPlane *)cpcalloc(2*numVerts, sizeof(cpSplittingPlane)); poly->tVerts = poly->verts + numVerts; poly->tPlanes = poly->planes + numVerts; for(int i=0; i<numVerts; i++){ cpVect a = cpvadd(offset, verts[i]); cpVect b = cpvadd(offset, verts[(i+1)%numVerts]); cpVect n = cpvnormalize(cpvperp(cpvsub(b, a))); poly->verts[i] = a; poly->planes[i].n = n; poly->planes[i].d = cpvdot(n, a); } }
void ColliderDetector::updateTransform(AffineTransform &t) { if (!m_bActive) { return; } for(auto object : *m_pColliderBodyList) { ColliderBody *colliderBody = (ColliderBody *)object; ContourData *contourData = colliderBody->getContourData(); b2PolygonShape* b2shape = nullptr; if (m_pB2Body != nullptr) { b2shape = (b2PolygonShape *)colliderBody->getB2Fixture()->GetShape(); } cpPolyShape* cpshape = nullptr; if (m_pCPBody != nullptr) { cpshape = (cpPolyShape *)colliderBody->getShape(); } int num = contourData->m_tVertexList.count(); ContourVertex2 **vs = (ContourVertex2 **)contourData->m_tVertexList.data->arr; #if ENABLE_PHYSICS_SAVE_CALCULATED_VERTEX ContourVertex2 **cvs = (ContourVertex2 **)colliderBody->getCalculatedVertexList()->data->arr; #endif for (int i = 0; i < num; i++) { helpPoint.setPoint( vs[i]->x, vs[i]->y); helpPoint = PointApplyAffineTransform(helpPoint, t); #if ENABLE_PHYSICS_SAVE_CALCULATED_VERTEX cvs[i]->x = helpPoint.x; cvs[i]->y = helpPoint.y; #endif if ( b2shape != nullptr ) { b2Vec2 &bv = b2shape->m_vertices[i]; bv.Set(helpPoint.x / PT_RATIO, helpPoint.y / PT_RATIO); } if ( cpshape != nullptr ) { cpVect v ; v.x = helpPoint.x; v.y = helpPoint.y; cpshape->verts[i] = v; } } if ( cpshape != nullptr ) { cpConvexHull(num, cpshape->verts, nullptr, nullptr, 0); for (int i = 0; i < num; i++) { cpVect b = cpshape->verts[(i + 1) % cpshape->numVerts]; cpVect n = cpvnormalize(cpvperp(cpvsub(b, cpshape->verts[i]))); cpshape->planes[i].n = n; cpshape->planes[i].d = cpvdot(n, cpshape->verts[i]); } } } }
cpVect * bmx_cpvect_normalize(cpVect * vec) { return bmx_cpvect_new(cpvnormalize(*vec)); }
void ColliderDetector::updateTransform(Mat4 &t) { if (!_active) { return; } for(auto& object : _colliderBodyList) { ColliderBody *colliderBody = (ColliderBody *)object; ContourData *contourData = colliderBody->getContourData(); #if ENABLE_PHYSICS_BOX2D_DETECT b2PolygonShape *shape = nullptr; if (_body != nullptr) { shape = (b2PolygonShape *)colliderBody->getB2Fixture()->GetShape(); } #elif ENABLE_PHYSICS_CHIPMUNK_DETECT cpPolyShape *shape = nullptr; if (_body != nullptr) { shape = (cpPolyShape *)colliderBody->getShape(); } #endif unsigned long num = contourData->vertexList.size(); std::vector<cocos2d::Vec2> &vs = contourData->vertexList; #if ENABLE_PHYSICS_SAVE_CALCULATED_VERTEX std::vector<cocos2d::Vec2> &cvs = colliderBody->_calculatedVertexList; #endif for (unsigned long i = 0; i < num; i++) { helpPoint.setPoint( vs.at(i).x, vs.at(i).y); helpPoint = PointApplyTransform(helpPoint, t); #if ENABLE_PHYSICS_SAVE_CALCULATED_VERTEX cvs.at(i).x = helpPoint.x; cvs.at(i).y = helpPoint.y; #endif #if ENABLE_PHYSICS_BOX2D_DETECT if (shape != nullptr) { b2Vec2 &bv = shape->m_vertices[i]; bv.Set(helpPoint.x / PT_RATIO, helpPoint.y / PT_RATIO); } #elif ENABLE_PHYSICS_CHIPMUNK_DETECT if (shape != nullptr) { cpVect v ; v.x = helpPoint.x; v.y = helpPoint.y; shape->verts[i] = v; } #endif } #if ENABLE_PHYSICS_CHIPMUNK_DETECT cpConvexHull((int)num, shape->verts, nullptr, nullptr, 0); for (unsigned long i = 0; i < num; i++) { cpVect b = shape->verts[(i + 1) % shape->numVerts]; cpVect n = cpvnormalize(cpvperp(cpvsub(b, shape->verts[i]))); shape->planes[i].n = n; shape->planes[i].d = cpvdot(n, shape->verts[i]); } #endif } }
static inline cpFloat Sharpness(cpVect a, cpVect b, cpVect c) { // TODO could speed this up by caching the normals instead of calculating each twice. return cpvdot(cpvnormalize(cpvsub(a, b)), cpvnormalize(cpvsub(c, b))); }
static void update(void) { int steps, i; cpFloat dt; cpVect look, lastPos, curPos; projectile_t *pj; /* temp for looping */ static cpVect delta = {0, 0}; static projectile_t *curProj = NULL; static bool canToggleEditor = true; curPos = atlMousePos(); lastPos = atlMouseLastPos(); /* rotate 'gun' based on mouse position */ look = cpvnormalize(cpvsub(curPos, g_Cannon->body->p)); cpBodySetAngle(g_Cannon->body, cpvtoangle(look)); if (isKeyPressed(KEY_e) && canToggleEditor) { canToggleEditor = false; editorMode = !editorMode; } else if (!isKeyPressed(KEY_e)) { canToggleEditor = true; } if (editorMode) { if (!editorBody) initializeEditor(); handleEditor(); } else { if (editorBody) destroyEditor(); if (atlLeftMouseDown()) { if (!curProj) { /* don't let player hold the left mouse button to fire multiple rounds */ delta = cpvnormalize(cpvsub(atlMouseClickPos(), g_Cannon->body->p)); if (g_Cannon->ai < MAX_PROJECTILES) { curProj = g_Cannon->ammo[g_Cannon->ai++]; if (curProj) { cpSpaceAddBody(g_Space, curProj->body); curProj->body->p = cpvadd(g_Cannon->body->p, cpvmult(look, g_Cannon->length)); cpSpaceAddShape(g_Space, curProj->shape); cpBodyApplyImpulse(curProj->body, cpvmult(cpvforangle(g_Cannon->body->a), 600.0f), cpvzero); cpBodyActivate(curProj->body); } } } } else { curProj = NULL; } } /* treat projectiles as limited resources. only allocated at the start of a level */ for (i = 0; i <= g_Cannon->ai-1; ++i) { pj = g_Cannon->ammo[i]; if (!pj) continue; if (pj->body->v.x >= -0.01f && pj->body->v.x <= 0.01f && pj->body->v.y >= -0.01f && pj->body->v.y <= 0.01f) { /* TODO: mark an object for deletion, but don't delete immediately */ cpSpaceRemoveBody(g_Space, pj->body); cpSpaceRemoveShape(g_Space, pj->shape); free(g_Cannon->ammo[i]); g_Cannon->ammo[i] = NULL; } } steps = 3; dt = 1.0f/60.0f/(cpFloat)steps; for (i = 0; i < steps; ++i) { cpSpaceStep(g_Space, dt); } }
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; }