Source code for serge.physical

"""Classes to help with physical body interaction"""

from common import pymunk
import serialize

class InvalidDimensions(Exception): """The dimensions specified for conditions were inconsistent"""
class InvalidMass(Exception): """Must be either fixed or have a mass"""


[docs]class PhysicalConditions(serialize.Serializable): """Represents physical parameters of an object This includes the mass, velocity, force applied, acceleration and the physical dimensions. """ my_properties = ( serialize.F('mass', 0.0, 'the mass of the object'), serialize.L('velocity', (0.0,0.0), 'the velocity of the object'), serialize.L('force', (0.0,0.0), 'the force on the object'), serialize.F('radius', 0.0, 'the radius of the object'), serialize.F('width', 0.0, 'the width of the object'), serialize.F('height', 0.0, 'the height of the object'), serialize.F('friction', 0.1, 'the friction the object'), serialize.F('elasticity', 1.0, 'the elasticity of the object'), serialize.I('layers', 0, 'the collision layers that we are in'), serialize.I('group', 0, 'the collision group that we are in'), serialize.B('fixed', False, 'whether the object is fixed in place'), serialize.B('update_angle', False, 'whether the rotation of the body should propagate to the actors visual'), serialize.B('visual_size', False, 'whether to set the size based on the visual element of our parent actor'), ) def __init__(self, mass=0.0, radius=0.0, velocity=(0.0, 0.0), force=(0.0, 0.0), width=0.0, height=0.0, fixed=False, friction=0.1, elasticity=1.0, group=0, layers=-1, update_angle=False, visual_size=False): """Initialise the conditions""" self.body = None if not mass and not fixed: raise InvalidMass('Mass must be specified unless the object is fixed in place') self.mass = mass if not fixed else pymunk.inf self.velocity = velocity self.force = force self.fixed = fixed self.friction = friction self.elasticity = elasticity self.update_angle = update_angle self.visual_size = visual_size self.group = group self.layers = layers self.space = None if not visual_size: self.setGeometry(radius, width, height)
[docs] def init(self): """Initialize from serialized form""" super(PhysicalConditions, self).init() self.setGeometry(self.radius, self.width, self.height) self._createPhysicsObject()
[docs] def setGeometry(self, radius=None, width=None, height=None): """Set the geometry You must specify either the radius or the width and height """ # # Reality check if radius and (width or height): raise InvalidDimensions('Must specify radius or width & height, not both') elif not radius and not (width and height): raise InvalidDimensions('Must specify width & height') # if radius: self.geometry_type = 'circle' else: self.geometry_type = 'rectangle' self.radius = radius self.width = width self.height = height self._createPhysicsObject()
def _createPhysicsObject(self): """Return a new physics object""" if self.geometry_type == 'circle': inertia = pymunk.moment_for_circle(self.mass, 0, self.radius, (0,0)) else: inertia = pymunk.moment_for_box(self.mass, self.width, self.height) # body = pymunk.Body(self.mass, inertia) body.velocity = self.velocity body.force = self.force # if self.geometry_type == 'circle': shape = pymunk.Circle(body, self.radius, (0,0)) else: #shape = pymunk.Poly(body, [(0, 0), (self.width, 0), # (self.width, self.height), (0, self.height)]) w2, h2 = self.width/2, self.height/2 shape = pymunk.Poly(body, [(-w2,-h2), (+w2, -h2), (+w2, +h2), (-w2, +h2)]) # shape.elasticity = self.elasticity shape.collision_type = 2 shape.group = self.group shape.layers = self.layers shape.friction = self.friction self.shape = shape self.body = body
[docs] def updateFrom(self, physical_conditions): """Update the properties and our physics object""" self.velocity = physical_conditions.velocity self.force = physical_conditions.force self.body.velocity = self.velocity self.body.force = self.force
[docs]class PhysicalBody(PhysicalConditions): """Physical conditions for an infinitesimal object The object has no dimensions (shape) but still has mass etc. """ def __init__(self, mass, **kw): """Initialise the body""" # # We create a body with a default shape but we will remove the shape from play # later super(PhysicalBody, self).__init__(mass, radius=0.1, **kw) def _createPhysicsObject(self): """Create the object This is where we remove the shape from play so that it doesn't interact with anything. """ super(PhysicalBody, self)._createPhysicsObject() self.shape = None