The Cymunk Module

These classes have cdefed functions that cannot be read by Sphinx. Read the source if you want to find out more about using them.

This module extends the base functionality of KivEnt by integrating it with the Chipmunk2d Physics engine. This will allow you to perform complex collision detection and real-time 2d physics calculations on large numbers of entities simultaneously.

Physics

class kivent_cymunk.physics.PhysicsComponent

The PhysicsComponent mainly exposes the ability to retrieve cymunk objects. You will want to review the documentation for the various parts of cymunk (and Chipmunk2D’s documentation) to properly use this system.

Attributes:

entity_id (unsigned int): The entity_id this component is currently associated with. Will be <unsigned int>-1 if the component is unattached.

body (Body): returns the cymunk.Body for your physics component. Only set this if you are handling the adding and removal of your physics body from the cymunk.Space yourself.

unit_vector (tuple): Returns the current unit_vector describing the heading of your physics body. Does not support setting only getting.

shapes (list): Returns a list of the shapes attached to the body. Be careful when setting to appropriately handle the shapes being added or removed from the body.

shape_type (str): The type of shape this components body was initialized with. Only set if you have been modifying your body manually and you know what you’re doing.

class kivent_cymunk.physics.CymunkPhysics(**kwargs)

Processing Depends On: PositionSystem2D, RotateSystem2D, CymunkPhysics

CymunkPhysics is a GameSystem that interacts with the Cymunk Port of the Chipmunk2d Physics Engine. Check the docs for Chipmunk2d to get an overview of how to work with Cymunk.

This GameSystem is dependent on the PositionComponent2D and RotateComponent2D in addition to its own component. It will write out the position and rotation of the cymunk.Body associated with your entity every frame to these components.

Attributes:

space (ObjectProperty): The Cymunk Space the physics system is using

gravity (ListProperty): The (x, y) gravity vector for the space.

iterations (NumericProperty): Number of solving iterations for the Space

sleep_time_threshold (NumericProperty): How long a Body is inactive in order to be slept in the space

collision_slop (NumericProperty): Collision_slop for the Space; i.e. how much collisions can overlap.

damping (NumericProperty): Damping for the Space. This is sort of like a global kind of friction. All velocities will be reduced to damping*initial_velocity every update tick.

add_collision_handler(self, int type_a, int type_b, begin_func=None, pre_solve_func=None, post_solve_func=None, separate_func=None)
Args:

type_a (int): the collision_type for the first Shape in the collision

type_b (int): the collision_type for the second Shape in the collision

Kwargs:

begin_func (function): called (once) when collision between 2 shapes first begins

pre_solve_func (function): called before every solve of the physics space where a collision persists

post_solve_func (function): called after every solve of the physics space where a collision persists

separate_func (function): called (once) when collision between 2 shapes ends.

Function to add collision handlers for collisions between pairs of collision_type. Collision functions for begin_func and pre_solve_func should return True if you want the collision to be solved, and False if you want the collisions to be ignored

Functions should accept args: space, arbiter You can then retrieve the entity_id‘s of the colliding shapes with:

first_id = arbiter.shapes[0].body.data
second_id = arbiter.shapes[1].body.data
clear_component(self, unsigned int component_index)
create_component(self, unsigned int entity_id, str zone_name, args)
init_component(self, unsigned int component_index, unsigned int entity_id, str zone_name, dict args)

Args:

args (dict): dict containing the kwargs required in order to initialize a Cymunk Body with one or more Shape attached. Shape types supported are ‘box’, ‘circle’, ‘poly’, and ‘segment’.

The args dict looks like:

args = {
    'entity_id': id,
    'main_shape': string_shape_name,
    'velocity': (x, y),
    'vel_limit': float,
    'position': (x, y),
    'angle': radians,
    'angular_velocity': radians,
    'ang_vel_limit': float,
    'mass': float,
    'col_shapes': [col_shape_dicts],
    'moment': float
    }

moment (if not specified) will be computed from component shapes

The col_shape_dicts look like:

col_shape_dict = {
    'shape_type': string_shape_name,
    'elasticity': float,
    'collision_type': int,
    'shape_info': shape_specific_dict
    }

shape_info dicts looke like this, depending on their shape:

box = {
    'width': float,
    'height': float,
    'mass': float
    }

circle = {
    'inner_radius': float,
    'outer_radius': float,
    'mass': float,
    'offset': (float, float)
    }

poly = {
    'mass': float,
    'vertices': list,
    'offset': (float, float)}

segment = {
    'mass': float,
    'a': (float, float),
    'b': (float, float),
    'radius': float (beveling radius for segment),
    }

If you want a solid circle set inner_radius to 0.
init_physics(self)

Internal function that handles initalizing the Cymunk Space

on_damping(self, instance, value)

Event handler that sets the damping of space.

on_gravity(self, instance, value)

Event handler that sets the gravity of space.

