public cpCollisionHandler LookupHandler(ulong a, ulong b, cpCollisionHandler defaultValue) { cpCollisionHandler test; if (collisionHandlers.TryGetValue(cp.CP_HASH_PAIR(a, b), out test)) { return(test); } else { return(defaultValue); } }
public cpCollisionHandler AddCollisionHandler(ulong a, ulong b) { ulong hash = cp.CP_HASH_PAIR(a, b); var handlers = this.collisionHandlers; cpCollisionHandler handler; if (!handlers.TryGetValue(hash, out handler)) { handler = new cpCollisionHandler(a, b, DefaultBegin, DefaultPreSolve, DefaultPostSolve, DefaultSeparate, null); handlers.Add(hash, handler); } return(handler); }
public cpCollisionHandler Clone() { cpCollisionHandler copy = new cpCollisionHandler(); copy.typeA = typeA; copy.typeB = typeB; copy.beginFunc = beginFunc; copy.preSolveFunc = preSolveFunc; copy.postSolveFunc = postSolveFunc; copy.separateFunc = separateFunc; copy.userData = userData; return(copy); }
public cpCollisionHandler AddWildcardHandler(ulong type) { UseWildcardDefaultHandler(); ulong hash = cp.CP_HASH_PAIR(type, cp.WILDCARD_COLLISION_TYPE); var handlers = this.collisionHandlers; cpCollisionHandler handler; if (!handlers.TryGetValue(hash, out handler)) { handler = new cpCollisionHandler(type, cp.WILDCARD_COLLISION_TYPE, cpCollisionHandler.AlwaysCollide, cpCollisionHandler.AlwaysCollide, cpCollisionHandler.DoNothing, cpCollisionHandler.DoNothing, null); handlers.Add(hash, handler); } return(handler); }
public ulong CollideShapes(cpShape a, cpShape b, ulong id) { // It would be nicer to use .bind() or something, but this is faster. //return new Action<object, object>((obj1, obj2) => //{// Reject any of the simple cases if (QueryReject(a, b)) { return(id); } //contactsBuffer.Clear(); List <cpContact> contacts = new List <cpContact>(); // Narrow-phase collision detection. //int numContacts = cpCollideShapes(a, b, contacts); cpCollisionInfo info = cpCollision.cpCollide(a, b, id, ref contacts); if (info.count == 0) { return(info.id); // Shapes are not colliding. } // Get an arbiter from space.arbiterSet for the two shapes. // This is where the persistant contact magic comes from. var arbHash = cp.CP_HASH_PAIR(info.a.hashid, info.b.hashid); cpArbiter arb; if (!cachedArbiters.TryGetValue(arbHash, out arb)) { arb = new cpArbiter(a, b); cachedArbiters.Add(arbHash, arb); } arb.Update(info, this); cpCollisionHandler handler = arb.handler; //LookupHandler(a.type, b.type, defaultHandler); // Call the begin function first if it's the first step if (arb.state == cpArbiterState.FirstCollision && !handler.beginFunc(arb, this, null)) { arb.Ignore(); // permanently ignore the collision until separation } if ( // Ignore the arbiter if it has been flagged (arb.state != cpArbiterState.Ignore) && // Call preSolve handler.preSolveFunc(arb, this, handler.userData) && !(a.sensor || b.sensor) && // Process, but don't add collisions for sensors. !(a.body.m == cp.Infinity && b.body.m == cp.Infinity) ) { this.arbiters.Add(arb); } else { //cpSpacePopContacts(space, numContacts); arb.contacts.Clear(); // Normally arbiters are set as used after calling the post-solve callback. // However, post-solve callbacks are not called for sensors or arbiters rejected from pre-solve. if (arb.state != cpArbiterState.Ignore) { arb.state = cpArbiterState.Normal; } } // Time stamp the arbiter so we know it was used recently. arb.stamp = this.stamp; // }); return(info.id); }
public void Update(cpCollisionInfo info, cpSpace space) { cpShape a = info.a, b = info.b; // For collisions between two similar primitive types, the order could have been swapped since the last frame. this.a = a; this.body_a = a.body; this.b = b; this.body_b = b.body; // Iterate over the possible pairs to look for hash value matches. for (int i = 0; i < info.count; i++) { cpContact con = info.arr[i]; // r1 and r2 store absolute offsets at init time. // Need to convert them to relative offsets. con.r1 = cpVect.cpvsub(con.r1, a.body.p); con.r2 = cpVect.cpvsub(con.r2, b.body.p); // Cached impulses are not zeroed at init time. con.jnAcc = con.jtAcc = 0.0f; for (int j = 0; j < this.Count; j++) { cpContact old = this.contacts[j]; // This could trigger false positives, but is fairly unlikely nor serious if it does. if (con.hash == old.hash) { // Copy the persistant contact information. con.jnAcc = old.jnAcc; con.jtAcc = old.jtAcc; } } } //TODO: revise this.contacts = info.arr; //this.count = info.count; this.n = info.n; this.e = a.e * b.e; this.u = a.u * b.u; cpVect surface_vr = cpVect.cpvsub(b.surfaceV, a.surfaceV); this.surface_vr = cpVect.cpvsub(surface_vr, cpVect.cpvmult(info.n, cpVect.cpvdot(surface_vr, info.n))); ulong typeA = info.a.type, typeB = info.b.type; cpCollisionHandler defaultHandler = space.defaultHandler; cpCollisionHandler handler = this.handler = space.LookupHandler(typeA, typeB, defaultHandler); // Check if the types match, but don't swap for a default handler which use the wildcard for type A. bool swapped = this.swapped = (typeA != handler.typeA && handler.typeA != cp.WILDCARD_COLLISION_TYPE); if (handler != defaultHandler || space.usesWildcards) { // The order of the main handler swaps the wildcard handlers too. Uffda. this.handlerA = space.LookupHandler(swapped ? typeB : typeA, cp.WILDCARD_COLLISION_TYPE, cpCollisionHandler.cpCollisionHandlerDoNothing); this.handlerB = space.LookupHandler(swapped ? typeA : typeB, cp.WILDCARD_COLLISION_TYPE, cpCollisionHandler.cpCollisionHandlerDoNothing); } // mark it as new if it's been cached if (this.state == cpArbiterState.Cached) { this.state = cpArbiterState.FirstCollision; } }
public void CallWildcardSeparateA(cpSpace space) { cpCollisionHandler handler = this.handlerA; handler.separateFunc(this, space, handler.userData); }
public void CallWildcardPostSolveA(cpSpace space) { cpCollisionHandler handler = this.handlerA; handler.postSolveFunc(this, space, handler.userData); }
public bool CallWildcardPreSolveA(cpSpace space) { cpCollisionHandler handler = this.handlerA; return(handler.preSolveFunc(this, space, handler.userData)); }
public bool CallWildcardBeginA(cpSpace space) { cpCollisionHandler handler = this.handlerA; return(handler.beginFunc(this, space, handler.userData)); }
// Used for disposing of collision handlers. //static void FreeWrap(void* ptr, void* unused) { cpfree(ptr); } //MARK: Memory Management Functions public cpSpace() { #if DEBUG Console.WriteLine("Initializing cpSpace - Chipmunk v{0} (Debug Enabled)\n", cp.cpVersionString); Console.WriteLine("Compile with -DNDEBUG defined to disable debug mode and runtime assertion checks\n"); #endif /// Number of iterations to use in the impulse solver to solve contacts. this.iterations = 10; /// Gravity to pass to rigid bodies when integrating velocity. this.gravity = cpVect.Zero; /// Damping rate expressed as the fraction of velocity bodies retain each second. /// A value of 0.9 would mean that each body's velocity will drop 10% per second. /// The default value is 1.0, meaning no damping is applied. /// @note This damping value is different than those of cpDampedSpring and cpDampedRotarySpring. this.damping = 1; /// Amount of encouraged penetration between colliding shapes.. /// Used to reduce oscillating contacts and keep the collision cache warm. /// Defaults to 0.1. If you have poor simulation quality, /// increase this number as much as possible without allowing visible amounts of overlap. this.collisionSlop = 0.1f; /// Determines how fast overlapping shapes are pushed apart. /// Expressed as a fraction of the error remaining after each second. /// Defaults to pow(1.0 - 0.1, 60.0) meaning that Chipmunk fixes 10% of overlap each frame at 60Hz. this.collisionBias = cp.cpfpow(1f - 0.1f, 60f); /// Number of frames that contact information should persist. /// Defaults to 3. There is probably never a reason to change this value. this.collisionPersistence = 3; this.locked = 0; this.stamp = 0; this.staticShapes = new cpBBTree(null); this.dynamicShapes = new cpBBTree(this.staticShapes); this.dynamicShapes.SetVelocityFunc(o => ShapeVelocityFunc(o as cpShape)); this.dynamicBodies = new List <cpBody>(); this.staticBodies = new List <cpBody>(); this.rousedBodies = new List <cpBody>(); this.sleepingComponents = new List <cpBody>(); /// Time a group of bodies must remain idle in order to fall asleep. /// Enabling sleeping also implicitly enables the the contact graph. /// The default value of Infinity disables the sleeping algorithm. this.sleepTimeThreshold = cp.Infinity; /// Speed threshold for a body to be considered idle. /// The default value of 0 means to let the space guess a good threshold based on gravity. this.idleSpeedThreshold = 0; this.arbiters = new List <cpArbiter>(); this.cachedArbiters = new Dictionary <ulong, cpArbiter>(); this.constraints = new List <cpConstraint>(); this.usesWildcards = false; this.defaultHandler = cpCollisionHandlerDoNothing; this.collisionHandlers = new Dictionary <ulong, cpCollisionHandler>(); this.postStepCallbacks = new List <cpPostStepCallback>(); this.skipPostStep = false; /// The designated static body for this space. /// You can modify this body, or replace it with your own static body. /// By default it points to a statically allocated cpBody in the cpSpace struct. this.staticBody = cpBody.NewStatic(); }