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 endParticle 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