pbox2d 0.3.1-java → 0.4.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +4 -2
- data/Rakefile +2 -2
- data/examples/bumpy_surface_noise.rb +41 -0
- data/examples/distance_joint/boundary.rb +39 -0
- data/examples/distance_joint/distance_joint.rb +38 -0
- data/examples/distance_joint/pair.rb +41 -0
- data/examples/distance_joint/particle.rb +75 -0
- data/examples/lib/boundary.rb +30 -0
- data/examples/lib/box.rb +15 -0
- data/examples/lib/custom_shape.rb +0 -0
- data/examples/lib/particle_system.rb +154 -0
- data/examples/lib/surface.rb +136 -0
- data/examples/liquid_fun_test.rb +42 -0
- data/examples/liquidy.rb +36 -0
- data/examples/polygons.rb +39 -0
- data/examples/quick_test.rb +141 -0
- data/examples/revolute_joint/box.rb +68 -0
- data/examples/revolute_joint/particle.rb +86 -0
- data/examples/revolute_joint/revolute_joint.rb +44 -0
- data/examples/revolute_joint/windmill.rb +53 -0
- data/examples/test_contact/lib/boundary.rb +33 -0
- data/examples/test_contact/lib/custom_listener.rb +29 -0
- data/examples/test_contact/lib/particle.rb +77 -0
- data/examples/test_contact/test_contact.rb +25 -0
- data/lib/box2d.jar +0 -0
- data/lib/pbox2d.rb +16 -20
- data/lib/pbox2d/box2d.rb +8 -6
- data/lib/pbox2d/version.rb +1 -1
- metadata +24 -2
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
# The Nature of Code
|
4
|
+
# PBox2D example
|
5
|
+
# An uneven surface boundary
|
6
|
+
class Surface
|
7
|
+
extend Forwardable
|
8
|
+
# We'll keep track of all of the surface points
|
9
|
+
def_delegators(:@app, :box2d, :width, :height, :begin_shape,
|
10
|
+
:end_shape, :fill, :stroke, :stroke_weight,
|
11
|
+
:vertex, :map1d, :noise)
|
12
|
+
attr_reader :surface, :body, :y
|
13
|
+
|
14
|
+
def initialize(app)
|
15
|
+
@app = app
|
16
|
+
@surface = []
|
17
|
+
# This is what box2d uses to put the surface in its world
|
18
|
+
chain = ChainShape.new
|
19
|
+
# Perlin noise argument
|
20
|
+
xoff = 0.0
|
21
|
+
# This has to go backwards so that the objects bounce off the top of the
|
22
|
+
# surface. This "edgechain" will only work in one direction!
|
23
|
+
(width + 10).step(-10, -5) do |x|
|
24
|
+
# Doing some stuff with perlin noise to calculate a surface that points
|
25
|
+
# down on one side and up on the other
|
26
|
+
if x > width / 2
|
27
|
+
@y = 100 + (width - x) * 1.1 + map1d(noise(xoff), (0..1.0), (-80..80))
|
28
|
+
else
|
29
|
+
@y = 100 + x * 1.1 + map1d(noise(xoff), (0..1.0), (-80..80))
|
30
|
+
end
|
31
|
+
# Store the vertex in screen coordinates
|
32
|
+
surface << Vec2.new(x, y)
|
33
|
+
# Move through perlin noise
|
34
|
+
xoff += 0.1
|
35
|
+
end
|
36
|
+
# Build an array of vertices in Box2D coordinates
|
37
|
+
# from the ArrayList we made
|
38
|
+
vertices = []
|
39
|
+
surface.each do |surf|
|
40
|
+
vertices << box2d.processing_to_world(surf)
|
41
|
+
end
|
42
|
+
# Create the chain!
|
43
|
+
chain.createChain(vertices, vertices.length)
|
44
|
+
# The edge chain is now attached to a body via a fixture
|
45
|
+
bd = BodyDef.new
|
46
|
+
bd.position.set(0.0, 0.0)
|
47
|
+
@body = box2d.createBody(bd)
|
48
|
+
# Shortcut, we could define a fixture if we
|
49
|
+
# want to specify frictions, restitution, etc.
|
50
|
+
body.createFixture(chain, 1)
|
51
|
+
end
|
52
|
+
|
53
|
+
# A simple function to just draw the edge chain as a series of vertex points
|
54
|
+
def display
|
55
|
+
stroke_weight(2)
|
56
|
+
stroke(0)
|
57
|
+
fill(135, 206, 250)
|
58
|
+
begin_shape
|
59
|
+
vertex(width, 0) # extra vertices so we can fill sky
|
60
|
+
surface.map { |v| vertex(v.x, v.y) } # the mountain range
|
61
|
+
vertex(0, 0) # extra vertices so we can fill sky
|
62
|
+
end_shape
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Using forwardable again
|
67
|
+
class Particle
|
68
|
+
extend Forwardable
|
69
|
+
def_delegators(:@app, :box2d, :push_matrix, :pop_matrix, :rotate,
|
70
|
+
:translate, :fill, :stroke, :stroke_weight, :noise,
|
71
|
+
:map1d, :ellipse, :line)
|
72
|
+
# We need to keep track of a Body
|
73
|
+
|
74
|
+
attr_reader :body, :x, :y, :r
|
75
|
+
|
76
|
+
# Constructor
|
77
|
+
def initialize(app, x, y, r)
|
78
|
+
@app, @x, @y, @r = app, x, y, r
|
79
|
+
# This function puts the particle in the Box2d world
|
80
|
+
make_body(x, y, r)
|
81
|
+
end
|
82
|
+
|
83
|
+
# This function removes the particle from the box2d world
|
84
|
+
def kill_body
|
85
|
+
box2d.destroy_body(body)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Is the particle ready for deletion?
|
89
|
+
def done
|
90
|
+
pos = box2d.body_coord(body)
|
91
|
+
# Is it off the bottom of the screen?
|
92
|
+
return false unless pos.y > box2d.height + r * 2
|
93
|
+
kill_body
|
94
|
+
true
|
95
|
+
end
|
96
|
+
|
97
|
+
def display
|
98
|
+
# We look at each body and get its screen position
|
99
|
+
pos = box2d.body_coord(body)
|
100
|
+
# Get its angle of rotation
|
101
|
+
a = body.get_angle
|
102
|
+
push_matrix
|
103
|
+
translate(pos.x, pos.y)
|
104
|
+
rotate(-a)
|
105
|
+
fill(175)
|
106
|
+
stroke(0)
|
107
|
+
stroke_weight(1)
|
108
|
+
ellipse(0, 0, r * 2, r * 2)
|
109
|
+
# Let's add a line so we can see the rotation
|
110
|
+
line(0, 0, r, 0)
|
111
|
+
pop_matrix
|
112
|
+
end
|
113
|
+
|
114
|
+
# This function adds the rectangle to the box2d world
|
115
|
+
def make_body(x, y, r)
|
116
|
+
# Define and create the body
|
117
|
+
bd = BodyDef.new
|
118
|
+
bd.position = box2d.processing_to_world(x, y)
|
119
|
+
bd.type = BodyType::DYNAMIC
|
120
|
+
@body = box2d.create_body(bd)
|
121
|
+
# Make the body's shape a circle
|
122
|
+
cs = CircleShape.new
|
123
|
+
cs.m_radius = box2d.scale_to_world(r)
|
124
|
+
fd = FixtureDef.new
|
125
|
+
fd.shape = cs
|
126
|
+
# Parameters that affect physics
|
127
|
+
fd.density = 1
|
128
|
+
fd.friction = 0.01
|
129
|
+
fd.restitution = 0.3
|
130
|
+
# Attach fixture to body
|
131
|
+
body.create_fixture(fd)
|
132
|
+
# Give it a random initial velocity (and angular velocity)
|
133
|
+
body.set_linear_velocity(Vec2.new(rand(-10..10), rand(5..10)))
|
134
|
+
body.set_angular_velocity(rand(-10..10))
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# The Nature of Code
|
2
|
+
# Daniel Shiffman
|
3
|
+
# http://natureofcode.com
|
4
|
+
# Basic example of falling rectangles
|
5
|
+
|
6
|
+
require 'pbox2d'
|
7
|
+
require_relative 'lib/boundary'
|
8
|
+
require_relative 'lib/box'
|
9
|
+
|
10
|
+
attr_reader :boxes, :boundaries, :box2d
|
11
|
+
|
12
|
+
def setup
|
13
|
+
size(640, 360, P2D)
|
14
|
+
@box2d = Box2D.new(self)
|
15
|
+
box2d.init_options(gravity: [0, -10])
|
16
|
+
box2d.create_world
|
17
|
+
@boundaries = []
|
18
|
+
@boxes = []
|
19
|
+
box2d.world.set_particle_radius(0.15)
|
20
|
+
box2d.world.set_particle_damping(0.2)
|
21
|
+
boundaries << Boundary.new(self, width / 4, height - 5, width / 2 - 50, 10)
|
22
|
+
boundaries << Boundary.new(self, 3 * width / 4, height - 50, width / 2 - 50, 10)
|
23
|
+
end
|
24
|
+
|
25
|
+
def mouse_pressed
|
26
|
+
boxes << Box.new(box2d, mouse_x, mouse_y)
|
27
|
+
end
|
28
|
+
|
29
|
+
def draw
|
30
|
+
background(255)
|
31
|
+
boundaries.each(&:display)
|
32
|
+
pos_buffer = box2d.world.particle_position_buffer
|
33
|
+
return if pos_buffer.nil?
|
34
|
+
stroke(0)
|
35
|
+
stroke_weight(2)
|
36
|
+
pos_buffer.each do |buf|
|
37
|
+
pos = box2d.world_to_processing(buf)
|
38
|
+
point(pos.x, pos.y)
|
39
|
+
end
|
40
|
+
fill(0)
|
41
|
+
text(format('f.p.s %d', frame_rate.to_i), 10, 60)
|
42
|
+
end
|
data/examples/liquidy.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'pbox2d'
|
2
|
+
require_relative 'lib/particle_system'
|
3
|
+
attr_reader :box2d, :boundaries, :systems
|
4
|
+
|
5
|
+
def setup
|
6
|
+
size(400, 300)
|
7
|
+
@box2d = Box2D.new(self)
|
8
|
+
box2d.init_options(gravity: [0, -20])
|
9
|
+
box2d.create_world
|
10
|
+
# to set a custom gravity otherwise
|
11
|
+
# box2d.gravity([0, -20])
|
12
|
+
# Create Arrays
|
13
|
+
@systems = []
|
14
|
+
@boundaries = []
|
15
|
+
# Add a bunch of fixed boundaries
|
16
|
+
boundaries << Boundary.new(self, 50, 100, 5, -0.3)
|
17
|
+
boundaries << Boundary.new(self, 250, 175, 5, 0.5)
|
18
|
+
end
|
19
|
+
|
20
|
+
def draw
|
21
|
+
background(255)
|
22
|
+
# Run all the particle systems
|
23
|
+
if systems.size > 0
|
24
|
+
systems.each do |system|
|
25
|
+
system.run
|
26
|
+
system.add_particles(self, rand(0..2))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
# Display all the boundaries
|
30
|
+
boundaries.each(&:display)
|
31
|
+
end
|
32
|
+
|
33
|
+
def mouse_pressed
|
34
|
+
# Add a new Particle System whenever the mouse is clicked
|
35
|
+
systems << ParticleSystem.new(self, 0, mouse_x, mouse_y)
|
36
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# Basic example of falling rectangles
|
2
|
+
require 'pbox2d'
|
3
|
+
require_relative 'lib/custom_shape'
|
4
|
+
|
5
|
+
attr_reader :box2d, :boundaries, :polygons
|
6
|
+
|
7
|
+
def setup
|
8
|
+
size(640, 360)
|
9
|
+
smooth
|
10
|
+
# Initialize box2d physics and create the world
|
11
|
+
@box2d = Box2D.new(self)
|
12
|
+
box2d.init_options(gravity: [0, -20])
|
13
|
+
box2d.create_world
|
14
|
+
# To later set a custom gravity
|
15
|
+
# box2d.gravity([0, -20]
|
16
|
+
# Create Arrays
|
17
|
+
@polygons = []
|
18
|
+
@boundaries = []
|
19
|
+
# Add a bunch of fixed boundaries
|
20
|
+
boundaries << Boundary.new(self, width / 4, height - 5, width / 2 - 50, 10, 0)
|
21
|
+
boundaries << Boundary.new(self, 3 * width / 4, height - 50, width / 2 - 50, 10, 0)
|
22
|
+
boundaries << Boundary.new(self, width - 5, height / 2, 10, height, 0)
|
23
|
+
boundaries << Boundary.new(self, 5, height / 2, 10, height, 0)
|
24
|
+
end
|
25
|
+
|
26
|
+
def draw
|
27
|
+
background(255)
|
28
|
+
# Display all the boundaries
|
29
|
+
boundaries.each(&:display)
|
30
|
+
# Display all the polygons
|
31
|
+
polygons.each(&:display)
|
32
|
+
# polygons that leave the screen, we delete them
|
33
|
+
# (note they have to be deleted from both the box2d world and our list
|
34
|
+
polygons.reject!(&:done)
|
35
|
+
end
|
36
|
+
|
37
|
+
def mouse_pressed
|
38
|
+
polygons << CustomShape.new(self, mouse_x, mouse_y)
|
39
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'pbox2d'
|
2
|
+
|
3
|
+
# A list we'll use to track fixed objects
|
4
|
+
attr_reader :box2d, :boundaries, :boxes
|
5
|
+
|
6
|
+
java_alias :background_int, :background, [Java::int]
|
7
|
+
java_alias :stroke_int, :stroke, [Java::int]
|
8
|
+
|
9
|
+
def setup
|
10
|
+
size(400,300)
|
11
|
+
stroke_int(0) # set stroke this way to avoid overload warnings
|
12
|
+
srand(5)
|
13
|
+
# Initialize box2d physics and create the world
|
14
|
+
@box2d = Box2D.new(self)
|
15
|
+
puts box2d.version # print out version of pbox2d gem in use
|
16
|
+
box2d.init_options(scale: 10, gravity: [0, -20.0])
|
17
|
+
box2d.create_world
|
18
|
+
# Set a custom gravity
|
19
|
+
# box2d.gravity(0, -20)
|
20
|
+
# Create ArrayLists
|
21
|
+
@boxes = []
|
22
|
+
@boundaries = []
|
23
|
+
# Add a bunch of fixed boundaries
|
24
|
+
boundaries << Boundary.new(self, width / 4, height - 5, width / 2 - 50, 10)
|
25
|
+
boundaries << Boundary.new(self, 3 * width / 4, height - 50, width / 2 - 50, 10)
|
26
|
+
end
|
27
|
+
|
28
|
+
def draw
|
29
|
+
background_int(255) # set background this way to avoid overload warnings
|
30
|
+
# Boxes fall from the top every so often
|
31
|
+
boxes << Box.new(self, width / 2, 30) if rand < 0.99
|
32
|
+
boundaries.each(&:display)
|
33
|
+
boxes.each(&:display)
|
34
|
+
# Boxes that leave the screen, we delete them note they have to be deleted
|
35
|
+
# from both the box2d world and locally
|
36
|
+
boxes.reject!(&:done)
|
37
|
+
exit if frame_count >= 908
|
38
|
+
end
|
39
|
+
|
40
|
+
class Boundary
|
41
|
+
extend Forwardable
|
42
|
+
def_delegators(:@app, :box2d, :fill, :rect, :rect_mode)
|
43
|
+
# A boundary is a simple rectangle with x, y, width, and height
|
44
|
+
attr_reader :x, :y, :w, :h, :b
|
45
|
+
|
46
|
+
def initialize(app, x ,y, w, h)
|
47
|
+
@app, @x ,@y, @w, @h = app, x ,y, w, h
|
48
|
+
# Create the body
|
49
|
+
bd = BodyDef.new
|
50
|
+
bd.position.set(box2d.processing_to_world(x, y))
|
51
|
+
@b = box2d.create_body(bd)
|
52
|
+
# Figure out the box2d coordinates
|
53
|
+
box2d_w = box2d.scale_to_world(w / 2)
|
54
|
+
box2d_h = box2d.scale_to_world(h / 2)
|
55
|
+
# Define the polygon
|
56
|
+
sd = PolygonShape.new
|
57
|
+
sd.setAsBox(box2d_w, box2d_h)
|
58
|
+
fd = FixtureDef.new
|
59
|
+
fd.shape = sd
|
60
|
+
fd.density = 0
|
61
|
+
fd.friction = 0.3
|
62
|
+
fd.restitution = 0.5
|
63
|
+
b.createFixture(fd)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Draw the boundary, if it were at an angle we'd have to do something fancier
|
67
|
+
def display
|
68
|
+
fill(0)
|
69
|
+
rect_mode(Java::ProcessingCore::PConstants::CENTER)
|
70
|
+
rect(x, y, w, h)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# A rectangular box
|
75
|
+
class Box
|
76
|
+
extend Forwardable
|
77
|
+
def_delegators(:@app, :box2d, :rect_mode, :rect,
|
78
|
+
:push_matrix, :pop_matrix, :fill, :rotate,
|
79
|
+
:stroke, :stroke_weight, :translate)
|
80
|
+
# We need to keep track of a Body and a width and height
|
81
|
+
attr_reader :body, :w, :h
|
82
|
+
|
83
|
+
# Constructor
|
84
|
+
def initialize(app, x, y)
|
85
|
+
@w = rand(4..16)
|
86
|
+
@h = rand(4..16)
|
87
|
+
@app = app
|
88
|
+
# Add the box to the box2d world
|
89
|
+
make_body(Vec2.new(x, y), w, h)
|
90
|
+
end
|
91
|
+
|
92
|
+
def done
|
93
|
+
# Let's find the screen position of the particle
|
94
|
+
pos = box2d.body_coord(body)
|
95
|
+
# Is it off the bottom of the screen?
|
96
|
+
return false unless (pos.y > box2d.height + w * h)
|
97
|
+
box2d.destroy_body(body)
|
98
|
+
true
|
99
|
+
end
|
100
|
+
|
101
|
+
# Drawing the box
|
102
|
+
def display
|
103
|
+
# We look at each body and get its screen position
|
104
|
+
pos = box2d.body_coord(body)
|
105
|
+
# Get its angle of rotation
|
106
|
+
a = body.angle
|
107
|
+
rect_mode(Java::ProcessingCore::PConstants::CENTER)
|
108
|
+
push_matrix
|
109
|
+
translate(pos.x, pos.y)
|
110
|
+
rotate(-a)
|
111
|
+
fill(175)
|
112
|
+
rect(0, 0, w, h)
|
113
|
+
pop_matrix
|
114
|
+
end
|
115
|
+
|
116
|
+
# This function adds the rectangle to the box2d world
|
117
|
+
def make_body(center, w, h)
|
118
|
+
# Define a polygon (this is what we use for a rectangle)
|
119
|
+
sd = PolygonShape.new
|
120
|
+
box2d_w = box2d.scale_to_world(w / 2)
|
121
|
+
box2d_h = box2d.scale_to_world(h / 2)
|
122
|
+
sd.setAsBox(box2d_w, box2d_h)
|
123
|
+
# Define a fixture
|
124
|
+
fd = FixtureDef.new
|
125
|
+
fd.shape = sd
|
126
|
+
# Parameters that affect physics
|
127
|
+
fd.density = 1
|
128
|
+
fd.friction = 0.3
|
129
|
+
fd.restitution = 0.5
|
130
|
+
# Define the body and make it from the shape
|
131
|
+
bd = BodyDef.new
|
132
|
+
bd.type = BodyType::DYNAMIC
|
133
|
+
bd.position.set(box2d.processing_to_world(center))
|
134
|
+
cs = CircleShape.new
|
135
|
+
@body = box2d.create_body(bd)
|
136
|
+
body.create_fixture(fd)
|
137
|
+
# Give it some initial random velocity
|
138
|
+
body.setLinearVelocity(Vec2.new(rand(-5.0..5), rand(2.0..5)))
|
139
|
+
body.setAngularVelocity(rand(-5.0..5))
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# The Nature of Code
|
2
|
+
# Daniel Shiffman
|
3
|
+
# http://natureofcode.com
|
4
|
+
require 'forwardable'
|
5
|
+
|
6
|
+
# A rectangular box
|
7
|
+
class Box
|
8
|
+
extend Forwardable
|
9
|
+
def_delegators(:@app, :push_matrix, :pop_matrix, :fill, :rotate, :box2d,
|
10
|
+
:stroke_weight, :translate, :rect_mode, :stroke, :rect)
|
11
|
+
# We need to keep track of a Body and a width and height
|
12
|
+
attr_reader :body, :w, :h
|
13
|
+
|
14
|
+
# Constructor
|
15
|
+
def initialize(x, y, w, h, lock)
|
16
|
+
@w, @h = w, h
|
17
|
+
@app = $app
|
18
|
+
# Define and create the body
|
19
|
+
bd = BodyDef.new
|
20
|
+
bd.position.set(box2d.processing_to_world(Vec2.new(x, y)))
|
21
|
+
bd.type = lock ? BodyType::STATIC : BodyType::DYNAMIC
|
22
|
+
|
23
|
+
@body = box2d.createBody(bd)
|
24
|
+
|
25
|
+
# Define the shape -- a (this is what we use for a rectangle)
|
26
|
+
sd = PolygonShape.new
|
27
|
+
box2dW = box2d.scale_to_world(w / 2)
|
28
|
+
box2dH = box2d.scale_to_world(h / 2)
|
29
|
+
sd.setAsBox(box2dW, box2dH)
|
30
|
+
|
31
|
+
# Define a fixture
|
32
|
+
fd = FixtureDef.new
|
33
|
+
fd.shape = sd
|
34
|
+
# Parameters that affect physics
|
35
|
+
fd.density = 1
|
36
|
+
fd.friction = 0.3
|
37
|
+
fd.restitution = 0.5
|
38
|
+
|
39
|
+
body.createFixture(fd)
|
40
|
+
|
41
|
+
# Give it some initial random velocity
|
42
|
+
body.setLinearVelocity(Vec2.new(rand(-5..5),rand(2..5)))
|
43
|
+
body.setAngularVelocity(rand(-5..5))
|
44
|
+
end
|
45
|
+
|
46
|
+
# This function removes the particle from the box2d world
|
47
|
+
def killBody
|
48
|
+
box2d.destroyBody(body)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Drawing the box
|
52
|
+
def display
|
53
|
+
# We look at each body and get its screen position
|
54
|
+
pos = box2d.body_coord(body)
|
55
|
+
# Get its angle of rotation
|
56
|
+
a = body.getAngle
|
57
|
+
|
58
|
+
rect_mode(Java::ProcessingCore::PConstants::CENTER)
|
59
|
+
push_matrix
|
60
|
+
translate(pos.x,pos.y)
|
61
|
+
rotate(-a)
|
62
|
+
fill(127)
|
63
|
+
stroke(0)
|
64
|
+
stroke_weight(2)
|
65
|
+
rect(0,0,w,h)
|
66
|
+
pop_matrix
|
67
|
+
end
|
68
|
+
end
|