query_bb(self, list box_to_query, ignore_groups=[])
Args:
box_to_query (list): should be a list of [x, y, x+w, y+h] where x, y is the bottom left hand corner of the box, and w, h is the width and height of the box.
Kwargs:
ignore_groups (list): list of collision_types to ignore during this query.

Queries collisions inside a box.

query_segment(self, vect_start, vect_end)
Args:

vect_start (tuple): (x1, y1) start point of segment.

vect_end (tuple): (x2, y2) end point of segment.

Queries collisions between (x1, y1) and (x2, y2)

register_collision_type(self, str type_name)
remove_component(self, unsigned int component_index)
update(self, dt)

Handles update of the cymunk space and updates the component data for position and rotate components.

Interaction

class kivent_cymunk.interaction.CymunkTouchComponent

The CymunkTouchComponent keeps track of a PivotJoint and a Body that has not been added to the cymunk Space in order to control physics objects actually added to the world. The PivotJoint is bound to the touch_body of this component and the Body of the touched Entity.

Attributes:

entity_id (unsigned int): The entity_id this component is currently associated with. Will be <unsigned int>-1 if the component is unattached.

touch_body (Body): This is a rogue body (unattached to the space) that influences another Body through a cymunk.constraint interaction.

pivot (PivotJoint): The constraint that acts on this body and the one it is attached to.

max_force (float): Maximum force the joint can exert on the attached body.

error_bias (float): The rate at which the joint is corrected.

class kivent_cymunk.interaction.CymunkTouchSystem

Processing Depends On: PositionSystem2D, CymunkTouchSystem

The CymunkTouchSystem provides a way to interact with the entities in a CymunkPhysics GameSystem, either through touches or mouse clicks. Touched entities will be ‘dragged’. This system will generate new entities when receiving an on_touch_down event that collides with an entity in the space of the CymunkPhysics GameSystem with system_id: physics_system.

The entities will be generated in zone zone_to_use so make sure to set this up appropriately. This zone should not need more than 100 entities unless you are planning on receiving very many simultaneous touches.

This system will be dependent on its own component and a PositionComponent2D (default system_id: ‘position’) for processing.

Attributes:

physics_system (StringProperty): Name (system_id) of the physics system to use with this system. Defaults to ‘cymunk_physics’.

touch_radius (NumericProperty): Size of the touch query to see which entities we are touching. Defaults to 20.

max_force (NumericProperty): Maximum force the PivotJoint will be able to exert. Defaults to 2500000.

max_bias (NumericProperty): The rate at which the joints for touch entities will be corrected. Defaults to 10000.

ignore_groups (ListProperty): List of collision_type (int) to ignore when performing the collision query in on_touch_down. Defaults to [].

zone_to_use (StringProperty): Name of the zone to create entities in. Defaults to ‘touch’.

clear_component(self, unsigned int component_index)

Clears the component at component_index. We must set the pointers in the C struct to empty and the references in the CymunkTouchComponent to None.

Args:

component_index (unsigned int): Component to remove.
init_component(self, unsigned int component_index, unsigned int entity_id, str zone, dict args)

The entities for this system are typically generated by its on_touch_down event. However, if you do need to create a component the args dict looks like:

You will also definitely want to look over how this GameSystem manipulates its components in the on_touch_down, on_touch_move, and on_touch_up event handling.

Args:

component_index (unsigned int): Index of the component to be initialized.

entity_id (usigned int): Identity of the entity we will be adding this component to.

zone (str): Name of the zone this entities memory will use.

args (dict): Contains the arguments for creating the PivotJoint. Described below.

Args dict looks like:

args = {
    'touch_pos': (float, float),
    #Tuple of the position this touch is occuring at

    'touched_ent': (unsigned int),
    #The id of the entity that was touched.

    'max_bias': float,
    #The error correction rate for this connection

    'max_force': float,
    #The maximum amount of force this joint can generate.
    }
on_touch_down(self, touch)

The touch down handling for the CymunkTouchSystem queries the CymunkPhysics GameSystem with system_id: physics_system to see if any touches occur withtin a square of x +- touch_radius, y +- touch_radius.

If we do collide with an entity, we will take the first one and bind a new rogue body (unattached from the physics Space) together with the touched entity’s physics Body by creating a PivotJoint. The new entity representing the PivotJoint will be created in zone: zone_to_use.

on_touch_move(self, touch)

The touch move handling keeps track of the touch entity generated in on_touch_down, updating its position to the new position of the touch.

on_touch_up(self, touch)

On touch up, if we have previously set the ud[‘ent_id’] in on_touch_down we will remove this entity from the GameWorld as the touch is now over.

remove_component(self, unsigned int component_index)

Before we clear the component we perform some cleanup on the physics objects, removing the _pivot PivotJoint from our Space. We also remove our entity from the entity_components aggregator at this time.

Args:

component_index (unsigned int): Component to remove.
update(self, float dt)