import pygame import pymunk import math from pyphysicssandbox import pin from pyphysicssandbox import win_width from pyphysicssandbox import win_height from pyphysicssandbox import space from pyphysicssandbox import add_observer class BaseShape: next_collision_type = 0 def __init__(self, cosmetic=False): self._cosmetic = cosmetic if cosmetic: self.body = None self.shape = [] else: self.body.custom_gravity = space.gravity self.body.custom_damping = space.damping self.body.constant_velocity = None self.elasticity = 0.90 self.friction = 0.6 self._color = pygame.Color('black') self._wrap_x = False self._wrap_y = False self._active = True self._visible = True self._debug = False self.custom_velocity_func = False BaseShape.next_collision_type += 1 self._collision_type = BaseShape.next_collision_type if type(self.shape) is list: for shape in self.shape: shape.collision_type = BaseShape.next_collision_type else: self.shape.collision_type = BaseShape.next_collision_type add_observer(self.observer) def observer(self, keys): if self._debug: print (repr(self)) def hit(self, direction, position): if self._cosmetic: return self.body.apply_impulse_at_world_point(direction, position) def has_own_body(self): return not self._cosmetic def inside(self, p): mask = pygame.Surface((win_width, win_height)) color = self.color self.color = pygame.Color('white') self._draw(mask) self.color = color mask.lock() pixel = mask.get_at(p) mask.unlock() return pixel == pygame.Color('white') def draw(self, screen): if self.visible: self._draw(screen) def paste_on(self, other_shape): p1, p2 = self._pin_points() pin(p1, self, p1, other_shape).visible = False pin(p2, self, p2, other_shape).visible = False @property def active(self): return self._active def deactivate(self): self._active = False if type(self.shape) is list: for s in self.shape: space.remove(s) if self.has_own_body(): space.remove(self.body) else: if self.has_own_body(): space.remove(self.shape, self.body) else: space.remove(self.shape) def reactivate(self): self._active = True if type(self.shape) is list: for s in self.shape: space.add(s) if self.has_own_body(): space.add(self.body) else: if self.has_own_body(): space.add(self.shape, self.body) else: space.add(self.shape) @property def angle(self): if self.body: return -math.degrees(self.body.angle) return 0.0 @angle.setter def angle(self, value): if type(value) == float or type(value) == int: self.body.angle = math.radians(-value) else: print("Angle value must be a number") @property def debug(self): return self._debug @debug.setter def debug(self, value): if type(value) == bool: self._debug = value else: print("Debug value must be a boolean") @property def position(self): if self.body: return self.body.position return pymunk.vec2d.Vec2d(self._x, self._y) @position.setter def position(self, value): if type(value) == tuple and len(value) == 2: if self.body: self.body.position = value else: self._x = value.x self._y = value.y else: print("Position value must be a (x, y) tuple") @property def surface_velocity(self): if type(self.shape) is list: return self.shape[0].surface_velocity return self.shape.surface_velocity @surface_velocity.setter def surface_velocity(self, value): if type(value) == tuple and len(value)==2: if type(self.shape) is list: for shape in self.shape: shape.surface_velocity = value else: self.shape.surface_velocity = value else: print("Surface velocity value must be a (x, y) tuple") @property def elasticity(self): if type(self.shape) is list: return self.shape[0].elasticity return self.shape.elasticity @elasticity.setter def elasticity(self, value): if type(value) == float: if type(self.shape) is list: for shape in self.shape: shape.elasticity = value else: self.shape.elasticity = value else: print("Elasticity value must be a floating point value") @property def collision_type(self): return self._collision_type @property def friction(self): if type(self.shape) is list: return self.shape[0].friction return self.shape.friction @friction.setter def friction(self, value): if type(value) == float: if type(self.shape) is list: for shape in self.shape: shape.friction = value else: self.shape.friction = value else: print("Friction value must be a floating point value") @property def wrap(self): return self._wrap_x or self.wrap_y @wrap.setter def wrap(self, value): if type(value) == bool: self._wrap_x = value self._wrap_y = value else: print("Wrap value must be True or False") @property def wrap_x(self): return self._wrap_x @wrap_x.setter def wrap_x(self, value): if type(value) == bool: self._wrap_x = value else: print("Wrap value must be True or False") @property def wrap_y(self): return self._wrap_y @wrap_y.setter def wrap_y(self, value): if type(value) == bool: self._wrap_y = value else: print("Wrap value must be True or False") @property def visible(self): return self._visible @visible.setter def visible(self, value): if type(value) == bool: self._visible = value else: print("Visible value must be True or False") @property def color(self): return self._color @color.setter def color(self, value): if type(value) == pygame.Color: self._color = value else: print("Color value must be a Color instance") @property def group(self): if type(self.shape) is list: return self.shape[0].filter.group return self.shape.filter.group @group.setter def group(self, value): if type(value) == int: if type(self.shape) is list: for shape in self.shape: shape.filter = pymunk.ShapeFilter(group=value) else: self.shape.filter = pymunk.ShapeFilter(group=value) else: print("Group value must be an integer") def _check_velocity_func(self): if not self.custom_velocity_func: self.custom_velocity_func = True self.body.velocity_func = adjust_velocity @property def gravity(self): if self._cosmetic: return 0, 0 return self.body.custom_gravity @gravity.setter def gravity(self, value): if self._cosmetic: return if type(value) == tuple and len(value) == 2: self.body.custom_gravity = value self._check_velocity_func() else: print("Gravity value must be a (x, y) tuple") @property def damping(self): if self._cosmetic: return 0, 0 return self.body.custom_damping @damping.setter def damping(self, value): if self._cosmetic: return if type(value) == float: self.body.custom_damping = value self._check_velocity_func() else: print("Damping value must be a float") @property def velocity(self): if self._cosmetic: return 0, 0 return self.body.custom_velocity @velocity.setter def velocity(self, value): if self._cosmetic: return if type(value) == tuple and len(value) == 2: self.body.constant_velocity = value self._check_velocity_func() else: print("Velocity value must be an x,y tuple") def adjust_velocity(body, gravity, damping, dt): if body.constant_velocity: body.velocity = body.constant_velocity return return body.update_velocity(body, body.custom_gravity, pow(body.custom_damping, dt), dt)