static inline void mergeBodies(cpSpace *space, cpArray *components, cpArray *rogueBodies, cpBody *a, cpBody *b) { // Ignore connections to static bodies if(cpBodyIsStatic(a) || cpBodyIsStatic(b)) return; cpBody *a_root = componentNodeRoot(a); cpBody *b_root = componentNodeRoot(b); cpBool a_sleep = cpBodyIsSleeping(a_root); cpBool b_sleep = cpBodyIsSleeping(b_root); if(a_sleep && b_sleep){ return; } else if(a_sleep || b_sleep){ componentActivate(a_root); componentActivate(b_root); } // Add any rogue bodies found to the list and reset the idle time of anything they touch. if(cpBodyIsRogue(a)){ cpArrayPush(rogueBodies, a); b->node.idleTime = 0.0f; } if(cpBodyIsRogue(b)){ cpArrayPush(rogueBodies, b); a->node.idleTime = 0.0f; } componentNodeMerge(a_root, b_root); }
NS_CC_EXT_BEGIN #if CC_ENABLE_CHIPMUNK_INTEGRATION /* IMPORTANT - READ ME! This file sets pokes around in the private API a lot to provide efficient debug rendering given nothing more than reference to a Chipmunk space. It is not recommended to write rendering code like this in your own games as the private API may change with little or no warning. */ static Color4F ColorForBody(cpBody *body) { if (cpBodyIsRogue(body) || cpBodyIsSleeping(body)) { return Color4F(0.5f, 0.5f, 0.5f ,0.5f); } else if (body->CP_PRIVATE(node).idleTime > body->CP_PRIVATE(space)->sleepTimeThreshold) { return Color4F(0.33f, 0.33f, 0.33f, 0.5f); } else { return Color4F(1.0f, 0.0f, 0.0f, 0.5f); } }
void cpBodySleepWithGroup(cpBody *body, cpBody *group){ cpAssert(!cpBodyIsStatic(body) && !cpBodyIsRogue(body), "Rogue and static bodies cannot be put to sleep."); cpSpace *space = body->space; cpAssert(space, "Cannot put a body to sleep that has not been added to a space."); cpAssert(!space->locked, "Bodies can not be put to sleep during a query or a call to cpSpaceSte(). Put these calls into a post-step callback."); cpAssert(!group || cpBodyIsSleeping(group), "Cannot use a non-sleeping body as a group identifier."); if(cpBodyIsSleeping(body)) return; for(cpShape *shape = body->shapesList; shape; shape = shape->next){ cpShapeCacheBB(shape); cpSpaceHashRemove(space->activeShapes, shape, shape->hashid); cpSpaceHashInsert(space->staticShapes, shape, shape->hashid, shape->bb); } if(group){ cpBody *root = componentNodeRoot(group); cpComponentNode node = {root, root->node.next, 0, 0.0f}; body->node = node; root->node.next = body; } else { cpComponentNode node = {NULL, body, 0, 0.0f}; body->node = node; cpArrayPush(space->sleepingComponents, body); } cpArrayDeleteObj(space->bodies, body); }
NS_CC_EXT_BEGIN /* IMPORTANT - READ ME! This file sets pokes around in the private API a lot to provide efficient debug rendering given nothing more than reference to a Chipmunk space. It is not recommended to write rendering code like this in your own games as the private API may change with little or no warning. */ // 此文件采用了很多私有的API,用于调试中渲染物理空间。 不推荐这么做,私有api最不愿改动 static ccColor4F ColorForBody(cpBody *body) { if (cpBodyIsRogue(body) || cpBodyIsSleeping(body)) { return ccc4f(0.5f, 0.5f, 0.5f ,0.5f); } else if (body->CP_PRIVATE(node).idleTime > body->CP_PRIVATE(space)->sleepTimeThreshold) { return ccc4f(0.33f, 0.33f, 0.33f, 0.5f); } else { return ccc4f(1.0f, 0.0f, 0.0f, 0.5f); } }
void cpBodyActivate(cpBody *body) { if(!cpBodyIsRogue(body)){ body->node.idleTime = 0.0f; componentActivate(componentNodeRoot(body)); } }
static inline cpBool componentActive(cpBody *root, cpFloat threshold) { cpBody *body = root, *next; do { next = body->node.next; if(cpBodyIsRogue(body) || body->node.idleTime < threshold) return cpTrue; } while((body = next) != root); return cpFalse; }
cpShape * cpSpaceAddStaticShape(cpSpace *space, cpShape *shape) { cpAssertHard(shape->space != space, "You have already added this shape to this space. You must not add it a second time."); cpAssertHard(!shape->space, "You have already added this shape to another space. You cannot add it to a second."); cpAssertHard(cpBodyIsRogue(shape->body), "You are adding a static shape to a dynamic body. Did you mean to attach it to a static or rogue body? See the documentation for more information."); cpAssertSpaceUnlocked(space); cpBody *body = shape->body; cpBodyAddShape(body, shape); cpShapeUpdate(shape, body->p, body->rot); cpSpatialIndexInsert(space->staticShapes, shape, shape->hashid); shape->space = space; return shape; }
void cpSpaceActivateBody(cpSpace *space, cpBody *body) { cpAssertHard(!cpBodyIsRogue(body), "Internal error: Attempting to activate a rogue body."); if(space->locked){ // cpSpaceActivateBody() is called again once the space is unlocked if(!cpArrayContains(space->rousedBodies, body)) cpArrayPush(space->rousedBodies, body); } else { cpAssertSoft(body->node.root == NULL && body->node.next == NULL, "Internal error: Activating body non-NULL node pointers."); cpArrayPush(space->bodies, body); CP_BODY_FOREACH_SHAPE(body, shape){ cpSpatialIndexRemove(space->staticShapes, shape, shape->hashid); cpSpatialIndexInsert(space->activeShapes, shape, shape->hashid); } CP_BODY_FOREACH_ARBITER(body, arb){ cpBody *bodyA = arb->body_a; // Arbiters are shared between two bodies that are always woken up together. // You only want to restore the arbiter once, so bodyA is arbitrarily chosen to own the arbiter. // The edge case is when static bodies are involved as the static bodies never actually sleep. // If the static body is bodyB then all is good. If the static body is bodyA, that can easily be checked. if(body == bodyA || cpBodyIsStatic(bodyA)){ int numContacts = arb->numContacts; cpContact *contacts = arb->contacts; // Restore contact values back to the space's contact buffer memory arb->contacts = cpContactBufferGetArray(space); memcpy(arb->contacts, contacts, numContacts*sizeof(cpContact)); cpSpacePushContacts(space, numContacts); // Reinsert the arbiter into the arbiter cache cpShape *a = arb->a, *b = arb->b; cpShape *shape_pair[] = {a, b}; cpHashValue arbHashID = CP_HASH_PAIR((cpHashValue)a, (cpHashValue)b); cpHashSetInsert(space->cachedArbiters, arbHashID, shape_pair, arb, NULL); // Update the arbiter's state arb->stamp = space->stamp; arb->handler = cpSpaceLookupHandler(space, a->collision_type, b->collision_type); cpArrayPush(space->arbiters, arb); cpfree(contacts); } }
static cpBody * rb_cpBodySleepValidate(VALUE vbody) { cpBody * body = BODY(vbody); cpSpace *space = body->CP_PRIVATE(space); if(!space) { rb_raise(rb_eArgError, "Cannot put a body to sleep that has not been added to a space."); return NULL; } if (cpBodyIsStatic(body) && cpBodyIsRogue(body)) { rb_raise(rb_eArgError, "Rogue AND static bodies cannot be put to sleep."); return NULL; } if(cpSpaceIsLocked(space)) { rb_raise(rb_eArgError, "Bodies can not be put to sleep during a query or a call to Space#add_collision_func. Put these calls into a post-step callback using Space#add_collision_handler."); return NULL; } return body; }
void cpSpaceConvertBodyToStatic(cpSpace *space, cpBody *body) { cpAssertHard(!cpBodyIsStatic(body), "Body is already static."); cpAssertHard(cpBodyIsRogue(body), "Remove the body from the space before calling this function."); cpAssertSpaceUnlocked(space); cpBodySetMass(body, INFINITY); cpBodySetMoment(body, INFINITY); cpBodySetVel(body, cpvzero); cpBodySetAngVel(body, 0.0f); body->node.idleTime = INFINITY; CP_BODY_FOREACH_SHAPE(body, shape){ cpSpatialIndexRemove(space->activeShapes, shape, shape->hashid); cpSpatialIndexInsert(space->staticShapes, shape, shape->hashid); }
void cpSpaceActivateBody(cpSpace *space, cpBody *body) { cpAssertHard(!cpBodyIsRogue(body), "Internal error: Attempting to activate a rouge body."); if(space->locked){ // cpSpaceActivateBody() is called again once the space is unlocked if(!cpArrayContains(space->rousedBodies, body)) cpArrayPush(space->rousedBodies, body); } else { cpArrayPush(space->bodies, body); CP_BODY_FOREACH_SHAPE(body, shape){ cpSpatialIndexRemove(space->staticShapes, shape, shape->hashid); cpSpatialIndexInsert(space->activeShapes, shape, shape->hashid); } CP_BODY_FOREACH_ARBITER(body, arb){ cpBody *bodyA = arb->body_a; if(body == bodyA || cpBodyIsStatic(bodyA)){ int numContacts = arb->numContacts; cpContact *contacts = arb->contacts; // Restore contact values back to the space's contact buffer memory arb->contacts = cpContactBufferGetArray(space); memcpy(arb->contacts, contacts, numContacts*sizeof(cpContact)); cpSpacePushContacts(space, numContacts); // Reinsert the arbiter into the arbiter cache cpShape *a = arb->a, *b = arb->b; cpShape *shape_pair[] = {a, b}; cpHashValue arbHashID = CP_HASH_PAIR((cpHashValue)a, (cpHashValue)b); cpHashSetInsert(space->cachedArbiters, arbHashID, shape_pair, arb, NULL); // Update the arbiter's state arb->stamp = space->stamp; arb->handler = cpSpaceLookupHandler(space, a->collision_type, b->collision_type); cpArrayPush(space->arbiters, arb); cpfree(contacts); } }
bool cBody::IsRogue() { return cpFalse != cpBodyIsRogue( mBody ); }
// TODO this function needs more commenting. void cpSpaceProcessComponents(cpSpace *space, cpFloat dt) { cpArray *bodies = space->bodies; cpArray *newBodies = cpArrayNew(bodies->num); cpArray *rogueBodies = cpArrayNew(16); cpArray *arbiters = space->arbiters; cpArray *constraints = space->constraints; cpArray *components = cpArrayNew(space->sleepingComponents->num); cpFloat dv = space->idleSpeedThreshold; cpFloat dvsq = (dv ? dv*dv : cpvdot(space->gravity, space->gravity)*dt*dt); // update idling for(int i=0; i<bodies->num; i++){ cpBody *body = (cpBody*)bodies->arr[i]; cpFloat thresh = (dvsq ? body->m*dvsq : 0.0f); body->node.idleTime = (cpBodyKineticEnergy(body) > thresh ? 0.0f : body->node.idleTime + dt); } // iterate graph edges and build forests for(int i=0; i<arbiters->num; i++){ cpArbiter *arb = (cpArbiter*)arbiters->arr[i]; mergeBodies(space, components, rogueBodies, arb->a->body, arb->b->body); } for(int j=0; j<constraints->num; j++){ cpConstraint *constraint = (cpConstraint *)constraints->arr[j]; mergeBodies(space, components, rogueBodies, constraint->a, constraint->b); } // iterate bodies and add them to their components for(int i=0; i<bodies->num; i++) addToComponent((cpBody*)bodies->arr[i], components); for(int i=0; i<rogueBodies->num; i++) addToComponent((cpBody*)rogueBodies->arr[i], components); // iterate components, copy or deactivate for(int i=0; i<components->num; i++){ cpBody *root = (cpBody*)components->arr[i]; if(componentActive(root, space->sleepTimeThreshold)){ cpBody *body = root, *next; do { next = body->node.next; if(!cpBodyIsRogue(body)) cpArrayPush(newBodies, body); cpComponentNode node = {NULL, NULL, 0, body->node.idleTime}; body->node = node; } while((body = next) != root); } else { cpBody *body = root, *next; do { next = body->node.next; for(cpShape *shape = body->shapesList; shape; shape = shape->next){ cpSpaceHashRemove(space->activeShapes, shape, shape->hashid); cpSpaceHashInsert(space->staticShapes, shape, shape->hashid, shape->bb); } } while((body = next) != root); cpArrayPush(space->sleepingComponents, root); } } space->bodies = newBodies; cpArrayFree(bodies); cpArrayFree(rogueBodies); cpArrayFree(components); }
static VALUE rb_cpBodyIsRogue(VALUE self) { return cpBodyIsRogue(BODY(self)) ? Qtrue : Qfalse; }
cpBool Body::isRogue() { return cpBodyIsRogue(body); }