2 * Copyright (c) 2023 Codefoco (codefoco@codefoco.com)
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 using System.Collections.Generic;
25 using System.ComponentModel;
26 using System.Diagnostics;
27 using System.Runtime.InteropServices;
28 using cpBody = System.IntPtr;
29 using cpCollisionHandlerPointer = System.IntPtr;
30 using cpCollisionType = System.UIntPtr;
31 using cpConstraint = System.IntPtr;
32 using cpDataPointer = System.IntPtr;
33 using cpShape = System.IntPtr;
34 using cpSpace = System.IntPtr;
35 using voidptr_t = System.IntPtr;
37 #if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__
41 namespace Tizen.NUI.Physics2D.Chipmunk
44 /// Spaces in Chipmunk are the basic unit of simulation. You add rigid bodies, shapes, and
45 /// constraints to the space and then step them all forward through time together.
47 [EditorBrowsable(EditorBrowsableState.Never)]
48 public class Space : IDisposable
50 #pragma warning disable IDE0032
51 private readonly cpSpace space;
52 #pragma warning restore IDE0032
55 /// Native handle cpSpace.
57 [EditorBrowsable(EditorBrowsableState.Never)]
58 public cpSpace Handle => space;
61 /// Create a new Space object.
63 [EditorBrowsable(EditorBrowsableState.Never)]
66 space = NativeMethods.cpSpaceNew();
71 /// Create a space from a native Handle (used by derived classes).
73 /// <param name="handle"></param>
74 protected internal Space(cpSpace handle)
81 /// Destroys and frees.
83 [EditorBrowsable(EditorBrowsableState.Never)]
91 /// Destroy and free space.
93 /// <param name="handle"></param>
94 protected virtual void FreeSpace(cpSpace handle)
96 NativeMethods.cpSpaceFree(handle);
100 /// Destroy and free space.
102 protected virtual void Dispose(bool disposing)
107 /// Disposes the Space object.
109 [EditorBrowsable(EditorBrowsableState.Never)]
110 public void Dispose()
113 GC.SuppressFinalize(this);
116 void RegisterUserData()
118 cpDataPointer pointer = NativeInterop.RegisterHandle(this);
119 NativeMethods.cpSpaceSetUserData(space, pointer);
122 void ReleaseUserData()
124 cpDataPointer pointer = NativeMethods.cpSpaceGetUserData(space);
125 NativeInterop.ReleaseHandle(pointer);
129 /// Get a Space object from native cpSpace handle.
131 [EditorBrowsable(EditorBrowsableState.Never)]
132 public static Space FromHandle(cpSpace space)
134 cpDataPointer handle = NativeMethods.cpSpaceGetUserData(space);
135 return NativeInterop.FromIntPtr<Space>(handle);
139 /// Get a Space object from native cpSpace handle, but return null if the handle is 0.
141 [EditorBrowsable(EditorBrowsableState.Never)]
142 public static Space FromHandleSafe(cpSpace space)
144 if (space == IntPtr.Zero)
149 return FromHandle(space);
155 /// Arbitrary user data.
157 [EditorBrowsable(EditorBrowsableState.Never)]
158 public object Data { get; set; }
161 /// Number of iterations to use in the impulse solver to solve contacts and other
164 [EditorBrowsable(EditorBrowsableState.Never)]
165 public int Iterations
167 get => NativeMethods.cpSpaceGetIterations(space);
168 set => NativeMethods.cpSpaceSetIterations(space, value);
172 /// Gravity to pass to rigid bodies when integrating velocity.
174 [EditorBrowsable(EditorBrowsableState.Never)]
177 get => NativeMethods.cpSpaceGetGravity(space);
178 set => NativeMethods.cpSpaceSetGravity(space, value);
182 /// Damping rate expressed as the fraction of velocity that bodies retain each second. A
183 /// value of 0.9 would mean that each body's velocity will drop 10% per second. The default
184 /// value is 1.0, meaning no damping is applied. Note: This damping value is different than
185 /// those of <see cref="DampedSpring"/> and <see cref="DampedRotarySpring"/>.
187 [EditorBrowsable(EditorBrowsableState.Never)]
188 public double Damping
190 get => NativeMethods.cpSpaceGetDamping(space);
191 set => NativeMethods.cpSpaceSetDamping(space, value);
195 /// Speed threshold for a body to be considered idle. The default value of 0 means to let
196 /// the space guess a good threshold based on gravity.
198 [EditorBrowsable(EditorBrowsableState.Never)]
199 public double IdleSpeedThreshold
201 get => NativeMethods.cpSpaceGetIdleSpeedThreshold(space);
202 set => NativeMethods.cpSpaceSetIdleSpeedThreshold(space, value);
206 /// Time a group of bodies must remain idle in order to fall asleep. Enabling sleeping also
207 /// implicitly enables the the contact graph. The default value of infinity disables the
208 /// sleeping algorithm.
210 [EditorBrowsable(EditorBrowsableState.Never)]
211 public double SleepTimeThreshold
213 get => NativeMethods.cpSpaceGetSleepTimeThreshold(space);
214 set => NativeMethods.cpSpaceSetSleepTimeThreshold(space, value);
218 /// Amount of encouraged penetration between colliding shapes. This is used to reduce
219 /// oscillating contacts and keep the collision cache warm. Defaults to 0.1. If you have
220 /// poor simulation quality, increase this number as much as possible without allowing
221 /// visible amounts of overlap.
223 [EditorBrowsable(EditorBrowsableState.Never)]
224 public double CollisionSlop
226 get => NativeMethods.cpSpaceGetCollisionSlop(space);
227 set => NativeMethods.cpSpaceSetCollisionSlop(space, value);
231 /// Determines how fast overlapping shapes are pushed apart.
233 [EditorBrowsable(EditorBrowsableState.Never)]
234 public double CollisionBias
236 get => NativeMethods.cpSpaceGetCollisionBias(space);
237 set => NativeMethods.cpSpaceSetCollisionBias(space, value);
241 /// Number of frames that contact information should persist. Defaults to 3. There is
242 /// probably never a reason to change this value.
244 [EditorBrowsable(EditorBrowsableState.Never)]
245 public int CollisionPersistence
247 get => (int)NativeMethods.cpSpaceGetCollisionPersistence(space);
248 set => NativeMethods.cpSpaceSetCollisionPersistence(space, (uint)value);
252 /// The Space provided static body for a given <see cref="Space"/>.
254 [EditorBrowsable(EditorBrowsableState.Never)]
255 public Body StaticBody
259 cpBody bodyHandle = NativeMethods.cpSpaceGetStaticBody(space);
260 cpDataPointer gcHandle = NativeMethods.cpBodyGetUserData(bodyHandle);
262 if (gcHandle != IntPtr.Zero)
264 return NativeInterop.FromIntPtr<Body>(gcHandle);
267 return new Body(bodyHandle);
272 /// Returns the current (or most recent) time step used with the given space.
273 /// Useful from callbacks if your time step is not a compile-time global.
275 [EditorBrowsable(EditorBrowsableState.Never)]
276 public double CurrentTimeStep => NativeMethods.cpSpaceGetCurrentTimeStep(space);
279 /// Returns true from inside a callback when objects cannot be added/removed.
281 [EditorBrowsable(EditorBrowsableState.Never)]
282 public bool IsLocked => NativeMethods.cpSpaceIsLocked(space) != 0;
285 // Collision Handlers
288 /// Create or return the existing collision handler that is called for all collisions that are
289 /// not handled by a more specific collision handler.
291 [EditorBrowsable(EditorBrowsableState.Never)]
292 public CollisionHandler GetOrCreateDefaultCollisionHandler()
294 cpCollisionHandlerPointer collisionHandle = NativeMethods.cpSpaceAddDefaultCollisionHandler(space);
295 return CollisionHandler.GetOrCreate(collisionHandle);
300 /// Create or return the existing collision handler for the specified pair of collision
301 /// types. If wildcard handlers are used with either of the collision types, it's the
302 /// responsibility of the custom handler to invoke the wildcard handlers.
304 [EditorBrowsable(EditorBrowsableState.Never)]
305 public CollisionHandler GetOrCreateCollisionHandler(int typeA, int typeB)
307 uint utypeA = unchecked((uint)typeA);
308 uint utypeB = unchecked((uint)typeB);
310 cpCollisionType collisionTypeA = new cpCollisionType(utypeA);
311 cpCollisionType collisionTypeB = new cpCollisionType(utypeB);
313 cpCollisionHandlerPointer collisionHandle = NativeMethods.cpSpaceAddCollisionHandler(space, collisionTypeA, collisionTypeB);
314 return CollisionHandler.GetOrCreate(collisionHandle);
319 /// Create or return the existing wildcard collision handler for the specified type.
321 [EditorBrowsable(EditorBrowsableState.Never)]
322 public CollisionHandler GetOrCreateWildcardHandler(int type)
324 cpCollisionHandlerPointer collisionHandle = NativeMethods.cpSpaceAddWildcardHandler(space, (cpCollisionType)type);
325 return CollisionHandler.GetOrCreate(collisionHandle);
329 /// Add a collision shape to the simulation.
331 [EditorBrowsable(EditorBrowsableState.Never)]
332 public void AddShape(Shape shape)
334 NativeMethods.cpSpaceAddShape(space, shape.Handle);
338 /// Add a rigid body to the simulation.
340 [EditorBrowsable(EditorBrowsableState.Never)]
341 public void AddBody(Body body)
343 NativeMethods.cpSpaceAddBody(space, body.Handle);
347 /// Add a constraint to the simulation.
349 [EditorBrowsable(EditorBrowsableState.Never)]
350 public void AddConstraint(Constraint constraint)
352 NativeMethods.cpSpaceAddConstraint(space, constraint.Handle);
356 /// Remove a collision shape from the simulation.
358 [EditorBrowsable(EditorBrowsableState.Never)]
359 public void RemoveShape(Shape shape)
361 NativeMethods.cpSpaceRemoveShape(space, shape.Handle);
365 /// Remove a rigid body from the simulation.
367 [EditorBrowsable(EditorBrowsableState.Never)]
368 public void RemoveBody(Body body)
370 NativeMethods.cpSpaceRemoveBody(space, body.Handle);
374 /// Remove a constraint from the simulation.
376 [EditorBrowsable(EditorBrowsableState.Never)]
377 public void RemoveConstraint(Constraint constraint)
379 NativeMethods.cpSpaceRemoveConstraint(space, constraint.Handle);
383 /// Test if a collision shape has been added to the space.
385 [EditorBrowsable(EditorBrowsableState.Never)]
386 public bool Contains(Shape shape)
388 return NativeMethods.cpSpaceContainsShape(space, shape.Handle) != 0;
392 /// Test if a rigid body has been added to the space.
394 [EditorBrowsable(EditorBrowsableState.Never)]
395 public bool Contains(Body body)
397 return NativeMethods.cpSpaceContainsBody(space, body.Handle) != 0;
401 /// Test if a constraint has been added to the space.
403 [EditorBrowsable(EditorBrowsableState.Never)]
404 public bool Contains(Constraint constraint)
406 return NativeMethods.cpSpaceContainsConstraint(space, constraint.Handle) != 0;
409 #if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__
410 #pragma warning disable CA1416 // Validate platform compatibility
411 [MonoPInvokeCallback(typeof(PostStepFunction))]
412 #pragma warning restore CA1416 // Validate platform compatibility
414 private static void PostStepCallBack(cpSpace handleSpace, voidptr_t handleKey, voidptr_t handleData)
416 var space = FromHandle(handleSpace);
417 var key = NativeInterop.FromIntPtr<object>(handleKey);
418 var data = NativeInterop.FromIntPtr<PostStepCallbackInfo>(handleData);
420 Action<Space, object, object> callback = data.Callback;
422 callback(space, key, data.Data);
424 NativeInterop.ReleaseHandle(handleKey);
425 NativeInterop.ReleaseHandle(handleData);
428 private static PostStepFunction postStepCallBack = PostStepCallBack;
431 /// Schedule a post-step callback to be called when <see cref="Step"/> finishes. You can
432 /// only register one callback per unique value for <paramref name="key"/>. Returns true
433 /// only if <paramref name="key"/> has never been scheduled before. It's possible to pass
434 /// null for <paramref name="callback"/> if you only want to mark <paramref name="key"/> as
437 [EditorBrowsable(EditorBrowsableState.Never)]
438 public bool AddPostStepCallback(Action<Space, object, object> callback, object key, object data)
440 var info = new PostStepCallbackInfo(callback, data);
442 IntPtr dataHandle = NativeInterop.RegisterHandle(info);
443 IntPtr keyHandle = NativeInterop.RegisterHandle(key);
445 return NativeMethods.cpSpaceAddPostStepCallback(space, postStepCallBack.ToFunctionPointer(), keyHandle, dataHandle) != 0;
448 #if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__
449 #pragma warning disable CA1416 // Validate platform compatibility
450 [MonoPInvokeCallback(typeof(SpacePointQueryFunction))]
451 #pragma warning restore CA1416 // Validate platform compatibility
453 private static void EachPointQuery(cpShape shapeHandle, Vect point, double distance, Vect gradient, voidptr_t data)
455 var list = (List<PointQueryInfo>)GCHandle.FromIntPtr(data).Target;
457 var shape = Shape.FromHandle(shapeHandle);
458 var pointQuery = new PointQueryInfo(shape, point, distance, gradient);
460 list.Add(pointQuery);
463 private static SpacePointQueryFunction eachPointQuery = EachPointQuery;
466 /// Get the shapes within a radius of the point location that are part of this space. The
467 /// filter is applied to the query and follows the same rules as the collision detection.
468 /// If a maxDistance of 0.0 is used, the point must lie inside a shape. Negative
469 /// <paramref name="maxDistance"/> is also allowed meaning that the point must be a under a
470 /// certain depth within a shape to be considered a match.
472 /// <param name="point">Where to check for shapes in the space.</param>
473 /// <param name="maxDistance">Match only within this distance.</param>
474 /// <param name="filter">Only pick shapes matching the filter.</param>
475 [EditorBrowsable(EditorBrowsableState.Never)]
476 public IReadOnlyList<PointQueryInfo> PointQuery(Vect point, double maxDistance, ShapeFilter filter)
478 var list = new List<PointQueryInfo>();
479 var gcHandle = GCHandle.Alloc(list);
481 NativeMethods.cpSpacePointQuery(space, point, maxDistance, filter, eachPointQuery.ToFunctionPointer(), GCHandle.ToIntPtr(gcHandle));
488 /// Get the nearest shape within a radius of a point that is part of this space. The filter
489 /// is applied to the query and follows the same rules as the collision detection. If a
490 /// <paramref name="maxDistance"/> of 0.0 is used, the point must lie inside a shape.
491 /// Negative <paramref name="maxDistance"/> is also allowed, meaning that the point must be
492 /// under a certain depth within a shape to be considered a match.
494 /// <param name="point">Where to check for collision in the space.</param>
495 /// <param name="maxDistance">Match only within this distance.</param>
496 /// <param name="filter">Only pick shapes matching the filter.</param>
497 [EditorBrowsable(EditorBrowsableState.Never)]
498 public PointQueryInfo PointQueryNearest(Vect point, double maxDistance, ShapeFilter filter)
500 var queryInfo = new cpPointQueryInfo();
502 cpShape shape = NativeMethods.cpSpacePointQueryNearest(space, point, maxDistance, filter, ref queryInfo);
503 if (shape == IntPtr.Zero)
506 return PointQueryInfo.FromQueryInfo(queryInfo);
509 #if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__
510 #pragma warning disable CA1416 // Validate platform compatibility
511 [MonoPInvokeCallback(typeof(SpaceSegmentQueryFunction))]
512 #pragma warning restore CA1416 // Validate platform compatibility
514 private static void EachSegmentQuery(cpShape shapeHandle, Vect point, Vect normal, double alpha, voidptr_t data)
516 var list = (List<SegmentQueryInfo>)GCHandle.FromIntPtr(data).Target;
518 var shape = Shape.FromHandle(shapeHandle);
519 var pointQuery = new SegmentQueryInfo(shape, point, normal, alpha);
521 list.Add(pointQuery);
524 private static SpaceSegmentQueryFunction eachSegmentQuery = EachSegmentQuery;
527 /// Get the shapes within a capsule-shaped radius of a line segment that is part of this
528 /// space. The filter is applied to the query and follows the same rules as the collision
531 [EditorBrowsable(EditorBrowsableState.Never)]
532 public IReadOnlyList<SegmentQueryInfo> SegmentQuery(Vect start, Vect end, double radius, ShapeFilter filter)
534 var list = new List<SegmentQueryInfo>();
535 var gcHandle = GCHandle.Alloc(list);
537 NativeMethods.cpSpaceSegmentQuery(space, start, end, radius, filter, eachSegmentQuery.ToFunctionPointer(), GCHandle.ToIntPtr(gcHandle));
544 /// Get the first shape within a capsule-shaped radius of a line segment that is part of
545 /// this space. The filter is applied to the query and follows the same rules as the
546 /// collision detection.
548 [EditorBrowsable(EditorBrowsableState.Never)]
549 public SegmentQueryInfo SegmentQueryFirst(Vect start, Vect end, double radius, ShapeFilter filter)
551 var queryInfo = new cpSegmentQueryInfo();
553 cpShape shape = NativeMethods.cpSpaceSegmentQueryFirst(space, start, end, radius, filter, ref queryInfo);
554 if (shape == IntPtr.Zero)
557 return SegmentQueryInfo.FromQueryInfo(queryInfo);
561 #if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__
562 #pragma warning disable CA1416 // Validate platform compatibility
563 [MonoPInvokeCallback(typeof(SpaceBBQueryFunction))]
564 #pragma warning restore CA1416 // Validate platform compatibility
566 private static void EachBBQuery(cpShape shapeHandle, voidptr_t data)
568 var list = (List<Shape>)GCHandle.FromIntPtr(data).Target;
570 var shape = Shape.FromHandle(shapeHandle);
575 private static SpaceBBQueryFunction eachBBQuery = EachBBQuery;
579 /// Get all shapes within the axis-aligned bounding box that are part of this shape. The
580 /// filter is applied to the query and follows the same rules as the collision detection.
582 [EditorBrowsable(EditorBrowsableState.Never)]
583 public IReadOnlyList<Shape> BoundBoxQuery(BoundingBox bb, ShapeFilter filter)
585 var list = new List<Shape>();
587 var gcHandle = GCHandle.Alloc(list);
589 NativeMethods.cpSpaceBBQuery(space, bb, filter, eachBBQuery.ToFunctionPointer(), GCHandle.ToIntPtr(gcHandle));
596 /// Get all bodies in the space.
598 [EditorBrowsable(EditorBrowsableState.Never)]
599 public IReadOnlyList<Body> Bodies
603 int count = NativeMethods.cpSpaceGetBodyCount(space);
606 return Array.Empty<Body>();
608 IntPtr ptrBodies = Marshal.AllocHGlobal(IntPtr.Size * count);
609 NativeMethods.cpSpaceGetBodiesUserDataArray(space, ptrBodies);
611 IntPtr[] userDataArray = new IntPtr[count];
613 Marshal.Copy(ptrBodies, userDataArray, 0, count);
615 Marshal.FreeHGlobal(ptrBodies);
617 Body[] bodies = new Body[count];
619 for (int i = 0; i < count; i++)
621 Body b = NativeInterop.FromIntPtr<Body>(userDataArray[i]);
630 /// Get dynamic bodies in the space.
632 [EditorBrowsable(EditorBrowsableState.Never)]
633 public IReadOnlyList<Body> DynamicBodies
637 int count = NativeMethods.cpSpaceGetDynamicBodyCount(space);
640 return Array.Empty<Body>();
642 IntPtr ptrBodies = Marshal.AllocHGlobal(IntPtr.Size * count);
643 NativeMethods.cpSpaceGetDynamicBodiesUserDataArray(space, ptrBodies);
645 IntPtr[] userDataArray = new IntPtr[count];
647 Marshal.Copy(ptrBodies, userDataArray, 0, count);
649 Marshal.FreeHGlobal(ptrBodies);
651 Body[] bodies = new Body[count];
653 for (int i = 0; i < count; i++)
655 Body b = NativeInterop.FromIntPtr<Body>(userDataArray[i]);
663 #if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__
664 #pragma warning disable CA1416 // Validate platform compatibility
665 [MonoPInvokeCallback(typeof(SpaceObjectIteratorFunction))]
666 #pragma warning restore CA1416 // Validate platform compatibility
668 private static void EachShape(cpShape shapeHandle, voidptr_t data)
670 var list = (List<Shape>)GCHandle.FromIntPtr(data).Target;
672 var shape = Shape.FromHandle(shapeHandle);
677 private static SpaceObjectIteratorFunction eachShape = EachShape;
680 /// Get all shapes in the space.
682 [EditorBrowsable(EditorBrowsableState.Never)]
683 public IReadOnlyList<Shape> Shapes
687 var list = new List<Shape>();
689 var gcHandle = GCHandle.Alloc(list);
691 NativeMethods.cpSpaceEachShape(space, eachShape.ToFunctionPointer(), GCHandle.ToIntPtr(gcHandle));
699 #if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__
700 #pragma warning disable CA1416 // Validate platform compatibility
701 [MonoPInvokeCallback(typeof(SpaceShapeQueryFunction))]
702 #pragma warning restore CA1416 // Validate platform compatibility
704 private static void ShapeQueryCallback(cpShape shape, IntPtr pointsPointer, voidptr_t data)
706 var list = (List<ContactPointSet>)GCHandle.FromIntPtr(data).Target;
708 var pointSet = NativeInterop.PtrToStructure<cpContactPointSet>(pointsPointer);
710 list.Add(ContactPointSet.FromContactPointSet(pointSet));
713 private static SpaceShapeQueryFunction shapeQueryCallback = ShapeQueryCallback;
716 /// Get all shapes in the space that are overlapping the given shape.
718 [EditorBrowsable(EditorBrowsableState.Never)]
719 public IReadOnlyList<ContactPointSet> ShapeQuery(Shape shape)
721 var list = new List<ContactPointSet>();
722 var gcHandle = GCHandle.Alloc(list);
724 NativeMethods.cpSpaceShapeQuery(space, shape.Handle, shapeQueryCallback.ToFunctionPointer(), GCHandle.ToIntPtr(gcHandle));
730 #if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__
731 #pragma warning disable CA1416 // Validate platform compatibility
732 [MonoPInvokeCallback(typeof(SpaceObjectIteratorFunction))]
733 #pragma warning restore CA1416 // Validate platform compatibility
735 private static void EachConstraint(cpConstraint constraintHandle, voidptr_t data)
737 var list = (List<Constraint>)GCHandle.FromIntPtr(data).Target;
739 var constraint = Constraint.FromHandle(constraintHandle);
741 list.Add(constraint);
744 private static SpaceObjectIteratorFunction eachConstraint = EachConstraint;
748 /// Get all constraints in the space.
750 [EditorBrowsable(EditorBrowsableState.Never)]
751 public IReadOnlyList<Constraint> Constraints
755 var list = new List<Constraint>();
757 var gcHandle = GCHandle.Alloc(list);
759 NativeMethods.cpSpaceEachConstraint(space, eachConstraint.ToFunctionPointer(), GCHandle.ToIntPtr(gcHandle));
768 /// Update the collision detection info for the static shapes in the space.
770 [EditorBrowsable(EditorBrowsableState.Never)]
771 public void ReindexStatic()
773 NativeMethods.cpSpaceReindexStatic(space);
777 /// Update the collision detection data for a specific shape in the space.
779 [EditorBrowsable(EditorBrowsableState.Never)]
780 public void ReindexShape(Shape shape)
782 NativeMethods.cpSpaceReindexShape(space, shape.Handle);
786 /// Update the collision detection data for all shapes attached to a body.
788 [EditorBrowsable(EditorBrowsableState.Never)]
789 public void ReindexShapesForBody(Body body)
791 NativeMethods.cpSpaceReindexShapesForBody(space, body.Handle);
795 /// Switch the space to use a spatial hash as its spatial index.
797 [EditorBrowsable(EditorBrowsableState.Never)]
798 public void UseSpatialHash(double dim, int count)
800 NativeMethods.cpSpaceUseSpatialHash(space, dim, count);
804 /// Update the space for the given time step. Using a fixed time step is highly recommended.
805 /// Doing so will increase the efficiency of the contact persistence, requiring an order of
806 /// magnitude fewer iterations to resolve the collisions in the usual case. It is not the
807 /// same to call step 10 times with a dt of 0.1, or 100 times with a dt of 0.01 even if the
808 /// end result is that the simulation moved forward 100 units. Performing multiple calls
809 /// with a smaller dt creates a more stable and accurate simulation. Therefore, it sometimes
810 /// makes sense to have a little for loop around the step call.
812 [EditorBrowsable(EditorBrowsableState.Never)]
813 public virtual void Step(double dt)
815 NativeMethods.cpSpaceStep(space, dt);
819 /// Draw all objects in the space for debugging purposes.
821 [EditorBrowsable(EditorBrowsableState.Never)]
822 public void DebugDraw(IDebugDraw debugDraw)
824 DebugDraw(debugDraw, DebugDrawFlags.All, DebugDrawColors.Default);
828 /// Draw all objects in the space for debugging purposes using flags.
830 [EditorBrowsable(EditorBrowsableState.Never)]
831 public void DebugDraw(IDebugDraw debugDraw, DebugDrawFlags flags)
833 DebugDraw(debugDraw, flags, DebugDrawColors.Default);
837 /// Draw all objects in the space for debugging purposes using flags and colors.
839 [EditorBrowsable(EditorBrowsableState.Never)]
840 public void DebugDraw(IDebugDraw debugDraw, DebugDrawFlags flags, DebugDrawColors colors)
842 var debugDrawOptions = new cpSpaceDebugDrawOptions();
843 IntPtr debugDrawOptionsPointer = debugDrawOptions.AcquireDebugDrawOptions(debugDraw, flags, colors);
845 NativeMethods.cpSpaceDebugDraw(space, debugDrawOptionsPointer);
847 debugDrawOptions.ReleaseDebugDrawOptions(debugDrawOptionsPointer);