Experiments with ruby-processing (processing-2.2.1) and JRubyArt for processing-3.0

Thursday 13 November 2014

Custom Contact Listener for pbox2d and ruby-processing

require 'pbox2d'
require_relative 'lib/custom_listener'
require_relative 'lib/particle'
require_relative 'lib/boundary'

attr_reader :box2d, :particles, :wall

def setup
  size 400, 400
  @box2d = Box2D.new(self)
  box2d.create_world
  box2d.add_listener(CustomListener.new)
  @particles = []
  @wall = Boundary.new(box2d, width / 2, height - 5, width, 10)
end

def draw
  background(255)

  if (rand < 0.1)
    particles << Particle.new(box2d, rand(width), 20, rand(4..8))
  end
  particles.each{ |p| p.display(self) }
  particles.reject!(&:done)
  wall.display(self)
end

Custom Listener
class CustomListener
  include ContactListener

  def begin_contact(cp)
    # Get both fixtures
    f1 = cp.getFixtureA
    f2 = cp.getFixtureB
    # Get both bodies
    b1 = f1.getBody
    b2 = f2.getBody
    # Get our objects that reference these bodies
    o1 = b1.getUserData
    o2 = b2.getUserData
    return unless (o1.respond_to?(:change) && o2.respond_to?(:change))
    o1.change
    o2.change
  end

  def end_contact(cp)
  end

  def pre_solve(cp, m)
  end

  def post_solve(cp, ci)
  end

end

Boundary class
CENTER ||= Java::ProcessingCore::PConstants::CENTER

class Boundary
  include PB
  attr_reader :box2d, :x, :y, :w, :h, :b
  def initialize(b2d, x, y, w, h)
    @box2d, @x, @y, @w, @h = b2d, x, y, w, h
    sd = PolygonShape.new
    box2dW = box2d.scale_to_world(w / 2)
    box2dH = box2d.scale_to_world(h / 2)
    # We're just a box
    sd.setAsBox(box2dW, box2dH);


    # Create the body
    bd = BodyDef.new
    bd.type = BodyType::STATIC;
    bd.position.set(box2d.processing_to_world(x,y))
    @b = box2d.create_body(bd)

    # Attached the shape to the body using a Fixture
    b.create_fixture(sd, 1)
    b.setUserData(self)
  end

  # Draw the boundary, if it were at an angle we'd have to do something fancier
  def display(app)
    app.fill(0)
    app.stroke(0)
    app.rectMode(CENTER)
    app.rect(x,y,w,h)
  end
end
Particle class
class Particle
  include PB
  attr_accessor :body
  attr_reader :box2d, :radius, :col

  def initialize(b2d, x, y, r)
    @box2d, @x, @y, @radius = b2d, x, y, r
    # This function puts the particle in the Box2d world
    make_body(x, y, radius)
    @col = -5263441
    body.setUserData(self)
  end

  # This function removes the particle from the box2d world
  def kill_body
    box2d.destroy_body(body)
  end

  # Change color when hit
  def change
    @col = -65536 # red
  end

  # Is the particle ready for deletion?
  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 + radius * 2)
    kill_body
    true
  end

  def display(app)
    # We look at each body and get its screen position
    pos = box2d.body_coord(body)
    # Get its angle of rotation
    a = body.get_angle
    app.push_matrix
    app.translate(pos.x, pos.y)
    app.rotate(a)
    app.fill(col)
    app.stroke(0)
    app.stroke_weight(1)
    app.ellipse(0, 0, radius * 2, radius * 2)
    # Let's add a line so we can see the rotation
    app.line(0, 0, radius, 0)
    app.pop_matrix
  end

  # Here's our function that adds the particle to the Box2D world
  def make_body(x, y, r)
    # Define a body
    bd = BodyDef.new
    # Set its position
    bd.position = box2d.processing_to_world(x, y)
    bd.type = BodyType::DYNAMIC
    @body = box2d.create_body(bd)
    # Make the body's shape a circle
    cs = CircleShape.new
    cs.m_radius = box2d.scale_to_world(r)
    fd = FixtureDef.new
    fd.shape = cs
    # Parameters that affect physics
    fd.density = 1
    fd.friction = 0.01
    fd.restitution = 0.3
    # Attach fixture to body
    body.create_fixture(fd)
    body.set_angular_velocity(rand(-10.0..10))
  end
end

No comments:

Post a Comment

Followers

About Me

My photo
I have developed JRubyArt and propane new versions of ruby-processing for JRuby-9.1.5.0 and processing-3.2.2