Example #1
0
        public bool StickyPreSolve(cpArbiter arb, object 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.
            float deepest = cp.Infinity;

            // Grab the contact set and iterate over them.
            cpContactPointSet contacts = arb.GetContactPointSet();

            for (int i = 0; i < contacts.count; i++)
            {
                // Sink the contact points into the surface of each shape.
                contacts.points[i].pointA = cpVect.cpvsub(contacts.points[i].pointA, cpVect.cpvmult(contacts.normal, STICK_SENSOR_THICKNESS));
                contacts.points[i].pointB = cpVect.cpvadd(contacts.points[i].pointB, cpVect.cpvmult(contacts.normal, STICK_SENSOR_THICKNESS));
                deepest = cp.cpfmin(deepest, contacts.points[i].distance);                // + 2.0f*STICK_SENSOR_THICKNESS);
            }

            // Set the new contact point data.
            arb.SetContactPointSet(ref contacts);

            // If the shapes are overlapping enough, then create a
            // joint that sticks them together at the first contact point.
            if (arb.GetUserData() == null && deepest <= 0.0f)
            {
                cpBody bodyA, bodyB;
                arb.GetBodies(out bodyA, out bodyB);

                // Create a joint at the contact point to hold the body in place.
                cpVect anchorA = bodyA.WorldToLocal(contacts.points[0].pointA);
                cpVect anchorB = bodyB.WorldToLocal(contacts.points[0].pointB);

                cpConstraint joint = new cpPivotJoint(bodyA, bodyB, anchorA, anchorB);

                // Give it a finite force for the stickyness.
                joint.SetMaxForce(3e3f);


                // Schedule a post-step() callback to add the joint.
                space.AddPostStepCallback(
                    (s, o1, o2) => PostStepAddJoint(joint, null),
                    joint, null);

                // Store the joint on the arbiter so we can remove it later.
                arb.SetUserData(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).
        }
Example #2
0
        public void StickySeparate(cpArbiter arb, object data)
        {
            cpConstraint joint = (cpConstraint)arb.GetUserData();

            if (joint != null)
            {
                // The joint won't be removed until the step is done.
                // Need to disable it so that it won't apply itself.
                // Setting the force to 0 will do just that

                joint.SetMaxForce(0.0f);

                space.AddPostStepCallback((s1, o1, o2) =>
                                          PostStepRemoveJoint(o1, o2), joint, null

                                          );
                // Perform the removal in a post-step() callback.

                // NULL out the reference to the joint.
                // Not required, but it's a good practice.
                arb.SetUserData(null);
            }
        }