JRubyでODEをはじめてみる2
オリジナルのODEにはdrawstuffというデモ用のGUIキット?が含まれています。
ode4jにもありがたいことにdemoのjarの中にdrawstuffが隠れています。
今回はdemoに含まれているdrawstuffを利用します。
ode4jのdrawstuffはLWJGLライブラリが使用されているので準備します。
http://lwjgl.org/download.php
lwjgl-2.9.1.zip
まずはdrawstuffの動作確認
require 'ode4j/core-0.2.8.jar' require 'ode4j/demo-0.2.8.jar' require 'lwjgl/jar/lwjgl.jar' require 'lwjgl/jar/lwjgl_util.jar' DrawStuff = org.ode4j.drawstuff.DrawStuff DsFunctions = org.ode4j.drawstuff.DrawStuff.dsFunctions class TestSim < DsFunctions def start end def command(cmd) end def step(pause) end def stop end end DrawStuff::dsSimulationLoop(ARGV, 400,300, TestSim.new)
実行は次のようにします。
lwjglはネイティブライブラリが必要なためパス指定を付けてあげます。
たとえば以下はMacOS の場合です。
- 実行
$ ls lwjgl/macosx libjinput-osx.jnilib liblwjgl.jnilib openal.dylib $ jruby-1.7.9 -J-Djava.library.path=lwjgl/macosx hoge2.rb
(GUI)ボールの落下
以下のソースでひとまず格好がつきました。
require 'ode4j/core-0.2.8.jar' require 'ode4j/demo-0.2.8.jar' require 'lwjgl/jar/lwjgl.jar' require 'lwjgl/jar/lwjgl_util.jar' #for ODE OdeHelper = org.ode4j.ode.OdeHelper DContactJoint = org.ode4j.ode.DContactJoint DContactBuffer = org.ode4j.ode.DContactBuffer OdeConstants = org.ode4j.ode.OdeConstants #for Drawstuff DrawStuff = org.ode4j.drawstuff.DrawStuff DsFunctions = org.ode4j.drawstuff.DrawStuff.dsFunctions class TestSim < DsFunctions MAX_CONTACTS = 4 def nearCallback(data,o1,o2) b1 = o1.getBody b2 = o2.getBody until b1 or b2 or !OdeHelper.areaConnectedExcluding(b1,b2,DContactJoint.class) return end contacts = DContactBuffer.new(MAX_CONTACTS) MAX_CONTACTS.times do |n| contact = contacts.get(n) contact.surface.mode = OdeConstants.dContactBounce | OdeConstants.dContactSoftCFM contact.surface.mu = OdeConstants.dInfinity contact.surface.bounce = 0.1 contact.surface.bounce_vel = 0.1 contact.surface.soft_cfm = 0.01 end numc = OdeHelper.collide(o1,o2,MAX_CONTACTS,contacts.getGeomBuffer) if numc != 0 numc.times do |n| c = OdeHelper.createContactJoint(@world,@cgroup,contacts.get(n)) c.attach(b1,b2) end end end def init @world = OdeHelper.createWorld @world.setGravity(0.0, 0.0, -9.8) @world.setCFM(0.001) @space = OdeHelper.createHashSpace #@space = OdeHelper.createSimpleSpace(nil) @cgroup = OdeHelper.createJointGroup floor = OdeHelper.createPlane(@space, 0.0, 0.0, 1.0, 0) ball_body = OdeHelper.createBody(@world) ball_body.setPosition(0.0, 0.0, 10.0) ball_mass = OdeHelper.createMass ball_mass.setSphereTotal(1.0, 0.5) ball_body.setMass(ball_mass) @ball = OdeHelper.createSphere(@space, 0.5) @ball.setBody(ball_body) end def start xyz = [-6.0,0,3.0] hpr = [0.0,0.0,0.0] DrawStuff::dsSetViewpoint(xyz,hpr) init end def command(cmd) end def simLoop(pause) @space.collide(nil, Proc.new{|data,o1,o2| nearCallback(data,o1,o2) }) if !pause # @world.step(0.02) @world.quickStep(0.02) end @cgroup.empty pos = @ball.getPosition.toFloatArray puts "pos - #{pos[0]} #{pos[1]} #{pos[2]}" DrawStuff::dsSetColor(1,0,0) DrawStuff::dsDrawSphere( @ball.getPosition, @ball.getRotation, 0.5) end def step(pause) simLoop(pause) end def stop end end #OdeHelper.initODE OdeHelper.initODE2(0) DrawStuff::dsSimulationLoop(ARGV, 400,300, TestSim.new)
作りはかなり雑です。
全くといっていいほどRubyらしく書けてません。
つっこむところはいろいろありそうですが、とりあえず、やりたいことの第一歩としてはよいのかなと。
JRuby+ODE という組み合わせは如何なものかと思いますが、利点をあげるとするならば
という感じでしょうか。
ただし、おそらくオリジナルODEよりは動作はおそくなるだろうなーと。
その辺はいろいろ試す中でみていこうと思います。