Recently I've published some sketches using the fisica library (using this library in ruby-processing is slightly problematic owing to a somewhat overly complicated polymorphic structure, and a protected abstract class that is supposed to provide "public" methods), here is a look at the Shiffman library that does essentially the same thing (
as fisica) by providing a wrapper for the JBox2D java physics library. However it might be just as easy for rubyists to work directly with JBox2D,
a note of caution you can't have both the fisica and the pbox2d libraries installed at he same time. Anyway it did at least provide an interesting exercise converting the following example to ruby-processing. Features to note are the required syntax to call the java constants
STATIC and
DYNAMIC, ie precede constant with '
::' and not a '
.', and the need to explicitly "to_java" required in the set "Array of Vec2" argument CustomShape class. Also it appears since we are including the library inside the Processing sketch/module we do no seem to require to include Processing::Proxy in the classes.
load_library :pbox2d
load_library :custom_shape
include B2D
attr_reader :box2d, :boundaries, :polygons
def setup
size(640,360)
smooth
@box2d = PBox2D.new(self)
box2d.create_world
box2d.set_gravity(0, -20)
@polygons = []
@boundaries = []
boundaries << Boundary.new(box2d, width / 4, height - 5, width/2 - 50, 10, 0)
boundaries << Boundary.new(box2d, 3*width / 4, height - 50, width/2 - 50, 10, 0)
boundaries << Boundary.new(box2d, width - 5,height / 2, 10, height, 0)
boundaries << Boundary.new(box2d, 5, height / 2, 10, height, 0)
end
def draw
background(255)
box2d.step
boundaries.each do |wall|
wall.display
end
polygons.each do |cs|
cs.display
end
polygons.each_with_index do |polygon, i|
if polygon.done
polygons.delete_at(i)
end
end
end
def mouse_pressed
polygons << CustomShape.new(box2d, mouse_x, mouse_y)
end
Here are the supporting classes, wrapped as a ruby module in a "library" custom_shape.rb, note the B2D prefix is needed in the module wrapped classes to access the "include_package" java packages, this is a jruby 'feature' they have not been able to get round as yet.
module B2D
include_package 'pbox2d'
include_package 'org.jbox2d.collision.shapes'
include_package 'org.jbox2d.common'
include_package 'org.jbox2d.dynamics'
java_import 'pbox2d.PBox2D'
class CustomShape
attr_reader :body, :box2d
def initialize(b2d, x, y)
@box2d = b2d
make_body(B2D::Vec2.new(x, y))
end
def kill_body!
box2d.destroy_body(body)
end
def done
pos = box2d.get_body_pixel_coord(body)
if (pos.y > $app.height)
kill_body!
return true
end
return false
end
def display
pos = box2d.get_body_pixel_coord(body)
a = body.get_angle
f = body.get_fixture_list
ps = f.get_shape
rect_mode(CENTER)
push_matrix
translate(pos.x, pos.y)
rotate(-a)
fill(175)
stroke(0)
begin_shape
ps.get_vertex_count.times do |i|
v = box2d.vector_world_to_pixels(ps.get_vertex(i))
vertex(v.x, v.y)
end
end_shape(CLOSE)
pop_matrix
end
def make_body(center)
sd = B2D::PolygonShape.new
vertices = []
vertices << box2d.vector_pixels_to_world(B2D::Vec2.new(-15, 25))
vertices << box2d.vector_pixels_to_world(B2D::Vec2.new(15, 0))
vertices << box2d.vector_pixels_to_world(B2D::Vec2.new(20, -15))
vertices << box2d.vector_pixels_to_world(B2D::Vec2.new(-10, -10))
sd.set(vertices.to_java(Java::OrgJbox2dCommon::Vec2), vertices.length)
bd = B2D::BodyDef.new
bd.type = B2D::BodyType::DYNAMIC
bd.position.set(box2d.coord_pixels_to_world(center))
@body = box2d.create_body(bd)
body.create_fixture(sd, 1.0)
body.set_linear_velocity(Vec2.new(rand(-5 .. 5), rand(2 .. 5)))
body.set_angular_velocity(rand(-5 .. 5))
end
end
class Boundary
attr_reader :box2d, :b, :x, :y, :w, :h
def initialize(b2d, x, y, w, h, a)
@box2d = b2d
@x = x
@y = y
@w = w
@h = h
sd = B2D::PolygonShape.new
box2dW = box2d.scalar_pixels_to_world(w/2)
box2dH = box2d.scalar_pixels_to_world(h/2)
sd.set_as_box(box2dW, box2dH)
bd = B2D::BodyDef.new
bd.type = B2D::BodyType::STATIC
bd.angle = a
bd.position.set(box2d.coord_pixels_to_world(x,y))
@b = box2d.create_body(bd)
b.create_fixture(sd,1)
end
def display
fill(0)
stroke(0)
stroke_weight(1)
rect_mode(CENTER)
a = b.get_angle
push_matrix
translate(x,y)
rotate(-a)
rect(0,0,w,h)
pop_matrix
end
end
end