Exemple #1
0
        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);
            }
        }
Exemple #2
0
        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);
        }
Exemple #3
0
        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);
        }
Exemple #4
0
        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);
        }
Exemple #5
0
        public bool CallWildcardBeginA(cpSpace space)
        {
            cpCollisionHandler handler = this.handlerA;

            return(handler.beginFunc(this, space, handler.userData));
        }
Exemple #6
0
        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;
        }
Exemple #7
0
 // Equals function for collisionHandlers.
 public static bool SetEql(cpCollisionHandler check, cpCollisionHandler pair)
 {
     return (
         (check.typeA == pair.typeA && check.typeB == pair.typeB) ||
         (check.typeB == pair.typeA && check.typeA == pair.typeB)
     );
 }
Exemple #8
0
        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.ToList();
            //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;
        }
Exemple #9
0
        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;
        }
Exemple #10
0
        public void CallWildcardSeparateA(cpSpace space)
        {
            cpCollisionHandler handler = this.handlerA;

            handler.separateFunc(this, space, handler.userData);
        }
Exemple #11
0
        // Used for disposing of collision handlers.
        //static void FreeWrap(void* ptr, void* unused) { cpfree(ptr); }

        //MARK: Memory Management Functions


        public cpSpace()
        {
#if DEBUG
            Debug.WriteLine("Initializing cpSpace - Chipmunk v{0} (Debug Enabled)\n", cp.cpVersionString);
            Debug.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();
        }
Exemple #12
0
        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);
        }
Exemple #13
0
 public void UseWildcardDefaultHandler()
 {
     // Spaces default to using the slightly faster "do nothing" default handler until wildcards are potentially needed.
     if (!this.usesWildcards)
     {
         this.usesWildcards = true;
         this.defaultHandler = cpCollisionHandlerDefault;
     }
 }
Exemple #14
0
 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;
 }
Exemple #15
0
        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;
        }
Exemple #16
0
        public bool CallWildcardPreSolveA(cpSpace space)
        {
            cpCollisionHandler handler = this.handlerA;

            return(handler.preSolveFunc(this, space, handler.userData));
        }
Exemple #17
0
        public void CallWildcardPostSolveA(cpSpace space)
        {
            cpCollisionHandler handler = this.handlerA;

            handler.postSolveFunc(this, space, handler.userData);
        }
Exemple #18
0
        /// A colliding pair of shapes.
        public cpArbiter(cpShape a, cpShape b)
        {
            this.handler = null;
            this.swapped = false;

            this.handlerA = null;
            this.handlerB = null;

            /// Calculated value to use for the elasticity coefficient.
            /// Override in a pre-solve collision handler for custom behavior.
            this.e = 0;
            /// Calculated value to use for the friction coefficient.
            /// Override in a pre-solve collision handler for custom behavior.
            this.u = 0;
            /// Calculated value to use for applying surface velocities.
            /// Override in a pre-solve collision handler for custom behavior.
            this.surface_vr = cpVect.Zero;

            this.a = a; this.body_a = a.body;
            this.b = b; this.body_b = b.body;

            this.thread_a = new cpArbiterThread(null, null);
            this.thread_b = new cpArbiterThread(null, null);

            this.contacts = new List<cpContact>();

            this.stamp = 0;

            this.state = cpArbiterState.FirstCollision;
        }
Exemple #19
0
        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.ToList();
            //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;
            }
        }
Exemple #20
0
        // Used for disposing of collision handlers.
        //static void FreeWrap(void* ptr, void* unused) { cpfree(ptr); }
        //MARK: Memory Management Functions
        public cpSpace()
        {
            #if DEBUG
            Debug.WriteLine("Initializing cpSpace - Chipmunk v{0} (Debug Enabled)\n", cp.cpVersionString);
            Debug.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();
        }