著者:飯尾 淳
本連載では「Pythonを昔から使っているものの、それほど使いこなしてはいない」という筆者が、いろいろな日常業務をPythonで処理することで、立派な「蛇使い」に育つことを目指します。その過程を温かく見守ってください。皆さんと共に勉強していきましょう。第29回では、物体の動きや力の作用など、現実世界の物理法則を数値的に計算してシミュレーションする「物理演算」にチャレンジします。
シェルスクリプトマガジン Vol.99は以下のリンク先でご購入できます。


図6 playground.pyファイルの最後の部分にあるコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
def main(): demo = PhysicsDemo() demo.run() if __name__ == "__main__": doprof = 0 if not doprof: main() else: import cProfile import pstats prof = cProfile.run("main()", "profile.prof") stats = pstats.Stats("profile.prof") stats.strip_dirs() stats.sort_stats("cumulative", "time", "calls") stats.print_stats(30) |
図7 PhysicsDemoクラスのrun()メソッドのコード
|
|
def run(self): while self.running: self.loop() |
図8 PhysicsDemoクラスのloop()メソッドのコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
|
def loop(self): for event in pygame.event.get(): if event.type == pygame.QUIT: self.running = False (略) self.space.gravity = g.rotated_degrees(45) mpos = pygame.mouse.get_pos() if pygame.key.get_mods() & \ pygame.KMOD_SHIFT and pygame.mouse.get_pressed()[2]: p = self.flipyv(Vec2d(*mpos)) self.poly_points.append(p) hit = self.space.point_query_nearest( self.flipyv(Vec2d(*mpos)), 0, pm.ShapeFilter() ) if hit != None: self.shape_to_remove = hit.shape else: self.shape_to_remove = None ### 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 (略) ### Tick clock and update fps in title self.clock.tick(50) pygame.display.set_caption("fps: " + str(self.clock.get_fps())) |
図9 create_ball()メソッドのコード
|
|
def create_ball(self, point, mass=1.0, radius=15.0): moment = pm.moment_for_circle(mass, 0.0, radius) ball_body = pm.Body(mass, moment) ball_body.position = Vec2d(*point) ball_shape = pm.Circle(ball_body, radius) ball_shape.friction = 1.5 ball_shape.collision_type = COLLTYPE_DEFAULT self.space.add(ball_body, ball_shape) return ball_shape |
図10 PhysicsDemoクラスのコンストラクタのコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
def __init__(self): self.running = True ### Init pygame and create screen pygame.init() self.w, self.h = 600, 600 self.screen = pygame.display.set_mode((self.w, self.h)) self.clock = pygame.time.Clock() ### Init pymunk and create space self.space = pm.Space() self.space.gravity = (0.0, -900.0) ### Walls self.walls = [] self.create_wall_segments([(100, 50), (500, 50)]) ## Balls # balls = [createBall(space, (100,300))] self.balls = [] ### Polys self.polys = [] h = 10 for y in range(1, h): # for x in range(1, y): x = 0 s = 10 p = Vec2d(300, 40) + Vec2d(0, y * s * 2) self.polys.append(self.create_box(p, size=s, mass=1)) self.run_physics = True ### Wall under construction self.wall_points = [] ### Poly under construction self.poly_points = [] self.shape_to_remove = None self.mouse_contact = None |
図11 playground.pyファイルの変更差分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
133a134,135 > pygame.draw.circle(self.screen, > pygame.Color("skyblue"), p, int(r), 0) 140c142 < pygame.draw.lines(self.screen, pygame.Color("lightgray"), False, [pv1, pv2]) --- > pygame.draw.lines(self.screen, pygame.Color("gray"), False, [pv1, pv2], 3) 148c150,151 < color = pygame.Color("green") --- > color = pygame.Color("forestgreen") > color2 = pygame.Color("lightgreen") 151c154,156 < pygame.draw.lines(self.screen, color, False, ps) --- > color2 = pygame.Color("orange") > pygame.draw.polygon(self.screen, color2, ps, 0) > pygame.draw.polygon(self.screen, color, ps, 2) |
※「[」を「[」に、「< 」を「<」に置き換えてください。