Using pbox2d gem
You should have JRubyArt (or propane) and the pbox2d gem installed, from your sketch require
pbox2d
require 'pbox2d'
# A list we'll use to track fixed objects
attr_reader :box2d, :boundaries, :boxes
You then need to create an instance of Box2D
in the setup
def settings
size(400,300)
end
def setup
sketch_title 'pbox2d sketch'
@box2d = WorldBuilder.build(app: self, gravity: [0, -20])
From sketch to physics world and vice versa
Because of the peculiar choice by the processing guys down is up (dimensions in pixels) jbox2d doesn’t like to live in the pixel world (where up is really up), and prefers meters or feet and inches (whatever). What this means is that there is a need to scale between the two worlds using world_to_processing
and processing_to_world
methods provided. You should study the included example sketches.
Example Sketch
require 'pbox2d'
require_relative 'lib/boundary'
# A list we'll use to track fixed objects
attr_reader :box2d, :boundaries, :boxes
java_alias :background_int, :background, [Java::int]
java_alias :stroke_int, :stroke, [Java::int]
Vect = Struct.new(:x, :y)
def setup
sketch_title 'Quick Test'
stroke_int(0) # set stroke this way to avoid overload warnings
srand(5)
# Initialize box2d physics and create the world
@box2d = WorldBuilder.build(app: self, scale: 10, gravity: [0, -20.0])
puts box2d.version
# Set a custom gravity
# box2d.gravity(0, -20)
# Create ArrayLists
@boxes = []
@boundaries = [
Boundary.new(box2d, Vect.new(width / 4, height - 5), Vect.new(width / 2 - 50, 10)),
Boundary.new(box2d, Vect.new(3 * width / 4, height - 50), Vect.new(width / 2 - 50, 10))
]
end
def draw
background_int(255) # set background this way to avoid overload warnings
# Boxes fall from the top every so often
boxes << Box.new(box2d, width / 2, 30) if rand < 0.99
boundaries.each(&:display)
boxes.each(&:display)
# Boxes that leave the screen, we delete them note they have to be deleted
# from both the box2d world and locally
boxes.reject!(&:done)
exit if frame_count >= 908
end
# A rectangular box
class Box
include Processing::Proxy
# We need to keep track of a Body and a width and height
attr_reader :box2d, :body, :w, :h
# Constructor
def initialize(b2d, x, y)
@w = rand(4..16)
@h = rand(4..16)
@box2d = b2d
# Add the box to the box2d world
make_body(Vec2.new(x, y), w, h)
end
def done
# Let's find the screen position of the particle
pos = box2d.body_coord(body)
# Is it off the bottom of the screen?
return false unless (pos.y > box2d.height + w * h)
box2d.destroy_body(body)
true
end
# Drawing the box
def display
# We look at each body and get its screen position
pos = box2d.body_coord(body)
# Get its angle of rotation
a = body.angle
rect_mode(CENTER)
push_matrix
translate(pos.x, pos.y)
rotate(-a)
fill(175)
rect(0, 0, w, h)
pop_matrix
end
# This function adds the rectangle to the box2d world
def make_body(center, w, h)
# Define a polygon (this is what we use for a rectangle)
sd = PolygonShape.new
box2d_w = box2d.scale_to_world(w / 2)
box2d_h = box2d.scale_to_world(h / 2)
sd.setAsBox(box2d_w, box2d_h)
# Define a fixture
fd = FixtureDef.new
fd.shape = sd
# Parameters that affect physics
fd.density = 1
fd.friction = 0.3
fd.restitution = 0.5
# Define the body and make it from the shape
bd = BodyDef.new
bd.type = BodyType::DYNAMIC
bd.position.set(box2d.processing_to_world(center))
cs = CircleShape.new
@body = box2d.create_body(bd)
body.create_fixture(fd)
# Give it some initial random velocity
body.setLinearVelocity(Vec2.new(rand(-5.0..5), rand(2.0..5)))
body.setAngularVelocity(rand(-5.0..5))
end
end
def settings
size(400,300)
end
The boundary classes
class Boundary
include Processing::Proxy
attr_reader :box2d, :b, :pos, :size, :a
def initialize(b2d, pos, sz, a = 0)
@box2d, @pos, @size, @a = b2d, pos, sz, a
# Define the polygon
sd = PolygonShape.new
# Figure out the box2d coordinates
box2d_w = box2d.scale_to_world(size.x / 2)
box2d_h = box2d.scale_to_world(size.y / 2)
# We're just a box
sd.set_as_box(box2d_w, box2d_h)
# Create the body
bd = BodyDef.new
bd.type = BodyType::STATIC
bd.angle = a
bd.position.set(box2d.processing_to_world(pos.x, pos.y))
@b = box2d.create_body(bd)
# Attached the shape to the body using a Fixture
b.create_fixture(sd, 1)
end
# Draw the boundary, it doesn't move so we don't have to ask the Body for location
def display
fill(0)
stroke(0)
stroke_weight(1)
rect_mode(CENTER)
a = b.get_angle
push_matrix
translate(pos.x, pos.y)
rotate(-a)
rect(0, 0, size.x,size.y)
pop_matrix
end
end