-
Notifications
You must be signed in to change notification settings - Fork 24
Home
- Chipmunk Physics
- Chipmunk Basics
- Ruby Bindings API
- Chipmunk Vectors
- Chipmunk Bounding Boxes
- Chipmunk Rigid Bodies
- Chipmunk Collision Shapes
- Chipmunk Spaces
- Chipmunk Constraints
- Constraint Types
- Overview of Collision Detection in Chipmunk
- Callbacks
- Chipmunk Collision Pairs
- Queries
Chipmunk is a 2D rigid body physics library distributed under the MIT license by Scott Lembcke. This file contains the documentation of the Ruby bindings of Chipmunk by John Mair and Beoran. It describes how you can use Chipmunk in Ruby. It is based on the original C documentation. Look there for anything that's missing here.
There are 4 basic objects you will use in Chipmunk.
- Body A Body holds the physical properties of an object. (mass, position, rotation, velocity, etc.) It does not have a shape by itself. If you’ve done physics with particles before, rigid bodies differ in that they are able to rotate.
- Shape: By attaching Shapes to bodies, you can define the a body’s shape. You can attach as many shapes to a single body as you need to in order to define a complex shape. Shapes contain the surface properties of an object such as how much friction or elasticity it has.
- Constraint Constraints and joints describe how bodies are attached to each other.
- Space Spaces are the basic simulation unit in Chipmunk. You add bodies, shapes and joints to a space, and then update the space as a whole.
There is often confusion between rigid bodies and their collision shapes in Chipmunk and how they relate to sprites. A sprite would be a visual representation of an object, while a collision shape is an invisible property that defines how objects should collide. Both the sprite’s and the collision shape’s position and rotation are controlled by a rigid body.
In these Ruby bindings, Chipmunk is automatically initialized when
you do require 'chipmunk'
Ruby is garbage collected, so normallly you don't have to worry
about this. One important exception are objects of the Arbiter
class, which may only be referenced inside a collision callback.
Any data inside the Arbiter has to be copied out, and no reference
to the Arbiter should be held, since Chipmunk erases the arbiters
after calling the collision callback.
These bindings commonly use Ruby Float for calculations.
There are a few functions in the CP module you will probably find very useful:
CP.clamp(f, min, max)
Clamp f
to be between min
and max
.
CP.flerp(f1, f2, t)
Linearly interpolate between f1
and f2
.
CP.flerpconst(f1, f2, d)
Linearly interpolate from f1
towards f2
by no more than d
.
Floating point infinity is defined for you as CP::INFINITY
, and
also as Float::INFINITY
if your version of Ruby doesn’t define it
for you.
To represent vectors, Chipmunk defines the Vec2 type and a set of operators for working with them.
- Vec2 – Create and manipulate 2D vectors.
- BB – Create and manipulate 2D axis-aligned bounding boxes.
- Body – Create and work with rigid bodies.
- Shape – Attach collision shapes to rigid bodies.
- Space – Create a “space” to put your objects into and simulate them.
- Constraint – Create joints and other constraints.
- Learn about how Collision Detection in Chipmunk works.
- Learn about Chipmunk’s Callback System for recieving collision events and adding custom behavior to your physics.
- Learn about Queries. Point queries and segment queries (raycasting).
CP::Vec2
2 dimensional vector class.
CP::Vec2.new(x, y)
Allocates a new vector with the given x
and y
coordinates.
vec2(x, y)
Global convenience function that allocates a new vector with the
given x
and y
coordinates.
CP::Vec2.for_angle?(a)
Constructs a unit vector wich makesan angle a
with the x axis.
CP::Vec2::ZERO
Constant for the zero vector.
``
CP::Vec2#x
X coordinate of vector.
CP::Vec2#y
Y coordinate of vector.
CP::Vec2#==(vec)
Check if two vectors are equal. (Be careful when comparing floating
point numbers!)
CP::Vec2#+(vec)
CP::Vec22#-(vec)
Add or subtract two vectors.
CP::Vec2#@-
CP::Vec22#@+
Negate a vector, or return itself.
CP::Vec2#*(scalar)
CP::Vec22#/(scalar)
Scalar multiplication and division.
CP::Vec2#dot(vect)
Vector dot product.
CP::Vec2#cross(vect)
2D vector cross product analog. The cross product of 2D vectors
results in a 3D vector with only a z component. This function
returns the magnitude of the z value.
CP::Vec2#perp
Returns a perpendicular vector. (90 degree rotation)
CP::Vec2#nperp
Returns a perpendicular vector. (-90 degree rotation)
CP::Vec2#project(vec)
Returns the vector projection of self
onto vec
.
CP::Vec2#rotate(vec)
Uses complex multiplication to rotate self
by vec
. Scaling will
occur if self
is not a unit vector.
CP::Vec2#unrotate(vec)
Inverse of CP::Vec2#rotate(vec)
CP::Vec2#length()
Returns the length of self
.
CP::Vec2#lengthsq()
Returns the squared length of self
. Faster than Vec2#length when
you only need to compare lengths.
CP::Vec2#lerp(vec, t)
Linearly interpolate between self
and vec
.
CP::Vec2#lerpconst(vec, d)
Linearly interpolate between self
towards vec
by distance d
.
CP::Vec2#slerp(vec, t)
Spherically linearly interpolate between self
and vec
.
CP::Vec2#slerpconst(vec, a)
Spherical linearly interpolate between self
towards vec
by no
more than angle a
in radians.
CP::Vec2#normalize
Returns a normalized copy of self
.
CP::Vec2#normalize_safe
Returns a normalized copy of self
. Protects against divide by
zero errors. Returns CP::Vec2::ZERO
if there vector was already
zero.
CP::Vec2#clamp(len)
Clamp self
to length len
.
CP::Vec2#dist(vec)
Returns the distance between self
and vec
.
CP::Vec2#distsq(vec)
Returns the squared distance between self
and vec
. Faster than
Vec2#dist(vec)
when you only need to compare distances.
CP::Vec2#near?(vec, dist)
Returns true if the distance between self
and vec
is less than
dist
.
CP::Vec2#to_angle
Returns the angular direction self
is pointing in (in radians).
CP::Vec2#to_s
Returns a string representation of self
. Intended mostly for
debugging purposes.
class CP::BB
Simple bounding box struct. Stored as left, bottom, right, top
values.
CP::BB.new(l, b, r, t)
Constructor for BB
classes.
CP::BB#l, CP::BB#b, CP::BB#r, CP::BB#t
Readers for the bounding box' left, bottom, right and top,
respectively.
CP::BB#intersect(other)
Returns true if the bounding boxes intersect.
CP::BB#contain_bb?(other)
Returns true if self
completely contains other
.
CP::BB#contain_vect?(vect)
Returns true if self
contains vec
.
CP::BB#contain?(other)
Returns true if self
contains other
. Convenience method that
works for both CP::Vec2 and CP::BB.
CP::BB#merge(other)
Return the minimal bounding box that contains both self
and
other
.
CP::BB#expand(vec)
Return the minimal bounding box that contains both self
and
vec
.
CP::BB#clamp_vect(vec)
Returns a copy of vec
clamped to the bounding box.
CP::BB#wrap_vect(vec)
Returns a copy of vec
wrapped to the bounding box.
CP::Body#velocity_func() { |body, gravity, damping, dt| ... }
If a block is passsed, this block is called as a custom velocity
integration function. If no block is passed, the default behaviour
is restored. If you wonder if you need this, then you don't. :)
CP::Body#position_func() { |body,dt| ... }
If a block is passsed, this block is called as a custom position
integration function. If no block is passed, the default behaviour
is restored. If you wonder if you need this, then you don't. :)
-
m
–Float
: Mass of the body. -
i
–Float
: Moment of inertia (MoI or sometimes just moment) of the body. The moment is like the rotational mass of a body. See below for function to help calculate the moment. -
p
–CP::Vec2
: Position of the body. -
v
–CP::Vec2
: Velocity of the body. -
f
–CP::Vec2
: Current force being applied to the body. Note: does not reset automatically as in some physics engines. -
a
–Float
: Current rotation angle of the body in radians. -
w
–Float
: Current rotational velocity of the body. -
t
–Float
: Current torque being applied to the body. Note: does not reset automatically as in some physics engines. -
rot
–CP::Vec2
: Cached unit length rotation vector. -
v_limit
–Float
: Maximum speed a body may have after updating it’s velocity. -
w_limit
–Float
: Maximum rotational speed a body may have after updating it’s velocity. -
data
–Object
: The ruby bindings use this field internally, so it is not available for you use. It returnsself
, but that is not guaranteed. -
object
–Object
: A user definable data object. If you set this to point at the game object the shapes is for, then you can access your game object from Chipmunk callbacks.
When changing any of a body’s properties, you should also call
CP::Body#activate()
to make sure that it is not stuck sleeping
when you’ve changed a property that should make it move again.
CP::Body.new(m, i)
Constructor for the Body class. m
and i
are the mass and moment
of inertia for the body. Guessing the mass for a body is usually
fine, but guessing a moment of inertia can lead to a very poor
simulation.
CP::Body.new_static()
CP::_static_body.new()
Creates static bodies with infinite mass and moment of inertia.
While every CP::Space
has a built in static body, this is not
usable from the Ruby API. With this constructor you can make your
own static bodies. One potential use is in a level editor. By
attaching chunks of your level to static bodies, you can still move
and rotate the chunks independently of each other. Then all you
have to do is call CP::Space.rehash_static()
to rebuild the
static collision detection data when you are done.
For more information on rogue and static bodies, see Chipmunk Spaces.
Use the following functions to approximate the moment of inertia for your body, adding the results together if you want to use more than one.
CP.moment_for_circle(m, r1, r2, offset)
Calculate the moment of inertia for a hollow circle, r1
and r2
are the inner and outer diameters in no particular order.
(A solid circle has an inner diameter of 0)
CP.moment_for_segment(m, a, b)
Calculate the moment of inertia for a line segment. The endpoints
a
and b
are relative to the body.
CP.moment_for_poly(m, verts, offset)
Calculate the moment of inertia for a solid polygon shape assuming
it’s center of gravity is at it’s centroid. The offset is added to
each vertex.
CP.moment_for_box(m, width, height)
Calculate the moment of inertia for a solid box centered on the
body.
Use the following functions to get the area for common Chipmunk shapes if you want to approximate masses.
CP.area_for_circle(r1, r2)
Area of a hollow circle.
CP.area_for_segment(a, b, r)
Area of a beveled segment. (Will always be zero if radius is zero)
CP.area_for_poly(verts)
Signed area of a polygon shape. Returns a negative number for
polygons with a backwards winding.
Because several rigid body values are linked to others, (m_inv
,
i_inv
, rot
), they cannot be set explicitly.
void CP::Body#slew(pos, dt)
Modify the velocity of the body so that it will move to the
specified absolute coordinates in the next timestep. Intended for
objects that are moved manually with a custom velocity integration
function.
void CP::Body#update_velocity(body, gravity, damping, dt)
Default rigid body velocity integration function. Updates the
velocity of the body using Euler integration.
void CP::Body#update_position(body, dt)
Default rigid body position integration function. Updates the
position of the body using Euler integration. Unlike the velocity
function, it’s unlikely you’ll want to override this function. If
you do, make sure you understand it’s source code as it’s an
important part of the collision/joint correction process.
CP::Body#local2world(vec)
Convert from body local coordinates to world space coordinates.
CP::Body#world2local(body, vex)
Convert from world space coordinates to body local coordinates.
CP::Body#apply_impulse(j, r)
Apply the impulse j
to body
at a relative offset r
from the
center of gravity. Both r
and j
are in world coordinates. r
is relative to the position of the body, but not the rotation. Many
people get tripped up by this.
CP::Body#reset_forces
Zero both the forces and torques accumulated on self
.
CP::Body#apply_force(f, r)
Apply (accumulate) the force f
on body
at a
relative offset (important!) r
from the center of gravity.
Both r
and f
are in world coordinates.
See Chipmunk Spaces CP::Space for more information on Chipmunk’s sleeping feature.
CP::Body#sleeping?
Returns true if body
is sleeping, false if not.
CP::Body#sleep_with_group(group)
When objects in Chipmunk sleep, they sleep as a group of all
objects that are touching or jointed together. When an object is
woken up, all of the objects in it’s group are woken up. Calling
CP::Body#sleep_with_group(group) forces a body to fall asleep
immediately. If group
is nil
, a new group will be created. If
group is another sleeping Body, it will be added to that body’s
group. It is an error to specify a non-sleeping Body for group
.
Make sure everything is set up before calling this method. Calling
a setter function or adding/removing a shape or constraint will
cause the body to be woken up again. Also, this function must not
be called from a collision handler or query callback. Use a
post-step callback instead.
An example of how this could be used is to set up a piles of boxes that a player can knock over. Creating the piles and letting them fall asleep normally would work, but it means that all of the boxes would need to be simulated until they fell asleep. This could be slow if you had a lot of piles. Instead you can force them to sleep and start the game with the boxes already sleeping.
Another example would be collapsing platforms. You could create a sleeping object that is suspended in the air. As soon as the player comes along to jump on it, it wakes up and starts falling. In this case, it would be impossible to have the platform fall asleep naturally.
CP::Body#sleep_alone
Equivalent to calling CP::Body#sleep_with_group(nil)
. It forces
body
to fall asleep and creates a new group for it. The name
sleep_alone
was chosen because sleep
is part of ruby's Kernel
module...
void CP::Body#activate
Wake self
up so that it starts actively simulating again if it’s
sleeping, or reset the idle timer if it’s active. In Chipmunk 5.3.4
and up, you can call this function from a collision or query
callback. In previous versions this was an error.
CP::Body#static?
Returns true if self
is a static body. (CP::_static_body or a
static rogue body)
CP::Body#rogue?()
Returns true if self
has never been added to a space. Though
shapes attached to this body may still be added to a space. For
more information on rogue and static bodies, see
Chipmunk Spaces.
CP::Bool CP::Body#sleeping?()
Returns true if self
is sleeping.
- Use forces to modify the rigid bodies if possible. This will be the most stable.
- Modifying a body’s velocity shouldn’t necessarily be avoided, but applying large changes every frame can cause strange results in the simulation. Experiment freely, but be warned.
- Don’t modify a body’s position every step unless you really know what you are doing. Otherwise you’re likely to get the position/velocity badly out of sync.
There are currently 3 collision shape types:
- Circles: Fastest and simplest collision shape.
- Line segments: Meant mainly as a static shape. They can be attached to moving bodies, but they don’t currently generate collisions with other line segments. Can be beveled in order to give them a thickness.
- Convex polygons: Slowest, but most flexible collision shape.
You can add multiple shapes to a body. This should give you the flexibility to make any shape you want as well providing different areas of the same object with different friction, elasticity or callback values.
All collision shapes include the CP::Shape module. Chipmunk shapes are meant to be opaque types.
-
body
–CP::Body
: The rigid body the shape is attached to. -
bb_raw
–CP::BB
: The bounding box of the shape. Only guaranteed to be valid afterCP::Shape#bb()
orCP::Space#step()
is called. Moving a body that a shape is connected to does not update it’s bounding box. -
sensor
–true or false
: A boolean value if this shape is a sensor or not. Sensors only call collision callbacks, and never generate real collisions. -
e
–Float
: Elasticity of the shape. A value of 0.0 gives no bounce, while a value of 1.0 will give a “perfect” bounce. However due to inaccuracies in the simulation using 1.0 or greater is not recommended however. See the notes at the end of the section. -
u
–Float
: Friction coefficient. Chipmunk uses the Coulomb friction model, a value of 0.0 is frictionless. Tables of friction coefficients. See the notes at the end of the section. -
surface_v
–CP::Vec2
: The surface velocity of the object. Useful for creating conveyor belts or players that move around. This value is only used when calculating friction, not resolving the collision. -
collision_type
–Symbol
: You can assign symbols as collision types types to Chipmunk collision shapes that trigger callbacks when objects of certain types touch. See the callbacks section or an example for more information. -
group
–Fixnum
: Shapes in the same non-zero group do not generate collisions. Useful when creating an object out of many shapes that you don’t want to self collide. Defaults toCP::NO_GROUP
. -
layers
–Fixnum
: Shapes only collide if they are in the same bit-planes. i.e.(a->layers & b->layers) != 0
By default, a shape occupies all bit-planes. Wikipedia has a nice article on bitmasks if you are unfamiliar with how to use them. Defaults toCP::ALL_LAYERS
. -
data
–Object
: The ruby bindings use this field internally, so it is not available for you use. It returnsself
, but that is not guaranteed. -
object
–Object
: A user definable data object. If you set this to point at the game object the shapes is for, then you can access your game object from Chipmunk callbacks.
Chipmunk has two primary means of ignoring collisions: groups and layers.
Groups are meant to ignore collisions between parts on a complex object. A ragdoll is a good example. When jointing an arm onto the torso, you’ll want them to allow them to overlap. Groups allow you to do exactly that. Shapes that have the same group don’t generate collisions. So by placing all of the shapes in a ragdoll in the same group, you’ll prevent it from colliding against other parts of itself.
Layers allow you to separate collision shapes into mutually exclusive planes. Shapes can be in more than one layer, and shapes only collide with other shapes that are in at least one of the same layers. As a simple example, say shape A is in layer 1, shape B is in layer 2, and shape C is in layer 1 and 2. Shape A and B won’t collide with each other, but shape C will collide with both A and B.
Layers can also be used to set up rule based collisions. Say you have four types of shapes in your game. The player, the enemies, player bullets and enemy bullets. The are that the player should collide with enemies, and bullets shouldn’t collide with the type (player or enemy) that fired them. Making a chart would look like this:
Player
Enemy
Player Bullet
Enemy Bullet
Player
–
(1)
(2)
Enemy
–
–
(3)
Player Bullet
–
–
–
Enemy Bullet
–
–
–
–
The ‘-’s are for redundant spots in the chart, and the numbers are
spots where types should collide. You can use a layer for rule that
you want to define. Then add the layers to each type: The player
should be in layers 1 and 2, the enemy should be in layers 1 and 3,
the player bullets should be in layer 3, and the enemy bullets
should be in layer 2. Treating layers as rules this way, you can
define up to 32 rules. The default layer
type has a resolution of
32 bits on most systems.
There is one last way of filtering collisions using collision handlers. See the section on callbacks for more information. While collision handlers can be more flexible, they are also the slowest method. So you try to use groups or layers first.
CP::Shape#cache_bb()
, CP::Shape#bb()
Updates and returns the bounding box of shape
and returns it.
void CP::Shape.reset_id_counter
Chipmunk keeps a counter so that every new shape is given a unique
hash value to be used in the spatial hash. Because this affects the
order in which the collisions are found and handled, you can reset
the shape counter every time you populate a space with new shapes.
If you don’t, there might be (very) slight differences in the
simulation.
CP::CircleShape.new(body, radius, offset)
body
is the body to attach the circle to, offset
is the offset
from the body’s center of gravity in body local coordinates.
CP::CircleShape#offset, CP::CircleShape#radius
Getters for circle shape properties.
CP::SegmentShape.new(body, veca, vecb, adius)
body
is the body to attach the segment to, veca
and vecb
are
the endpoints, and radius
is the thickness of the segment.
CP::SegmentShape#a(CP::Shape *shape), CP::SegmentShape#b(CP::Shape *shape), CP::SegmentShape#normal(CP::Shape *shape), CP::SegmentShape#radius(CP::Shape *shape)
Getters for segment shape properties. Passing a non-segment shape
will throw an assertion.
CP::PolyShape.new(body, verts, offset)
body
is the body to attach the poly to, verts
is an array of
CP::Vec2
objects defining a convex hull with a clockwise winding,
offset
is the offset from the body’s center of gravity in body
local coordinates. An assertion will be thrown the vertexes are not
convex or do not have a clockwise winding.
CP::PolyShape.num_verts, CP::PolyShape.vert(index)
Getters for poly shape properties. Passing an index that does not
exist will return nil.
CP::centroid_for_poly(verts) TODO!
Calculate the centroid for a polygon.
void CP::recenter_poly(verts)
Center a polygon to (0,0). Subtracts the centroid from each vertex.
The short answer is that you can’t because the changes would be only picked up as a change to the position of the shape’s surface. The long answer is that you can't because the unsafe C api that would allow you to do this is not wrapped in these Ruby binding.
- You can attach multiple collision shapes to a rigid body. This should allow you to create almost any shape you could possibly need.
- Shapes attached to the same rigid body will never generate collisions. You don’t have to worry about overlap when attaching multiple shapes to a rigid body.
- The amount of elasticity applied during a collision is determined by multiplying the elasticity of both shapes together. The same is done for determining the friction. If you want to override this default behavior, you can do so inside of a preSolve collision callback. See the Chipmunk Callbacks section for more information.
- Make sure you add both the body and it’s collision shapes to a space. The exception is when you want to have a static body or a body that you integrate yourself. In that case, only add the shape.
Spaces in Chipmunk are the basic unit of simulation. You add rigid bodies, shapes and constraints to it and then step them forward through time.
Chipmunk uses an iterative solver to figure out the forces between objects in the space. What this means is that it builds a big list of all of the collisions, joints, and other constraints between the bodies and makes several passes over the list considering each one individually. The number of passes it makes is the iteration count, and each iteration makes the solution more accurate. If you use too many iterations, the physics should look nice and solid, but may use up too much CPU time. If you use too few iterations, the simulation may seem mushy or bouncy when the objects should be solid. Setting the number of iterations lets you balance between CPU usage and the accuracy of the physics. Chipmunk’s default of 10 iterations is sufficient for most simple games.
Rogue bodies are bodies that have not been added to the space, but are referenced from shapes or joints. Rogue bodies are a common way of controlling moving elements in Chipmunk such as platforms. As long as the body’s velocity matches the changes to it’s position, there is no problem with doing this. Most games will not need rogue bodies however.
In previous versions, Chipmunk used infinite mass rogue bodies to attach static shapes to. Creating and maintaining your own body for this is no longer necessary in C as each space has it’s own body for attaching static shapes to.
This body is marked as being a static body. A static body allows other objects resting on or jointed to it to fall asleep even though it does not fall asleep itself.
In Ruby, however, it might be a good idea to use your own static
shapes, as the built-in static Shape of the Space is not so useful.
Additional static bodies can be created using
CP::StaticBody.new()
or CP::Body.new_static()
. Objects resting
on or jointed to rogue bodies can never fall asleep. This is
because the purpose of rogue bodies are to allow the programmer to
move or modify them at any time. Without knowing when they will
move, Chipmunk has to assume that objects cannot fall asleep when
touching them.
Chipmunk optimizes collision detection against shapes that do not move. There are two ways that Chipmunk knows a shape is static.
The first is automatic. When adding or removing shapes attached to
static bodies, Chipmunk knows to handle them specially and you just
use the same functions as adding regular dynamic shapes,
CP::Space.add_shape()
and CP::Space.remove_shape()
.
The second way is to explicitly tag shapes as static using
CP::Space.add_static_shape()
. This is rarely needed, but say for
instance that you have a rogue body that seldomly moves. In this
case, adding a shape attached to it as a static shape and updating
it only when the body moves can increase performance. Shapes added
this way must be removed by calling
CP::Space.remove_static_shape()
.
Because static shapes aren’t updated automatically, you must let
Chipmunk know that it needs to update the static shapes. You can
update all of the static shapes at once using
CP::Space#rehash_static()
or individual shapes using
CP::Space#rehash_shape
. If you find yourself rehashing static
bodies often, you should be adding them normally using
CP::Space#add_shape
instead.
New in Chipmunk 5.3 is the ability of spaces to disable entire
groups of objects that have stopped moving to save CPU time as well
as battery life. In order to use this feature you must do 2 things.
The first is that you must attach all your static geometry to
static bodies. Objects cannot fall asleep if they are touching a
non-static rogue body even if it’s shapes were added as static
shapes. The second is that you must enable sleeping explicitly by
choosing a time threshold value for
CP::Space#sleep_time_threshold
. If you do not set
CP::Space#idle_speed_threshold
explicitly, a value will be chosen
automatically based on the current amount of gravity.
iterations
– Fixnum
: Allow you to control the accuracy of the
solver. Defaults to 10. See the section on iterations above for an
explanation.
gravity
– CP::Vec2
: Global gravity applied to the space.
Defaults to CP::vzero
. Can be overridden on a per body basis by
writing custom integration functions.
damping
– Float
: Amount of viscous damping to apply to the
space. A value of 0.9 means that each body will lose 10% of it’s
velocity per second. Defaults to 1. Like gravity
can be
overridden on a per body basis.
idle_speed
– Float
: 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.
sleep_time
– Float
: Time a group of bodies must remain idle in
order to fall asleep. The default value of INFINITY
disables the
sleeping algorithm.
CP::Space.new()
Returns a new Space object.
CP::Space#add_shape(shape) void CP::Space#add_static_shape(sape) void CP::Space#add_body(body) void CP::Space#add_constraint(constraint) void CP::Space#remove_shape(shape) void CP::Space#remove_static_shape(shape) void CP::Space#remove_body(body) void CP::Space#remove_constraint(constraint)
These functions add and remove shapes, bodies and constraints from
space
. See the section on Static Shapes above for an explanation
of what a static shape is and how it differs from a normal shape.
Also, you cannot call the any of these functions from within a
callback other than a post-step callback (which is different than a
post-solve callback!). Attempting to add or remove objects from the
space while CP::Space#step
is still executing will throw an
assertion. See the callbacks section for more
information.
void CP::Space#activate_touching(shape)
Perform a query for all shapes touching shape
and call
CP::Body#activate
on them. This is useful when you need to move a
shape explicitly. Waking shapes touching the moved shape prevents
objects from sleeping when the floor is moved or something similar.
You only need to do this when changing the shape of an existing
shape or moving a static shape. Most other methods of moving a
shape automatically would wake up other touching objects.
Chipmunk uses a spatial hash to accelerate it’s collision detection. While it’s not necessary to interact with the hash directly. The current API does expose some of this at the space level to allow you to tune it’s performance.
void CP::Space#resize_static_hash(dim, count) CP::Space#resize_active_hash(dim, count)
The spatial hash data structures used by Chipmunk’s collision
detection are fairly size sensitive. dim
is the size of the hash
cells. Setting dim
to the average collision shape size is likely
to give the best performance. Setting dim
too small will cause
the shape to be inserted into many cells, setting it too low will
cause too many objects into the same hash slot.
count
is the suggested minimum number of cells in the hash
table. If there are too few cells, the spatial hash will return
many false positives. Too many cells will be hard on the cache and
waste memory. the Setting count
to ~10x the number of objects in
the space is probably a good starting point. Tune from there if
necessary. By default, dim
is 100.0, and count
is 1000. The new
demo program has a visualizer for the static hash. You can use this
to get a feel for how to size things up against the spatial hash.
Using the spatial has visualization in the demo program you can see
what I mean. The grey squares represent cells in the spatial hash.
The darker the cell, the more objects have been mapped into that
cell. A good dim
size is when your objects fit nicely into the
grid:
Notice the light grey meaning that each cell doesn’t have too many objects mapped onto it.
When you use too small a size, Chipmunk has to insert each object into a lot of cells. This can get expensive.
Notice that the grey cells are very small compared to the collision shapes.
When you use too big of a size, a lot of shapes will fit into each cell. Each shape has to be checked against every other shape in the cell, so this makes for a lot of unnecessary collision checks.
Notice the dark grey cells meaning that many objects are mapped
onto them.
CP::Space#rehash_static()
Rehashes the shapes in the static spatial hash. You must call this
if you move any static shapes or Chipmunk won’t update their
collision detection data.
CP::Space#rehash_shape(shape)
Update an individual static shape that has moved.
void CP::Space#step(dt)
Update the space for the given time step. Using a fixed time step
is highly recommended. Doing so will increase the efficiency of
the contact persistence, requiring an order of magnitude fewer
iterations and CPU usage.
- When removing objects from the space, make sure you remove any other objects that reference it. For instance, when you remove a body, remove the joints and shapes attached to it.
- The number of iterations, and the size of the time step determine the quality of the simulation. More iterations, or smaller time steps increase the quality. Keep in mind that higher quality also means higher CPU usage.
- Because static shapes are only rehashed when you request it,
it’s possible to use a much higher
count
argument toCP::Space.resize_static_hash(dim, count)
than toCP::Space.resize_active_hash(dom, count)
. Doing so will use more memory but can improve performance if you have a lot of static shapes.
A constraint is something that describes how two bodies interact with each other. (how they constrain each other) Constraints can be simple joints that allow bodies to pivot around each other like the bones in your body, or they can be more abstract like the gear joint or motors.
Constraints in Chipmunk are all velocity based constraints. This means that they act primarily by synchronizing the velocity of two bodies. A pivot joint holds two anchor points on two separate bodies together by defining equations that say that the velocity of the anchor points must be the same and calculating impulses to apply to the bodies to try and keep it that way. A constraint takes a velocity as it’s primary input and produces a velocity change as it’s output. Some constraints, (joints in particular) apply velocity changes to correct differences in positions. More about this in the next section.
A spring connected between two bodies is not a constraint. It’s very constraint-like as it creates forces that affect the velocities of the two bodies, but a spring takes distances as input and produces forces as it’s output. If a spring is not a constraint, then why do I have two varieties of spring constraints you ask? The reason is because they are damped springs. The damping associated with the spring is a true constraint that creates velocity changes based on the relative velocities of the two bodies it links. As it is convenient to put a damper and a spring together most of the time, I figured I might as well just apply the spring force as part of the constraint instead of having a damper constraint and having the user calculate and apply their own spring forces separately.
-
a
–CP::Body
: The first body that the constraint acts on. -
b
–CP::Body
: The second body that the constraint acts on. -
maxForce
–Float
: is the maximum force that the constraint can use to act on the two bodies. Defaults to INFINITY. -
biasCoef
–Float
: is the percentage of error corrected each step of the space. (Can cause issues if you don’t use a constant time step) Defaults to 0.1. -
maxBias
–Float
: is the maximum speed at which the constraint can apply error correction. Defaults to INFINITY. -
data
–Object
: The ruby bindings use this field internally, so it is not available for you use. It returnsself
, but that is not guaranteed. -
object
–Object
: A user definable data object. If you set this to point at the game object the shapes is for, then you can access your game object from Chipmunk callbacks.
To access properties of specific joint types, use the getter and
setter functions provided (ex: CP::PinJoint.anchr1
). See the
lists of properties for more information.
Joints in Chipmunk are not perfect. A pin joint can’t maintain the exact correct distance between it’s anchor points, nor can a pivot joint hold it’s anchor points completely together. Instead, they are designed to deal with this by correcting themselves over time. In Chipmunk 5, you have a fair amount of extra control over how joints correct themselves and can even use this ability to create physical effects that allow you to use joints in unique ways:
- Servo motors – Ex: open/close doors or rotate things without going over a maximum force.
- Winches – Pull one object towards another at a constant speed without going over a maximum force.
- Mouse manipulation – Interact with objects smoothly given coarse/shaky mouse input.
There are three public fields of CP::Constraint structs that
control the error correction, max_force
, max_bias
, and
bias_coef
. max_force
is pretty self explanatory, a joint or
constraint will not be able to use more than this amount of force
in order to function. If it needs more force to be able to hold
itself together, it will fall apart. max_bias
is the maximum
speed at which error correction can be applied. If you change a
property on a joint so that the joint will have to correct itself,
it normally does so very quickly. By setting a max_speed
you can
make the joint work like a servo, correcting itself at a constant
rate over a longer period of time. Lastly, bias_coef
is the
percentage of error corrected every step before clamping to a
maximum speed. You can use this to make joints correct themselves
smoothly instead of at a constant speed, but is probably the least
useful of the three properties by far.
Neither constraints or collision shapes have any knowledge of the other. When connecting joints to a body the anchor points don’t need to be inside of any shapes attached to the body and it often makes sense that they shouldn’t. Also, adding a constraint between two bodies doesn’t prevent their collision shapes from colliding. In fact, this is the primary reason that the collision group property exists.
CP::Constraint#impulse
Get the most recent impulse that constraint
applied. To convert
this to a force, divide by the timestep passed to
CP::Space#step()
.
CP::PinJoint.new(a, b, anchr1, anchr2)
a
and b
are the two bodies to connect, and anchr1
and
anchr2
are the anchor points (Vect2) on those bodies. The
distance between the two anchor points is measured when the joint
is created. If you want to set a specific distance, use the setter
function to override it.
PinJoint Attributes List
Name
Type
anchr1
CP::Vec2
anchr2
CP::Vec2
dist
Float
CP::SlideJoint.new(a, b, anchr1, anchr2, min, max)
a
and b
are the two bodies to connect, anchr1
and anchr2
are the anchor points on those bodies, and min
and max
define
the allowed distances of the anchor points.
Attributes List
Name
Type
anchr1
CP::Vec2
anchr2
CP::Vec2
Min
Float
Max
Float
CP::_pivot_joint *CP::_pivot_joint_alloc(void) CP::_pivot_joint *CP::_pivot_joint_init(CP::_pivot_joint *joint, CP::Body *a, CP::Body *b, CP::Vec2 pivot) CP::Constraint *CP::_pivot_joint_new(CP::Body *a, CP::Body *b, CP::Vec2 pivot) CP::Constraint *CP::_pivot_joint_new2(CP::Body *a, CP::Body *b, CP::Vec2 anchr1, CP::Vec2 anchr2)
a
and b
are the two bodies to connect, and pivot
is the point
in world coordinates of the pivot. Because the pivot location is
given in world coordinates, you must have the bodies moved into the
correct positions already. Alternatively you can specify the joint
based on a pair of anchor points, but make sure you have the bodies
in the right place as the joint will fix itself as soon as you
start simulating the space.
Attributes List
Name
Type
anchr1
CP::Vec2
anchr2
CP::Vec2
CP::GrooveJoint.new(a, *b, groove_a, groove_b, anchr2)
The groove goes from groov_a
to groove_b
on body a
, and the
pivot is attached to anchr2
on body b
. All coordinates are body
local.
Attributes List
Name
Type
anchr2
CP::Vec2
groove_a
CP::Vec2
groove_b
CP::Vec2
CP::DampedSpring.new(a, b, anchr1, anchr2, restLength, stiffness, damping)
Defined much like a slide joint. restLength
is the distance the
spring wants to be, stiffness
is the spring constant
(>Young’s modulus),
and damping
is how soft to make the damping of the spring.
Attributes List
Name
Type
anchr1
CP::Vec2
anchr2
CP::Vec2
rest_length
Float
stiffness
Float
damping
Float
CP::DampedRotarySpring.new(a, b, restAngle, stiffness, damping)
Like a damped spring, but works in an angular fashion. restAngle
is the relative angle in radians that the bodies want to have,
stiffness
and damping
work basically the same as on a damped
spring.
Attributes List
Name
Type
rest_angle
Float
stiffness
Float
damping
Float
CP::RotaryLimitJoint.new(a, b, min,max)
Constrains the relative rotations of two bodies. min
and max
are the angular limits in radians. It is implemented so that it’s
possible to for the range to be greater than a full revolution.
Attributes List
Name
Type
min
Float
max
Float
CCP::RatchetJoint.new(a, b, phase, ratchet);
Works like a socket wrench. ratchet
is the distance between
“clicks”, phase
is the initial offset to use when deciding where
the ratchet angles are.
Attributes List
Name
Type
angle
Float
phase
Float
ratchet
Float
CP::GearJoint.new(a, b, phase, ratio);
Keeps the angular velocity ratio of a pair of bodies constant.
ratio
is always measured in absolute terms. It is currently not
possible to set the ratio in relation to a third body’s angular
velocity. phase
is the initial angular offset of the two bodies.
Attributes List
Name
Type
Phase
Float
Ratio
Float
CP::SimpleMotor.new(a, b, Float rate);
Keeps the relative angular velocity of a pair of bodies constant.
rate
is the desired relative angular velocity. You will usually
want to set an force (torque) maximum for motors as otherwise they
will be able to apply a nearly infinite torque to keep the bodies
moving.
Attributes List
Name
Type
Rate
Float
- You can add multiple joints between two bodies, but make sure that they don’t fight. Doing so can cause the bodies jitter or spin violently.
In order to make collision detection in Chipmunk as fast as possible, the process is broken down into several stages. While I’ve tried to keep it conceptually simple, the implementation can be a bit daunting. Fortunately as a user of the library, you don’t need to understand everything about how it works. If you are trying to squeeze every ounce of performance out of Chipmunk, understanding this section is crucial.
The Chipmunk module CP contains a variables that control how collisions are solved. They can’t be set on a per space basis, but most games wont need to change them at all.
CP.bias_coef
Because Chipmunk does not perform swept collisions, shapes may
overlap. Each time you call CP::Space#step()
Chipmunk fixes a
percentage of the overlap to push the shapes apart. By default,
this value is set to 0.1. With this setting, after 15 steps the
overlap will be reduced to 20%, after 30 it will be reduced to 4%.
This is usually satisfactory for most games. Setting
CP::_bias_coef to 1.0 is not recommended as it will reduce the
stability of stacked objects.
CP.collision_slop
Chipmunk’s impulse solver works by caching the last solution as it
is likely to be very similar to the current one. In order to help
keep objects touching, Chipmunk allows objects to overlap a small
amount. By default this value is 0.1. If you are using pixel
coordinates you won’t even notice. If using a different scale,
adjust the value to be as high as possible without creating any
unwanted visual overlap.
CP.contact_persistence
This is how many steps the space should remember old contact
solutions. The default value is 3 and it’s unlikely that you’ll
need to change it.
Chipmunk uses a spatial hash for its broad phase culling. Spatial hashes are very efficient for a scene made up of consistently sized objects. It basically works by taking the axis aligned bounding boxes for all the objects in the scene, mapping them onto an infinite sized grid, then mapping those grid cells onto a finite sized hash table. This way, you only have to check collisions between objects in the same hash table cells, and mapping the objects onto the grid can be done fairly quickly. Objects in the same hash table cells tend to be very close together, and therefore more likely to be colliding. The downside is that in order to get the best performance out of a spatial hash, you have to tune the size of the grid cells and the size of the hash table so you don’t get too many false positives. For more information about tuning the hash see the CP::Space section.
Things to keep in mind:
- Using too small a grid size means that your objects will be split into many grid cells which means that the spatial hash will spend a lot of time filling empty hash cells for just one object and rarely finding any with multiple objects. Making the grid size too big means that you will be putting a lot of objects into a single hash cell, and collisions will have to be checked between all of them.
- Using too small of a hash table means that you will map too many far away objects into a single hash cell. Using too many means that the hash table will have to spend a lot of time doing clears and rehashes.
For more information on spatial hashing in general, Optimized Spatial Hashing for Collision Detection of Deformable Objects is a good paper that covers all the basics.
After the spatial hash figures out pairs of shapes that are likely to be near each other, it passes them back to the space to perform some additional filtering on the pairs. If the pairs pass all the filters, then Chipmunk will test if the shapes are actually overlapping. If the shape to shape collision check passes, then the collision handler callbacks are called. These tests are much faster to try than the shape to shape collision checks, so use these if you can to reject collisions early instead of rejecting them from callbacks if you can.
- Bounding Box Test: The shapes are not colliding if their bounding boxes are not overlapping. You can’t really affect this, but this is when it’s done.
- Layer Test: The shapes are not colliding if they don’t occupy and of the same layers. (the bitwise AND of their layer masks is 0)
- Group Test: Shapes shouldn’t collide with other shapes in the same non-zero group.
The most expensive test that you can do to see if shapes should collide is to actually check based on their geometry. Circle to circle and circle to line collisions are pretty quick. Poly to poly collisions get more expensive as the number of vertexes increases. Simpler shapes make for faster collisions (and more importantly fewer collision points for the solver to run).
After checking if two shapes overlap Chipmunk will look to see if you have defined a collision handler for the collision types of the shapes. This gives you a large amount of flexibility to process collisions events, but also gives you a very flexible way to filter out collisions.
The return value of the begin and pre_solve callbacks determines whether or not the colliding pair of shapes is discarded or not. Returning true will keep the pair, false will discard it. If you don’t define a handler for the given collision_types, Chipmunk will call the space’s default handler, which by default is defined to simply accept all collisions.
While using callbacks to filter collisions is the most flexible way, keep in mind that by the time your callback is called all of the most expensive collision detection has already been done. For simulations with a lot of colliding objects each frame, the time spent finding collisions is small compared to the time spent solving the physics for them so it may not be a big deal. Still, use layers or groups first if you can.
A physics library without any events or feedback would not be very useful for games. How would you know when the player bumped into an enemy so that you could take some health points away? How would you know how hard the car hit something so you don’t play a loud crash noise when a pebble hits it? What if you need to decide if a collision should be ignored based on specific conditions, like implementing one way platforms? Chipmunk has a number of powerful callback systems that you can plug into to accomplish all of that.
The ruby bindings support 2 types of collision handlers, namely a simple block, or a collision handler object.
A collision handler block is a block that takes either 0, 1, 2, or 3 arguments. These arguments may include the two colliding shapes, and an arbiter that describes the details of the collision. SeeCP::Arbiter for more info on arbiters.
Collision handler blocks are installed by calling
Space#add_collision_func(collision_type1, collision_type2) do ... end
.
Depending on the arity of the handler block, different arguments
will be passed:
Arguments passed Arity Signature Passed 0 do ... end No arguments passed. 1 do |arbiter| ... end Arbiter passed. 2 do |a,b|... end Colliding shapes a and b passed. 3 do |a,b,arbiter|... end Colliding shapes a and b, and arbiter passed. A collision handler block will be called in the pre_solve step of the collision detection. Return false from the callback to make Chipmunk ignore the collision this step or true to process it normally.
A collision handler object is an Object that responds_to? one or more of 4 distinct messages. Or, in other words, it's any object that has the one or more of 4 following methods for the different collision events that Chipmunk recognizes. The event types are:
-
begin
Two shapes just started touching for the first time this step. Return true from the callback to process the collision normally or false to cause Chipmunk to ignore the collision entirely. If you return false, the pre-solve and post-solve callbacks will never be run, but you will still recieve a separate event when the shapes stop overlapping. - pre_solve: Two shapes are touching during this step. Return false from the callback to make Chipmunk ignore the collision this step or true to process it normally. Additionally, you may override collision values such as CP::Arbiter.e and CP::Arbiter.u to provide custom friction or elasticity values. See CP::Arbiter for more info.
- post_solve: Two shapes are touching and their collision response has been processed. You can retrieve the collision force at this time if you want to use it to calculate sound volumes or damage amounts. See CP::Arbiter for more info.
- separate Two shapes have just stopped touching for the first time this step.
Depending on the arity of the mentioned methods, different arguments will be passed to them:
Arguments passed Arity Signature Passed 0 () No arguments passed. 1 (arbiter) Arbiter passed. 2 (a,b) Colliding shapes a and b passed. 3 (a,b,arbiter) Colliding shapes a and b, and arbiter passed. The following is and example of a valid Collision Handler Object:
`` class CollisionHandler def begin(a, b, arbiter) end
def pre_solve(a, b)
end
def post_solve(arbiter)
end
def separate
end
end
Collision callbacks are closely associated with CP::Arbiter structs. You should familiarize yourself with those as well.
Note: Shapes tagged as sensors (CP::Shape.sensor == true
)
never generate collisions that get processed so collisions between
sensors shapes and other shapes will never call the post-solve
callback. They still generate begin, and separate callbacks, and
the pre solve callback is also called every frame even though there
is no real collision.
CP::Space#add_collision_handler(collision_type_a, collision_type_b, collision_handler_object)
Add a collision handler for given collision type pair. Whenever a
shapes with collision type (Symbol
) a
and collision type b
collide, the callbacks defined on collision_handler_object
will
be used to process the collision.
CP::Space#add_collision_handler(collision_type_a, collision_type_b, &block)
Add a collision handler block for given collision type pair.
Whenever a shapes with collision type (Symbol
) a
and collision
type b
collide, the block will be called to process the
collision.
CP::Space#remove_collision_handler(collision_type a, collision_type b)
Remove a collision handler for a given collision type pair.
CP::Space.default_collision_handler(collision_type_a, collision_type_b,collision_handler_object), CP::Space.default_collision_handler(collision_type_a, collision_type_b,&collision_handler_block)
Register a default collision handler to be used when no specific
collision handler is found. The space is given a default handler
when created that returns true for all collisions in begin
and
pre_solve
and does nothing in the post_solve()
and separate()
callbacks.
Post-step callbacks are the one place where you can break the rules about adding or removing objects from within a callback. In fact, their primary function is to help you safely remove objects from the space that you wanted to disable or destroy in a collision callback.
Post step callbacks are registered as a function and a pointer that is used as a key. You can only register one post step callback per key. This prevents you from accidentally removing an object more than once. For instance, say that you get a collision callback between a bullet and object A. You want to destroy both the bullet and object A, so you register a post-step callback to safely remove them from your game. Then you get a second collision callback between the bullet and object B. You register a post-step callback to remove object B, and a second post-step callback to remove the bullet. Because you can only register one callback per key, the post-step callback for the bullet will only be called once and you can’t accidentally register to have it removed twice.
Note: Additional callbacks registered to the same key are ignored even if they use a different callback function or data pointer.
do |space, key| ... end
Block used for post step callbacks. space
is the space the
callback was registered on, key
is the pointer value you supplied
as the key
CP::Space.add_post_step_callback(key, &block)
Add block
to be called before CP::Space#step()
returns.
self (CP::Space)
and key (Object)
will be passed to your block,
which must have the signature do |space, key| ... end
. Only the
last callback registered for any unique value of key
will be
recorded. You can add post-step callbacks from outside of other
callback functions, but they won’t be called until
CP::Space#step()
is called again.
First of all, why are they called arbiters? The short answer is that Box2D called them that way back in 2006 when Scott Lembcke was looking at the source for it’s solver. An arbiter is like a judge, a person that has authority to settle disputes between two people. It was a fun, fitting name and was shorter to type than CollisionPair which he had been using. :p
Originally arbiters were going to be an internal data type that Chipmunk used that wouldn’t ever be sent to outside code. In Chipmunk 4.x and earlier, only a single callback hook was provided for handling collision events. It was triggered every step that to shapes were touching. This made it non-trivial to track when objects started and stopped touching as the user would have to record and process this themselves. Many people, including myself, wanted to get collision begin/separate events and eventually I realized that information was already being stored in the arbiter cache that the Chipmunk maintains. With some changes to the collision callback API, that information is now exposed to the user. Internally, arbiters are used primarily for solving collision impulses. To external users, you can simply think of them as a weird type used in collision callbacks.
You should never need to create an arbiter, nor will you ever need to free one as they are handled by the space. More importantly, because they are managed by the space you should never store a reference to an arbiter as you don’t know when they will be destroyed. Use them within the callback where they are given to you and then forget about them or copy out the information you need. This is even so in these Ruby bindings!
CP::Arbiter#shapes
Returns an array with the shapes in the order that they were
defined in the collision handler associated with this arbiter. If
you defined the handler as
CP::Space#add_collision_handler(space, 1, 2, ...)
, you you will
find that a.collision_type == 1
and b.collision_type == 2
.
int CP::Arbiter.first_contact?
Returns true if this is the first step that the shapes touched. You
can use this from pre_solve()
and post_solve()
callbacks to
know if a collision between two shapes is new without needing to
flag a boolean in your begin()
callback.
CP::Arbiter.count
CP::Arbiter.contacts
Returns the number of contact points in this arbiter.
CP::Arbiter.normal(i)
Returns the collision normal for the i’th contact point, flipping
it if necessary. Note: Currently due to how Chipmunk’s
collision detection is implemented, the collision normals will be
the same for all collision points. You can simply do
CP::Arbiter.normal(0)
and not have to check each contact point.
Note: calling this function from the separate()
callback is
undefined.
CP::Vec2 CP::Arbiter.point(i)
Returns the position of the i’th collision point. Note: calling
this function from the separate()
callback is undefined.
CP::Vec2 CP::Arbiter.depth(int i)
Returns the penetration depth of the i’th collision point.
CP::Vec2 CP::Arbiter.impulse(friction = nil)
Returns the impulse that was applied this step to resolve the
collision. These functions should only be called from a
post_step()
callback, otherwise the result is undefined.
Note: If you are using the deprecated elastic iterations
setting on your space, it will cause you to get incorrect results.
Elastic iterations should no longer be needed, and you should be
able to safely turn them off.
It’s unlikely that you’ll need to interact with a CP::Arbiter
struct directly as the collision helper functions should provide
most functionality that people will need. One exception is the e
,
and u
attributes. By default, Chipmunk multiplies the friction
and elasticity values of to shapes together to determine what
values to use when solving the collision. This mostly works, but in
many cases is simply not flexible enough. If you are running into
problems with that, you can change the values calculated for e
and u
in a preSolve callback. This is likely to change in the
next major version of Chipmunk.
-
contacts
–Fixnum
: Number of contact points for this collision. -
e
–Float
: Calculated amount of elasticity to apply for this collision. Can be overriden from apreSolve()
callback. -
u
–Float
: Calculated amount of friction to apply for this collision. Can be overriden from apreSolve()
callback. -
surface_v
–CP::Vec2
: Calculated amount of surface velocity to apply for this collision. Can be overriden from apre_solve()
callback. Very likely to change in the next major version of Chipmunk.
Chipmunk spaces currently support three kinds of spatial queries,
point, segment and bounding box. Any type can be done efficiently
against an entire space, or against individual shapes. All types of
queries take a collision group and layer that are used to filter
matches out using the same rules used for filtering collisions
between shapes. See CP::Shape for more information. If
you don’t want to filter out any matches, use CP::ALL_LAYERS
for
the layers and CP::NO_GROUP
as the group.
Point queries are useful for things like mouse picking and simple sensors.
CP::Shape.point_query(p)
Check if the given point (CP::Vec2) lies within the shape.
CP::Space.point_query(point,layers, group) do |shape| ... end
Query space
at point
filtering out matches with the given
layers
and group
. The given block is called for each shape
found with shape
as argument. Sensor shapes are included.
CP::Space.point_query_first(point, layers, group)
Query space
at point
and return the first shape found matching
the given layers
and group
. Returns nil
if no shape was
found. Sensor shapes are ignored.
Segment queries are like ray casting, but because Chipmunk uses a spatial hash to process collisions, it cannot process infinitely long queries like a ray. In practice this is still very fast and you don’t need to worry too much about the performance as long as you aren’t using extremely long segments for your queries.
CP::SegmentQueryInfo is a Ruby Struct with the following members: shape: shape that was hit, nil if no collision. t: Distance along query segment, will always be in the range 0..1 . n: Normal of hit surface.
Segment queries return more information than just a simple yes or
no, they also return where a shape was hit and it’s surface normal
at the hit point. t
is the percentage between the query start and
end points. If you need the hit point in world space or the
absolute distance from start, see the segment query helper
functions farther down.
CP::Shape.segment_query(a, b)
Check if the line segment from a
to b
intersects the shape.
Returns a CP::SegmentQueryInfo struct with the results of the
query.
CP::Space#segment_query(start, stop, layers, group) do |shape, t, n|
Query space
along the line segment from start
to stop
filtering out matches with the given layers
and group
. The
block is called with the shape found, the normalized distance along
the line and surface normal for each shape found. Sensor shapes are
included.
CP::Space#segment_query_first(start, stop, layers, group)
Query space
along the line segment from start
to stop
filtering out matches with the given layers
and group
. Only the
first shape encountered is returned and the search is short
circuited. Returns nil
if no shape was found. Otherwise returns a
CP::SegmentQueryInfo struct with the results of the query. Sensor
shapes are ignored.
CP::SegmentQueryInfo#hit_point(start, stop)
Return the hit point in world coordinates where the segment first
intersected with the shape.
CP::SegmentQueryInfo#hit_dist(start, stop)
Return the absolute distance where the segment first hit the shape.