物理エンジン Chipmunk を Gosu で表示(Ruby)
2D物理エンジン「Chipmunk」を Ruby から使ってみました。表示には Gem 'gosu' を使っています。Linux Mint 18.3, Ruby 2.3.3 で確認しました。
gosu_chipmunk_sample2.rb (Gist)
require 'gosu' require 'rmagick' require 'chipmunk' Width, Height = 600, 600 Wall_h = 20 class MyWindow < Gosu::Window def initialize super Width, Height, false self.caption = "Gosu + Chipmunk" @space = CP::Space.new @space.gravity = CP::Vec2.new(0, 250) #円の画像の生成 circle_image = Magick::Image.new(21, 21) {self.background_color = 'transparent'} gc = Magick::Draw.new gc.fill('yellow') gc.circle(10, 10, 0, 10) gc.draw(circle_image) @circle = Gosu::Image.new(circle_image) #壁の生成 background = Magick::Image.new(Width, Height) {self.background_color = "black"} create_wall(0, Height - Wall_h, Width, Height - Wall_h, Wall_h, background) create_wall(Wall_h, 0, Wall_h, Height, Wall_h, background) create_wall(Width, 0, Width, Height, Wall_h, background) create_wall(120, 150, 400, 200, Wall_h, background) create_wall(200, 450, 480, 400, Wall_h, background) @background_image = Gosu::Image.new(background) @circles = [] end def create_circle body = CP::Body.new(1, CP::INFINITY) body.p = CP::Vec2.new(rand(Width / 2 + Width / 4), -20) body.v = CP::Vec2.new(rand * 500 - 250, 0) shape = CP::Shape::Circle.new(body, 10, CP::Vec2.new(0, 0)) shape.e = 0.8 shape.u = 0 @space.add_body(body) @space.add_shape(shape) body end def create_wall(x1, y1, x2, y2, height, bg) sb = CP::Body.new_static p1 = CP::Vec2.new(x1, y1) p4 = CP::Vec2.new(x2, y2) p0 = p4 - p1 p2 = p1 + p0.normalize.rotate(CP::Vec2.new(0, 1)) * height p3 = p2 + p0 verts = [p1, p2, p3, p4] wshape = CP::Shape::Poly.new(sb, verts, CP::Vec2.new(0, 0)) wshape.e = 1 wshape.u = 0 @space.add_shape(wshape) gc = Magick::Draw.new gc.fill('firebrick') verts = verts.map {|vt| [vt.x, vt.y]}.flatten gc.polygon(*verts) gc.draw(bg) end def update @space.step(1.0 / 60) @circles << create_circle if rand < 0.1 and @circles.size < 300 end def draw @background_image.draw(0, 0, 0) @circles.each {|c| @circle.draw_rot(c.p.x, c.p.y, 1, 0)} end end MyWindow.new.show
Chipmunk で計算したものを Gosu を使って表示しています。画像の生成には RMagick を使っています。
メソッド create_wall(x1, y1, x2, y2, height, bg) の (x1, y1), (x2, y2) は壁の上面のラインを指定します。height は壁の厚みです。
おもしろいことに、上のコードで行数を取っているのはほとんどが円や壁の設定です。計算は Chipmunk が、描画は Gosu が自動的にやってくれるため、メインループ(メソッド update, draw)は数行しかありません。
全体の構造も単純です。Chipmunk の空間は @space = CP::Space.new
であり、@space.gravity
で重力を発生させます。円の本体は CP::Body.new
で生成し、壁は動かないので CP::Body.new_static
で生成します。@space.step
メソッドで時間を進めます。
Gosu はまず Gosu::Window
を継承した MyWindow
クラスを作り、そのインスタンスを show
すれば基本的に描画されます。メインループ内のロジックは update
, 描画は draw
メソッド内に書きます。こうするとデフォルトで 1/60 秒ごとに描画が繰り返されます。
Ruby の強力な「オブジェクト指向プログラミング」のおかげで、じつに簡単に物理エンジンが動かせかつ可視化できていると思います。
Gosu + Chipmunk + RMagick については以下に簡単なまとめとサンプルを書いておきました。
Chipmunk については下のサイトがすごくわかりやすかったです。
さらに Chipmunk + Gosu で遊んでみました。
obelisk.hatenablog.com