bool DropCapsid::onContactAstroObj(ContactInfo& cinfo) { if (cinfo.contact.getEventCode() == PhysicsContact::EventCode::POSTSOLVE) { if (cpArbiter* arb = static_cast<cpArbiter*>(cinfo.contact.getContactInfo())) { cpContactPointSet cps = cpArbiterGetContactPointSet(arb); bool moving = false; for (int i = 0; i < cps.count; ++i) { cpVect va = cpBodyGetVelocityAtWorldPoint(arb->body_a, cps.points[i].pointA); cpVect vb = cpBodyGetVelocityAtWorldPoint(arb->body_b, cps.points[i].pointB); cpVect rv = cpvsub(va, vb); cpFloat wa = cpBodyGetAngularVelocity(arb->body_a); cpFloat wb = cpBodyGetAngularVelocity(arb->body_b); cpFloat rw = wa - wb; //if (cpvlengthsq(rv) > 1e-6 || fabs(rw) > 0.5) { if (cpvlengthsq(rv) > 1.0 || fabs(rw) > 5) { moving = true; break; } } if (!moving) { Unit* created = onLandCreate(_game); Player* player = _player; replaceWith(created); // this is destroyed float up = (cinfo.thisBody->getPosition() - cinfo.thatBody->getPosition()).getAngle() / (M_PI / 180.0); created->getNode()->getPhysicsBody()->setRotation(90 - up); created->setPlayer(player); // CCLOG("LANDING up# %f", up); return true; } } } return true; }
/* * @return [Chipmunk2d::ContactPointSet] */ static mrb_value arbiter_get_contact_point_set(mrb_state* mrb, mrb_value self) { cpArbiter* arbiter; cpContactPointSet contact_point_set; arbiter = mrb_cp_get_arbiter_ptr(mrb, self); contact_point_set = cpArbiterGetContactPointSet(arbiter); return mrb_cp_contact_point_set_value(mrb, &contact_point_set); }
static cpBool StickyPreSolve(cpArbiter *arb, cpSpace *space, void *data) { // We want to fudge the collisions a bit to allow shapes to overlap more. // This simulates their squishy sticky surface, and more importantly // keeps them from separating and destroying the joint. // Track the deepest collision point and use that to determine if a rigid collision should occur. cpFloat deepest = INFINITY; // Grab the contact set and iterate over them. cpContactPointSet contacts = cpArbiterGetContactPointSet(arb); for(int i=0; i<contacts.count; i++){ // Increase the distance (negative means overlaping) of the // collision to allow them to overlap more. // This value is used only for fixing the positions of overlapping shapes. cpFloat dist = contacts.points[i].dist + 2.0f*STICK_SENSOR_THICKNESS; contacts.points[i].dist = cpfmin(0.0f, dist); deepest = cpfmin(deepest, dist); } // Set the new contact point data. cpArbiterSetContactPointSet(arb, &contacts); // If the shapes are overlapping enough, then create a // joint that sticks them together at the first contact point. if(!cpArbiterGetUserData(arb) && deepest <= 0.0f){ CP_ARBITER_GET_BODIES(arb, bodyA, bodyB); // Create a joint at the contact point to hold the body in place. cpConstraint *joint = cpPivotJointNew(bodyA, bodyB, contacts.points[0].point); // Give it a finite force for the stickyness. cpConstraintSetMaxForce(joint, 3e3); // Schedule a post-step() callback to add the joint. cpSpaceAddPostStepCallback(space, PostStepAddJoint, joint, NULL); // Store the joint on the arbiter so we can remove it later. cpArbiterSetUserData(arb, joint); } // Position correction and velocity are handled separately so changing // the overlap distance alone won't prevent the collision from occuring. // Explicitly the collision for this frame if the shapes don't overlap using the new distance. return (deepest <= 0.0f); // Lots more that you could improve upon here as well: // * Modify the joint over time to make it plastic. // * Modify the joint in the post-step to make it conditionally plastic (like clay). // * Track a joint for the deepest contact point instead of the first. // * Track a joint for each contact point. (more complicated since you only get one data pointer). }
static World_CollisionInfo _collisionInfoForArbiter(cpArbiter *aArbiter) { cpBody *bodyA, *bodyB; cpArbiterGetBodies(aArbiter, &bodyA, &bodyB); WorldEntity_t *a = bodyA->data; dynamo_assert(a != NULL, "Incomplete collision"); WorldEntity_t *b = bodyB->data; dynamo_assert(b != NULL, "Incomplete collision"); cpContactPointSet cpPointSet = cpArbiterGetContactPointSet(aArbiter); World_ContactPointSet pointSet = *(World_ContactPointSet *)&cpPointSet; return (World_CollisionInfo) { a, b, cpArbiterIsFirstContact(aArbiter), pointSet, aArbiter }; }
cpContactPointSet cArbiter::ContactPointSet() { return cpArbiterGetContactPointSet( mArbiter ); }