ruby-processing 1.0.5 → 1.0.6
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.
- data/CHANGELOG +8 -0
- data/lib/ruby-processing.rb +1 -1
- data/lib/ruby-processing/app.rb +85 -20
- data/lib/ruby-processing/exporters/base_exporter.rb +1 -1
- data/lib/ruby-processing/runners/base.rb +1 -1
- data/lib/ruby-processing/runners/watch.rb +1 -1
- data/lib/templates/applet/images/built_with.jpg +0 -0
- data/lib/templates/applet/images/ruby.jpg +0 -0
- data/lib/templates/applet/index.html.erb +7 -3
- data/lib/templates/application/Contents/Resources/sketch.icns +0 -0
- data/library/control_panel/control_panel.rb +18 -13
- data/samples/circle_collision.rb +72 -85
- data/samples/getting_started.rb +1 -0
- data/samples/jwishy.rb +8 -7
- data/samples/orbit.rb +27 -32
- data/samples/processing_app/3D/camera/ortho_vs_perspective.rb +22 -30
- data/samples/processing_app/3D/camera/perspective.rb +21 -29
- data/samples/processing_app/3D/form/brick_tower.rb +46 -54
- data/samples/processing_app/3D/typography/kinetic_type.rb +36 -35
- data/samples/processing_app/topics/simulate/multiple_particle_systems.rb +74 -73
- data/samples/reflection.rb +13 -22
- metadata +2 -2
data/CHANGELOG
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
v1.0.6 Inner Classes...
|
2
|
+
* Java-style inner classes. Any inner class of a sketch will now have the
|
3
|
+
Processing methods and constants proxied down for convenience.
|
4
|
+
* Sketches with tiny sizes get displayed in a nicer fashion.
|
5
|
+
* New Blue Logo: Ruby-Processing, literally.
|
6
|
+
* Moumar contributed a patch for the control_panel library, allowing your
|
7
|
+
sliders and buttons to have an initial value.
|
8
|
+
|
1
9
|
v1.0.5 Spring Cleaning...
|
2
10
|
* The "Learning Processing" examples are now a separate project, a
|
3
11
|
long-merited change. They'll grow up on their own at
|
data/lib/ruby-processing.rb
CHANGED
@@ -14,7 +14,7 @@ require 'ruby-processing/helpers/numeric'
|
|
14
14
|
|
15
15
|
# The top-level namespace, a home for all Ruby-Processing classes.
|
16
16
|
module Processing
|
17
|
-
VERSION = [1,0,
|
17
|
+
VERSION = [1,0,6] unless defined? Processing::VERSION
|
18
18
|
|
19
19
|
# Returns the current version of Ruby-Processing.
|
20
20
|
def self.version
|
data/lib/ruby-processing/app.rb
CHANGED
@@ -45,11 +45,9 @@ module Processing
|
|
45
45
|
:key_typed => :keyTyped
|
46
46
|
}
|
47
47
|
|
48
|
-
# Override the default width and height to make them a little larger.
|
49
|
-
DEFAULT_WIDTH = 200
|
50
|
-
DEFAULT_HEIGHT = 200
|
51
|
-
|
52
48
|
|
49
|
+
# When certain special methods get added to the sketch, we need to let
|
50
|
+
# Processing call them by their expected Java names.
|
53
51
|
def self.method_added(method_name) #:nodoc:
|
54
52
|
if METHODS_TO_WATCH_FOR.keys.include?(method_name)
|
55
53
|
alias_method METHODS_TO_WATCH_FOR[method_name], method_name
|
@@ -176,11 +174,12 @@ module Processing
|
|
176
174
|
proxy_java_fields
|
177
175
|
set_sketch_path unless online?
|
178
176
|
make_accessible_to_the_browser if online?
|
179
|
-
|
180
|
-
@
|
181
|
-
@
|
182
|
-
@
|
183
|
-
|
177
|
+
default_title = File.basename(Processing::SKETCH_PATH).sub(/(\.rb|\.pde)$/, '').titleize
|
178
|
+
@width = options[:width] || DEFAULT_WIDTH
|
179
|
+
@height = options[:height] || DEFAULT_HEIGHT
|
180
|
+
@title = options[:title] || default_title
|
181
|
+
@render_mode ||= JAVA2D
|
182
|
+
@@full_screen ||= options[:full_screen]
|
184
183
|
self.init
|
185
184
|
determine_how_to_display
|
186
185
|
end
|
@@ -189,6 +188,7 @@ module Processing
|
|
189
188
|
# Make sure we set the size if we set it before we start the animation thread.
|
190
189
|
def start
|
191
190
|
self.size(@width, @height)
|
191
|
+
mix_proxy_into_inner_classes
|
192
192
|
super()
|
193
193
|
end
|
194
194
|
|
@@ -309,9 +309,9 @@ module Processing
|
|
309
309
|
end
|
310
310
|
|
311
311
|
|
312
|
-
# Is the sketch
|
313
|
-
def
|
314
|
-
@
|
312
|
+
# Is the sketch finished?
|
313
|
+
def finished?
|
314
|
+
@declared_fields['finished'].value(java_self)
|
315
315
|
end
|
316
316
|
|
317
317
|
|
@@ -351,15 +351,28 @@ module Processing
|
|
351
351
|
# some methods. Add to this list as needed.
|
352
352
|
def proxy_java_fields
|
353
353
|
@declared_fields = {}
|
354
|
-
fields = %w(sketchPath key frameRate defaultSize)
|
354
|
+
fields = %w(sketchPath key frameRate defaultSize finished)
|
355
355
|
fields.each {|f| @declared_fields[f] = java_class.declared_field(f) }
|
356
356
|
end
|
357
357
|
|
358
358
|
|
359
|
+
# Mix the Processing::Proxy into any inner classes defined for the
|
360
|
+
# sketch, attempting to mimic the behavior of Java's inner classes.
|
361
|
+
def mix_proxy_into_inner_classes
|
362
|
+
unwanted = /Java::ProcessingCore/
|
363
|
+
klass = Processing::App.sketch_class
|
364
|
+
klass.constants.each do |name|
|
365
|
+
const = klass.const_get name
|
366
|
+
next if const.class != Class || const.to_s.match(unwanted)
|
367
|
+
const.class_eval 'include Processing::Proxy'
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
|
359
372
|
# Tests to see which display method should run.
|
360
373
|
def determine_how_to_display
|
361
374
|
# Wait for init to get its grey tracksuit on and run a few laps.
|
362
|
-
sleep 0.02 while default_size? && !@@full_screen
|
375
|
+
sleep 0.02 while default_size? && !finished? && !@@full_screen
|
363
376
|
|
364
377
|
if online?
|
365
378
|
display_in_an_applet
|
@@ -376,7 +389,6 @@ module Processing
|
|
376
389
|
end
|
377
390
|
|
378
391
|
|
379
|
-
# Go full screen, if possible
|
380
392
|
def display_full_screen(display)
|
381
393
|
@frame = java.awt.Frame.new(display.default_configuration)
|
382
394
|
mode = display.display_mode
|
@@ -396,12 +408,17 @@ module Processing
|
|
396
408
|
|
397
409
|
def display_in_a_window
|
398
410
|
@frame = javax.swing.JFrame.new(@title)
|
399
|
-
@frame.
|
411
|
+
@frame.set_layout nil
|
412
|
+
@frame.add self
|
400
413
|
@frame.pack
|
401
414
|
@frame.set_default_close_operation(javax.swing.JFrame::EXIT_ON_CLOSE)
|
402
415
|
@frame.set_resizable(false)
|
403
|
-
|
404
|
-
|
416
|
+
ins = @frame.get_insets
|
417
|
+
hpad, vpad = ins.left + ins.right, ins.top + ins.bottom
|
418
|
+
frame_width = [width, MIN_WINDOW_WIDTH].max + hpad
|
419
|
+
frame_height = [height, MIN_WINDOW_HEIGHT].max + vpad
|
420
|
+
@frame.set_size(frame_width, frame_height)
|
421
|
+
set_bounds((frame_width - width) / 2.0, (frame_height - vpad - height) / 2.0, width, height)
|
405
422
|
@frame.show
|
406
423
|
end
|
407
424
|
|
@@ -429,5 +446,53 @@ module Processing
|
|
429
446
|
window.set_member('ruby', ruby)
|
430
447
|
end
|
431
448
|
|
432
|
-
end
|
433
|
-
|
449
|
+
end # Processing::App
|
450
|
+
|
451
|
+
|
452
|
+
# This module will get automatically mixed in to any inner class of
|
453
|
+
# a Processing::App, in order to mimic Java's inner classes, which have
|
454
|
+
# unfettered access to the methods defined in the surrounding class.
|
455
|
+
module Proxy
|
456
|
+
|
457
|
+
# Generate the list of method names that we'd like to proxy for inner classes.
|
458
|
+
# Nothing camelCased, nothing __internal__, just the Processing API.
|
459
|
+
def self.desired_method_names
|
460
|
+
bad_method = /__/ # Internal JRuby methods.
|
461
|
+
unwanted = PApplet.superclass.instance_methods + Object.instance_methods
|
462
|
+
methods = Processing::App.public_instance_methods
|
463
|
+
methods.reject {|m| unwanted.include?(m) || bad_method.match(m) }
|
464
|
+
end
|
465
|
+
|
466
|
+
|
467
|
+
# Proxy methods through to the sketch. Perhaps extend this to support blocks?
|
468
|
+
def self.proxy_methods
|
469
|
+
code = desired_method_names.inject('') do |code, method|
|
470
|
+
code << <<-EOS
|
471
|
+
def #{method}(*args) # def rect(*args)
|
472
|
+
$app.#{method} *args # $app.rect *args
|
473
|
+
end # end
|
474
|
+
EOS
|
475
|
+
end
|
476
|
+
module_eval(code, "Processing::Proxy", 1)
|
477
|
+
end
|
478
|
+
|
479
|
+
|
480
|
+
# Proxy the sketch's constants on to the inner classes.
|
481
|
+
def self.proxy_constants
|
482
|
+
Processing::App.constants.each do |name|
|
483
|
+
Processing::Proxy.const_set(name, Processing::App.const_get(name))
|
484
|
+
end
|
485
|
+
end
|
486
|
+
|
487
|
+
|
488
|
+
# Don't do all of the work unless we have an inner class that needs it.
|
489
|
+
def self.included(inner_class)
|
490
|
+
return if @already_defined
|
491
|
+
proxy_methods
|
492
|
+
proxy_constants
|
493
|
+
@already_defined = true
|
494
|
+
end
|
495
|
+
|
496
|
+
end # Processing::Proxy
|
497
|
+
|
498
|
+
end # Processing
|
@@ -8,7 +8,7 @@ module Processing
|
|
8
8
|
class BaseExporter
|
9
9
|
include FileUtils
|
10
10
|
|
11
|
-
DEFAULT_DIMENSIONS = {'width' =>
|
11
|
+
DEFAULT_DIMENSIONS = {'width' => '100', 'height' => '100'}
|
12
12
|
DEFAULT_DESCRIPTION = ''
|
13
13
|
|
14
14
|
# Returns the filepath, basename, and directory name of the sketch.
|
@@ -28,7 +28,7 @@ module Processing
|
|
28
28
|
def self.load_and_run_sketch
|
29
29
|
source = self.read_sketch_source
|
30
30
|
has_sketch = !!source.match(/^[^#]*< Processing::App/)
|
31
|
-
has_methods = !!source.match(/^[^#]*def
|
31
|
+
has_methods = !!source.match(/^[^#]*(def\s+setup|def\s+draw)/)
|
32
32
|
|
33
33
|
if has_sketch
|
34
34
|
load Processing::SKETCH_PATH
|
Binary file
|
Binary file
|
@@ -24,11 +24,14 @@
|
|
24
24
|
padding: 0;
|
25
25
|
}
|
26
26
|
#container {
|
27
|
-
width: <%= @width + 14 %>px;
|
27
|
+
width: <%= [@width.to_i, 200].max + 14 %>px;
|
28
28
|
margin: 0 auto;
|
29
29
|
margin-top: 20px;
|
30
|
+
text-align: center;
|
30
31
|
}
|
31
32
|
#the_applet {
|
33
|
+
margin: 0 auto;
|
34
|
+
width: <%= @width.to_i %>px;
|
32
35
|
padding: 6px;
|
33
36
|
padding-top: 7px; padding-bottom: 2px;
|
34
37
|
background: #262626 url(images/top.png) top left repeat-x;
|
@@ -42,7 +45,7 @@
|
|
42
45
|
}
|
43
46
|
#description {
|
44
47
|
font-size: 12px;
|
45
|
-
width: <%= @width - 16
|
48
|
+
width: <%= [@width.to_i, 200].max - 16 %>px;
|
46
49
|
padding: 7px 15px 7px 15px;
|
47
50
|
background: #111;
|
48
51
|
text-align: justify;
|
@@ -74,7 +77,8 @@
|
|
74
77
|
<param name="archive" value="<%= @file_list %>" />
|
75
78
|
<param name="jruby.eval" value="ARGV[0] = '<%= @main_file %>'; require 'ruby-processing/runners/run.rb'" />
|
76
79
|
<param name="image" value="images/ruby.jpg" />
|
77
|
-
<param name="
|
80
|
+
<param name="centerimage" value="true" />
|
81
|
+
<param name="boxmessage" value="Loading <%= @title %>..." />
|
78
82
|
<param name="lang" value="en" />
|
79
83
|
<param name="mayscript" value="true" />
|
80
84
|
<param name="scriptable" value="true" />
|
Binary file
|
@@ -3,11 +3,12 @@
|
|
3
3
|
# These controls will set instance variables on the sketches.
|
4
4
|
|
5
5
|
# You can make sliders, checkboxes, buttons, and drop-down menus.
|
6
|
+
# (optionally) pass the range and default value.
|
6
7
|
|
7
8
|
module ControlPanel
|
8
9
|
|
9
10
|
class Slider < javax.swing.JSlider
|
10
|
-
def initialize(name, range,
|
11
|
+
def initialize(control_panel, name, range, initial_value, proc=nil)
|
11
12
|
min, max = range.begin * 100, range.end * 100
|
12
13
|
super(min, max)
|
13
14
|
set_minor_tick_spacing((max - min).abs / 10)
|
@@ -20,6 +21,8 @@ module ControlPanel
|
|
20
21
|
$app.instance_variable_set("@#{name}", value) unless value.nil?
|
21
22
|
proc.call(value) if proc
|
22
23
|
end
|
24
|
+
set_value(initial_value ? initial_value*100 : min)
|
25
|
+
fire_state_changed
|
23
26
|
end
|
24
27
|
|
25
28
|
def value
|
@@ -35,7 +38,7 @@ module ControlPanel
|
|
35
38
|
|
36
39
|
|
37
40
|
class Menu < javax.swing.JComboBox
|
38
|
-
def initialize(name, elements,
|
41
|
+
def initialize(control_panel, name, elements, initial_value, proc=nil)
|
39
42
|
super(elements.to_java(:String))
|
40
43
|
set_preferred_size(java.awt.Dimension.new(190, 30))
|
41
44
|
control_panel.add_element(self, name)
|
@@ -43,6 +46,7 @@ module ControlPanel
|
|
43
46
|
$app.instance_variable_set("@#{name}", value) unless value.nil?
|
44
47
|
proc.call(value) if proc
|
45
48
|
end
|
49
|
+
set_selected_index(initial_value ? elements.index(initial_value) : 0)
|
46
50
|
end
|
47
51
|
|
48
52
|
def value
|
@@ -52,7 +56,7 @@ module ControlPanel
|
|
52
56
|
|
53
57
|
|
54
58
|
class Checkbox < javax.swing.JCheckBox
|
55
|
-
def initialize(
|
59
|
+
def initialize(control_panel, name, proc=nil)
|
56
60
|
@control_panel = control_panel
|
57
61
|
super(name.to_s)
|
58
62
|
set_preferred_size(java.awt.Dimension.new(190, 64))
|
@@ -71,7 +75,7 @@ module ControlPanel
|
|
71
75
|
|
72
76
|
|
73
77
|
class Button < javax.swing.JButton
|
74
|
-
def initialize(
|
78
|
+
def initialize(control_panel, name, proc=nil)
|
75
79
|
super(name.to_s)
|
76
80
|
set_preferred_size(java.awt.Dimension.new(170, 64))
|
77
81
|
control_panel.add_element(self, name, false, true)
|
@@ -99,7 +103,7 @@ module ControlPanel
|
|
99
103
|
set_resizable false
|
100
104
|
# Need to wait for the sketch to finish sizing...
|
101
105
|
Thread.new do
|
102
|
-
sleep 0.2 while $app.default_size?
|
106
|
+
sleep 0.2 while $app.default_size?
|
103
107
|
set_location($app.width + 10, 0)
|
104
108
|
show
|
105
109
|
end
|
@@ -120,20 +124,21 @@ module ControlPanel
|
|
120
124
|
dispose
|
121
125
|
end
|
122
126
|
|
123
|
-
def slider(name, range=0..100, &block)
|
124
|
-
slider = Slider.new(name, range,
|
127
|
+
def slider(name, range=0..100, initial_value = nil, &block)
|
128
|
+
slider = Slider.new(self, name, range, initial_value, block || nil)
|
125
129
|
end
|
126
130
|
|
127
|
-
def menu(name,
|
128
|
-
menu = Menu.new(name, elements,
|
131
|
+
def menu(name, elements, initial_value = nil, &block)
|
132
|
+
menu = Menu.new(self, name, elements, initial_value, block || nil)
|
129
133
|
end
|
130
134
|
|
131
|
-
def checkbox(name, &block)
|
132
|
-
checkbox = Checkbox.new(
|
135
|
+
def checkbox(name, initial_value = nil, &block)
|
136
|
+
checkbox = Checkbox.new(self, name, block || nil)
|
137
|
+
checkbox.do_click if initial_value == true
|
133
138
|
end
|
134
139
|
|
135
140
|
def button(name, &block)
|
136
|
-
button = Button.new(
|
141
|
+
button = Button.new(self, name, block || nil)
|
137
142
|
end
|
138
143
|
end
|
139
144
|
|
@@ -150,4 +155,4 @@ module ControlPanel
|
|
150
155
|
end
|
151
156
|
|
152
157
|
|
153
|
-
Processing::App.send :include, ControlPanel::InstanceMethods
|
158
|
+
Processing::App.send :include, ControlPanel::InstanceMethods
|
data/samples/circle_collision.rb
CHANGED
@@ -1,52 +1,45 @@
|
|
1
1
|
# Based on http://processing.org/learning/topics/circlecollision.html
|
2
2
|
# by Joe Holt
|
3
3
|
|
4
|
-
require 'ruby-processing'
|
5
|
-
|
6
|
-
class Vect2D
|
7
|
-
attr_accessor :vx, :vy
|
8
|
-
def initialize(vx = 0.0, vy = 0.0)
|
9
|
-
@vx = vx
|
10
|
-
@vy = vy
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
|
15
|
-
class Ball
|
16
|
-
attr_accessor :x, :y, :r, :m, :vec
|
17
|
-
def initialize(r = 0.0, vec = nil, x = 0.0, y = 0.0)
|
18
|
-
@x = x
|
19
|
-
@y = y
|
20
|
-
@r = r
|
21
|
-
@m = r*0.1
|
22
|
-
@vec = vec
|
23
|
-
end
|
24
|
-
|
25
|
-
def draw
|
26
|
-
r = @r * 2
|
27
|
-
P.ellipse @x, @y, r, r
|
28
|
-
@px = @x
|
29
|
-
@py = @y
|
30
|
-
end
|
31
|
-
|
32
|
-
def erase
|
33
|
-
r = @r * 2
|
34
|
-
P.rect @px, @py, r, r
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
|
39
4
|
class Sketch < Processing::App
|
5
|
+
|
6
|
+
# This inner class demonstrates the use of Ruby-Processing's emulation of
|
7
|
+
# Java inner classes. The Balls are able to call Processing::App methods.
|
8
|
+
class Ball
|
9
|
+
attr_accessor :x, :y, :r, :m, :vec
|
10
|
+
def initialize(r = 0.0, vec = nil, x = 0.0, y = 0.0)
|
11
|
+
@x, @y, @r = x, y, r
|
12
|
+
@m = r * 0.1
|
13
|
+
@vec = vec
|
14
|
+
end
|
15
|
+
|
16
|
+
def move
|
17
|
+
@x += @vec.x
|
18
|
+
@y += @vec.y
|
19
|
+
end
|
20
|
+
|
21
|
+
def draw
|
22
|
+
r = @r * 2
|
23
|
+
ellipse @x, @y, r, r
|
24
|
+
@px, @py = @x, @y
|
25
|
+
end
|
26
|
+
|
27
|
+
def erase
|
28
|
+
r = @r * 2
|
29
|
+
rect @px, @py, r, r
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
40
33
|
|
41
34
|
def setup
|
42
35
|
smooth
|
43
|
-
|
44
|
-
|
45
|
-
|
36
|
+
no_stroke
|
37
|
+
frame_rate 30
|
38
|
+
rect_mode RADIUS
|
46
39
|
|
47
40
|
@balls = []
|
48
|
-
5.times { @balls << Ball.new(10,
|
49
|
-
2.times { @balls << Ball.new(40,
|
41
|
+
5.times { @balls << Ball.new(10, PVector.new(2.15, -1.35), *empty_space(15)) }
|
42
|
+
2.times { @balls << Ball.new(40, PVector.new(-1.65, 0.42), *empty_space(45)) }
|
50
43
|
|
51
44
|
@frame_time = nil
|
52
45
|
@frame_count = 0
|
@@ -55,9 +48,7 @@ class Sketch < Processing::App
|
|
55
48
|
|
56
49
|
def draw
|
57
50
|
t = Time.now
|
58
|
-
if @frame_time
|
59
|
-
fps = 1.0 / (t - @frame_time)
|
60
|
-
end
|
51
|
+
fps = 1.0 / (t - @frame_time) if @frame_time
|
61
52
|
@frame_time = t
|
62
53
|
@frame_count += 1
|
63
54
|
|
@@ -72,19 +63,17 @@ class Sketch < Processing::App
|
|
72
63
|
# move the balls
|
73
64
|
fill 240
|
74
65
|
@balls.each do |ball|
|
75
|
-
ball.
|
76
|
-
ball.y += ball.vec.vy
|
66
|
+
ball.move
|
77
67
|
ball.draw
|
78
|
-
|
68
|
+
check_boundary_collision ball
|
79
69
|
end
|
80
|
-
|
81
|
-
1 * 20
|
70
|
+
check_object_collisions
|
82
71
|
end
|
83
72
|
|
84
73
|
|
85
|
-
def
|
74
|
+
def empty_space(r)
|
86
75
|
x = y = nil
|
87
|
-
while !x || !
|
76
|
+
while !x || !empty_space?(x, y, r) do
|
88
77
|
x = rand(width)
|
89
78
|
y = rand(height)
|
90
79
|
end
|
@@ -92,7 +81,7 @@ class Sketch < Processing::App
|
|
92
81
|
end
|
93
82
|
|
94
83
|
|
95
|
-
def
|
84
|
+
def empty_space?(x, y, r)
|
96
85
|
@balls.each do |ball|
|
97
86
|
vx = x - ball.x
|
98
87
|
vy = y - ball.y
|
@@ -103,7 +92,7 @@ class Sketch < Processing::App
|
|
103
92
|
end
|
104
93
|
|
105
94
|
|
106
|
-
def
|
95
|
+
def check_object_collisions
|
107
96
|
|
108
97
|
(0...(@balls.length)).each do |ia|
|
109
98
|
((ia+1)...(@balls.length)).each do |ib|
|
@@ -112,15 +101,15 @@ class Sketch < Processing::App
|
|
112
101
|
bb = @balls[ib]
|
113
102
|
|
114
103
|
# get distances between the balls components
|
115
|
-
bVect =
|
116
|
-
bVect.
|
117
|
-
bVect.
|
104
|
+
bVect = PVector.new
|
105
|
+
bVect.x = bb.x - ba.x
|
106
|
+
bVect.y = bb.y - ba.y
|
118
107
|
|
119
108
|
# calculate magnitude of the vector separating the balls
|
120
|
-
bVectMag = sqrt(bVect.
|
109
|
+
bVectMag = sqrt(bVect.x * bVect.x + bVect.y * bVect.y)
|
121
110
|
next if bVectMag >= ba.r + bb.r
|
122
111
|
# get angle of bVect
|
123
|
-
theta = atan2(bVect.
|
112
|
+
theta = atan2(bVect.y, bVect.x)
|
124
113
|
# precalculate trig values
|
125
114
|
sine = sin(theta)
|
126
115
|
cosine = cos(theta)
|
@@ -134,32 +123,32 @@ class Sketch < Processing::App
|
|
134
123
|
# bTemp[0].x and bTemp[0].y will initialize
|
135
124
|
# automatically to 0.0, which is what you want
|
136
125
|
# since bb will rotate around ba
|
137
|
-
bTemp[1].x = cosine * bVect.
|
138
|
-
bTemp[1].y = cosine * bVect.
|
126
|
+
bTemp[1].x = cosine * bVect.x + sine * bVect.y
|
127
|
+
bTemp[1].y = cosine * bVect.y - sine * bVect.x
|
139
128
|
|
140
129
|
# rotate Temporary velocities
|
141
|
-
vTemp = [
|
142
|
-
vTemp[0].
|
143
|
-
vTemp[0].
|
144
|
-
vTemp[1].
|
145
|
-
vTemp[1].
|
130
|
+
vTemp = [PVector.new, PVector.new]
|
131
|
+
vTemp[0].x = cosine * ba.vec.x + sine * ba.vec.y
|
132
|
+
vTemp[0].y = cosine * ba.vec.y - sine * ba.vec.x
|
133
|
+
vTemp[1].x = cosine * bb.vec.x + sine * bb.vec.y
|
134
|
+
vTemp[1].y = cosine * bb.vec.y - sine * bb.vec.x
|
146
135
|
|
147
136
|
# Now that velocities are rotated, you can use 1D
|
148
137
|
# conservation of momentum equations to calculate
|
149
138
|
# the final velocity along the x-axis.
|
150
|
-
vFinal = [
|
139
|
+
vFinal = [PVector.new, PVector.new]
|
151
140
|
# final rotated velocity for ba
|
152
|
-
vFinal[0].
|
153
|
-
vTemp[1].
|
154
|
-
vFinal[0].
|
141
|
+
vFinal[0].x = ((ba.m - bb.m) * vTemp[0].x + 2 * bb.m *
|
142
|
+
vTemp[1].x) / (ba.m + bb.m)
|
143
|
+
vFinal[0].y = vTemp[0].y
|
155
144
|
# final rotated velocity for ba
|
156
|
-
vFinal[1].
|
157
|
-
vTemp[0].
|
158
|
-
vFinal[1].
|
145
|
+
vFinal[1].x = ((bb.m - ba.m) * vTemp[1].x + 2 * ba.m *
|
146
|
+
vTemp[0].x) / (ba.m + bb.m)
|
147
|
+
vFinal[1].y = vTemp[1].y
|
159
148
|
|
160
149
|
# hack to avoid clumping
|
161
|
-
bTemp[0].x += vFinal[0].
|
162
|
-
bTemp[1].x += vFinal[1].
|
150
|
+
bTemp[0].x += vFinal[0].x
|
151
|
+
bTemp[1].x += vFinal[1].x
|
163
152
|
|
164
153
|
# Rotate ball positions and velocities back
|
165
154
|
# Reverse signs in trig expressions to rotate
|
@@ -178,36 +167,34 @@ class Sketch < Processing::App
|
|
178
167
|
ba.y = ba.y + bFinal[0].y
|
179
168
|
|
180
169
|
# update velocities
|
181
|
-
ba.vec.
|
182
|
-
ba.vec.
|
183
|
-
bb.vec.
|
184
|
-
bb.vec.
|
170
|
+
ba.vec.x = cosine * vFinal[0].x - sine * vFinal[0].y
|
171
|
+
ba.vec.y = cosine * vFinal[0].y + sine * vFinal[0].x
|
172
|
+
bb.vec.x = cosine * vFinal[1].x - sine * vFinal[1].y
|
173
|
+
bb.vec.y = cosine * vFinal[1].y + sine * vFinal[1].x
|
185
174
|
end
|
186
175
|
end
|
187
176
|
|
188
177
|
end
|
189
178
|
|
190
179
|
|
191
|
-
def
|
192
|
-
|
180
|
+
def check_boundary_collision(ball)
|
193
181
|
if ball.x > width-ball.r
|
194
182
|
ball.x = width-ball.r
|
195
|
-
ball.vec.
|
183
|
+
ball.vec.x *= -1
|
196
184
|
elsif ball.x < ball.r
|
197
185
|
ball.x = ball.r
|
198
|
-
ball.vec.
|
186
|
+
ball.vec.x *= -1
|
199
187
|
end
|
200
188
|
if ball.y > height-ball.r
|
201
189
|
ball.y = height-ball.r
|
202
|
-
ball.vec.
|
190
|
+
ball.vec.y *= -1
|
203
191
|
elsif ball.y < ball.r
|
204
192
|
ball.y = ball.r
|
205
|
-
ball.vec.
|
193
|
+
ball.vec.y *= -1
|
206
194
|
end
|
207
|
-
|
208
195
|
end
|
209
196
|
|
210
197
|
end
|
211
198
|
|
212
199
|
|
213
|
-
|
200
|
+
Sketch.new(:width => 400, :height => 400, :title => "CircleCollision2")
|