ruby-processing 1.0.5 → 1.0.6
Sign up to get free protection for your applications and to get access to all the features.
- 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")
|