def createShape(self, verticies): assert len(verticies) >= 2 verticies = self.verticies = map(Vec2d, verticies) if is_clockwise(verticies): # fix it if it is clockwise average = sum(verticies) / len(verticies) verticies.sort(key=lambda v: (average-v).get_angle()) assert not is_clockwise(verticies), 'OMG, my code is wrong! the poly points are still clockwise' assert is_convex(verticies), 'Shape verticies must be convex!' if len(verticies) in self.specialPolyTypes: self.polyType = self.specialPolyTypes[len(verticies)] else: self.polyType = pg.GL_POLYGON self.shape = Poly(self.body, verticies) # note: collisionLayers and collisionType get created by physics.py self.shape.layers = self.collisionLayers self.shape.collision_type = self.collisionType self.shapes = [self.shape] bb = self.shape.cache_bb() self.size = Vec2d(bb.right-bb.left, bb.top-bb.bottom)
def __init__(self, body, vertices, offset=(0,0), auto_order_vertices=True): """Create a polygon body : `Body` The body to attach the poly to vertices : [(x,y)] or [`Vec2d`] Define a convex hull of the polygon with a counterclockwise winding. offset : (x,y) or `Vec2d` The offset from the body's center of gravity in body local coordinates. auto_order_vertices : bool Set to True to automatically order the vertices. If you know the vertices are in the correct (clockwise) orded you can gain a little performance by setting this to False. """ self._body = body self.offset = offset #self.verts = (Vec2d * len(vertices))(*vertices) self.verts = (Vec2d * len(vertices)) self.verts = self.verts(Vec2d(0, 0)) i_vs = enumerate(vertices) if auto_order_vertices and not u.is_clockwise(vertices): i_vs = zip(xrange(len(vertices)-1, -1, -1), vertices) for (i, vertex) in i_vs: self.verts[i].x = vertex[0] self.verts[i].y = vertex[1] self._shape = cp.cpPolyShapeNew(body._body, len(vertices), self.verts, offset) self._shapecontents = self._shape.contents
def draw_poly(self, poly): body = poly.body ps = poly.get_vertices() ps.append(ps[0]) ps = list(map(self.flipyv, ps)) if u.is_clockwise(ps): color = THECOLORS["green"] else: color = THECOLORS["red"] pygame.draw.lines(self.screen, color, False, ps)
def draw_poly(self, poly): body = poly.body ps = [p.rotated(body.angle) + body.position for p in poly.get_vertices()] ps.append(ps[0]) ps = list(map(self.flipyv, ps)) if u.is_clockwise(ps): color = THECOLORS["green"] else: color = THECOLORS["red"] pygame.draw.lines(self.screen, color, False, ps)
def assert_valid(verts): if len(verts) < 3: raise TypeError('need 3 or more verts: %s' % (verts,)) if not is_convex(verts): raise TypeError('not convex: %s' % (verts,)) if area(verts) == 0.0: raise TypeError("colinear: %s" % (verts,)) # note: pymunk considers y-axis points down, ours points up, # hence we consider pymunk's 'clockwise' to be anticlockwise if not is_clockwise(verts): raise TypeError('anticlockwise winding: %s' % (verts,))
def add_poly(self, points, density=0.1, friction=2.0, elasticity=0.3): """ Mass will be calculated out of mass = A * density Parameter: points == [(int(x), int(y)), (int(x), int(y)), ...] Optional: See #physical_parameters Returns: pymunk.Shape() (=> .Poly()) """ # Make Vec2d's out of the points poly_points = [] for p in points: poly_points.append(self.Vec2df(p)) # Reduce polygon points poly_points = util.reduce_poly(poly_points) if len(poly_points) < 3: return False # Make a convex hull poly_points = util.convex_hull(poly_points) # Make it counter-clockwise if not util.is_clockwise(poly_points): poly_points.reverse() # Change vectors to the point of view of the center poly_points_center = util.poly_vectors_around_center(poly_points) U, A = util.get_poly_UA(poly_points_center) A *= 2.5 # get_poly_UA is not working properly with the area :) mass = A * density # Calculate A Good Momentum moment = pm.moment_for_poly(mass, poly_points_center, Vec2d(0,0)) # Create Body body = pm.Body(mass, moment) center = cx, cy = util.calc_center(poly_points) body.position = Vec2d((cx, cy)) # Create Shape shape = pm.Poly(body, poly_points_center, Vec2d(0,0)) shape.friction = friction shape.elasticity = elasticity shape.color = self.get_color() shape.color2 = self.get_color() # Append to Space self.space.add(body, shape) self.element_count += 1 return shape
def loop(self): for event in pygame.event.get(): if event.type == QUIT: self.running = False elif event.type == KEYDOWN and event.key == K_ESCAPE: self.running = False elif event.type == KEYDOWN and event.key == K_p: pygame.image.save(self.screen, "playground.png") elif event.type == MOUSEBUTTONDOWN and event.button == 1: # LMB if pygame.key.get_mods() & KMOD_SHIFT: p = self.flipyv(Vec2d(event.pos)) self.polys.append(self.create_box(pos = p)) else: #t = -10000 p = self.flipyv(Vec2d(event.pos)) self.balls.append(self.create_ball(p)) elif event.type == MOUSEBUTTONDOWN and event.button == 3: #RMB if pygame.key.get_mods() & KMOD_SHIFT: pass elif pygame.key.get_mods() & KMOD_CTRL: p = self.flipyv(Vec2d(event.pos)) self.wall_points.append(p) elif self.shape_to_remove is not None: self.balls = filter(lambda a: a != self.shape_to_remove, self.balls) self.walls = filter(lambda a: a != self.shape_to_remove, self.walls) self.polys = filter(lambda a: a != self.shape_to_remove, self.polys) self.space.remove(self.shape_to_remove.body, self.shape_to_remove) elif event.type == KEYUP and event.key in (K_RCTRL, K_LCTRL): ### Create Wall self.create_wall_segments(self.wall_points) self.wall_points = [] elif event.type == KEYUP and event.key in (K_RSHIFT, K_LSHIFT): ### Create Polygon if len(self.poly_points) > 0: self.poly_points = u.reduce_poly(self.poly_points, tolerance=5) if len(self.poly_points) > 2: self.poly_points = u.convex_hull(self.poly_points) if not u.is_clockwise(self.poly_points): self.poly_points.reverse() center = u.calc_center(self.poly_points) self.poly_points = u.poly_vectors_around_center(self.poly_points) self.polys.append(self.create_poly(self.poly_points, pos=center)) self.poly_points = [] elif event.type == KEYDOWN and event.key == K_SPACE: self.run_physics = not self.run_physics elif event.type == KEYDOWN and event.key == K_k: for x in range (-100,100,25): for y in range(-100,100,25): p = pygame.mouse.get_pos() p = self.flipyv(Vec2d(p)) + (x,y) self.polys.append(self.create_box(pos=p)) elif event.type == KEYDOWN and event.key == K_b: p = flipyv(Vec2d(pygame.mouse.get_pos())) self.polys.append(self.create_box(p, size=10, mass = 1)) elif event.type == KEYDOWN and event.key == K_f: bp = Vec2d(100,500) p = self.flipyv(Vec2d(pygame.mouse.get_pos())) -bp ball = self.create_ball(bp) p = p.normalized() ball.body.apply_impulse(p*1000, (0,0)) self.balls.append(ball) elif event.type == KEYDOWN and event.key == K_g: g = self.space.gravity g.rotate(45) self.space.gravity = g mpos = pygame.mouse.get_pos() if pygame.key.get_mods() & KMOD_SHIFT and pygame.mouse.get_pressed()[2]: p = self.flipyv(Vec2d(mpos)) self.poly_points.append(p) self.shape_to_remove = self.space.point_query_first( self.flipyv(Vec2d(mpos)) ) ### Update physics if self.run_physics: x = 1 dt = 1.0/60.0/x for x in range(x): self.space.step(dt) for ball in self.balls: #ball.body.reset_forces() pass for poly in self.polys: #poly.body.reset_forces() pass ### Draw stuff self.draw() ### Check for objects outside of the screen, we can remove those # Balls xs = [] for ball in self.balls: if ball.body.position.x < -1000 or ball.body.position.x > 1000 \ or ball.body.position.y < -1000 or ball.body.position.y > 1000: xs.append(ball) for ball in xs: self.space.remove(ball, ball.body) self.balls.remove(ball) # Polys xs = [] for poly in self.polys: if poly.body.position.x < -1000 or poly.body.position.x > 1000 \ or poly.body.position.y < -1000 or poly.body.position.y > 1000: xs.append(poly) for poly in xs: self.space.remove(poly, poly.body) self.polys.remove(poly) ### Tick clock and update fps in title self.clock.tick(50) pygame.display.set_caption("fps: " + str(self.clock.get_fps()))