Skip to content

Commit 48ff608

Browse files
committed
fireflies
1 parent 8ce00af commit 48ff608

File tree

3 files changed

+165
-0
lines changed

3 files changed

+165
-0
lines changed

contributed/data/background.png

365 KB
Loading

contributed/data/mask.png

10.4 KB
Loading

contributed/luciernagas.rb

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
# Luciernagas
2+
# After an original by Marcel Miranda aka reaktivo
3+
# https://github.com/reaktivo/rp-luciernagas
4+
# translated and updated by Martin Prout for JRubyArt
5+
# features use of Vec2D class and grid method
6+
load_library :control_panel
7+
8+
attr_reader :panel, :hide, :image_mask, :spots
9+
ACCURACY = 4
10+
11+
# Firefly holder
12+
Flyer = Struct.new(:pos, :to_pos, :rotation, :positions)
13+
14+
def settings
15+
size 1024, 480, P2D
16+
smooth
17+
end
18+
19+
def setup
20+
sketch_title 'Luciernagas'
21+
control_panel do |control|
22+
control.title 'Firefly Controller'
23+
control.look_feel 'Nimbus'
24+
control.slider(:speed, 0..20, 5)
25+
control.slider(:tail_length, 0..400, 30)
26+
control.slider(:rotation_max, 0..30, 7)
27+
control.slider(:target_radius, 5...100, 20)
28+
control.slider(:spot_distance, 5..200, 80)
29+
control.button :reset
30+
@panel = control
31+
end
32+
@hide = false
33+
@spotlight = create_spotlight
34+
@background = load_image(data_path('background.png'))
35+
@image_mask = load_image(data_path('mask.png'))
36+
load_spots(image_mask, ACCURACY)
37+
reset
38+
end
39+
40+
def reset
41+
@flyers = (0..100).map { create_flyer }
42+
end
43+
44+
def draw
45+
unless hide
46+
@hide = true
47+
panel.set_visible(hide)
48+
end
49+
image @background, 0, 0
50+
draw_lights
51+
draw_flyers
52+
end
53+
54+
def draw_lights
55+
lights = create_graphics width, height, P2D
56+
lights.begin_draw
57+
@flyers.each do |flyer|
58+
lights.push_matrix
59+
position = flyer.pos
60+
lights.translate position.x, position.y
61+
lights.image @spotlight, -@spotlight.width / 2, -@spotlight.height / 2
62+
lights.pop_matrix
63+
end
64+
lights.end_draw
65+
image_mask.mask lights
66+
image image_mask, 0, 0
67+
end
68+
69+
def draw_flyers
70+
rotation_max = @rotation_max / 100 * TWO_PI
71+
@flyers.each do |flyer|
72+
# check if point reached
73+
if flyer.pos.dist(flyer.to_pos) < @target_radius
74+
spot = find_spot_near flyer.pos, @spot_distance
75+
flyer.to_pos = spot
76+
end
77+
# set new rotation
78+
to_rotation = (flyer.to_pos - flyer.pos).heading
79+
to_rotation = find_nearest_rotation(flyer.rotation, to_rotation)
80+
# rotate to new direction
81+
if flyer.rotation < to_rotation
82+
flyer.rotation = flyer.rotation + rotation_max
83+
flyer.rotation = to_rotation if flyer.rotation > to_rotation
84+
else
85+
flyer.rotation = flyer.rotation - rotation_max
86+
flyer.rotation = to_rotation if flyer.rotation < to_rotation
87+
end
88+
# add tail position
89+
flyer.positions << flyer.pos.dup
90+
flyer.positions.shift while flyer.positions.size > @tail_length
91+
# set flyer position
92+
flyer.pos.x = flyer.pos.x + @speed * cos(flyer.rotation)
93+
flyer.pos.y = flyer.pos.y + @speed * sin(flyer.rotation)
94+
# draw flyer tail
95+
draw_tail flyer
96+
# draw flyer
97+
no_stroke
98+
fill 201, 242, 2
99+
push_matrix
100+
translate flyer.pos.x, flyer.pos.y
101+
ellipse 0, 0, 5, 5
102+
pop_matrix
103+
end
104+
end
105+
106+
def create_flyer
107+
spot = rand_spot
108+
to_spot = find_spot_near spot, @spot_distance
109+
rotation = rand * TWO_PI
110+
Flyer.new(spot, to_spot, rotation, [])
111+
end
112+
113+
def draw_tail(flyer)
114+
positions = flyer.positions
115+
return unless positions && !positions.empty?
116+
alpha_add = (255 / positions.size).to_i
117+
positions.each_index do |i|
118+
stroke(255, i * alpha_add)
119+
if i < positions.size - 2
120+
line(positions[i].x, positions[i].y, positions[i + 1].x, positions[i + 1].y)
121+
end
122+
end
123+
end
124+
125+
def load_spots(spot_image, accuracy = ACCURACY)
126+
@spots = []
127+
spot_image.load_pixels
128+
corner_color = spot_image.get 0, 0
129+
grid(spot_image.width, spot_image.height, accuracy, accuracy) do |x, y|
130+
color = spot_image.get(x, y)
131+
spots << Vec2D.new(x, y) if color != corner_color
132+
end
133+
end
134+
135+
def rand_spot
136+
spots.sample
137+
end
138+
139+
def find_spot_near(pos, distance)
140+
spot = Vec2D.new(Float::INFINITY, Float::INFINITY)
141+
spot = rand_spot until spot.dist(pos) < distance
142+
spot
143+
end
144+
145+
def find_nearest_rotation(from, to)
146+
dif = (to - from) % TWO_PI
147+
if dif != dif % PI
148+
dif = dif < 0 ? dif + TWO_PI : dif - TWO_PI
149+
end
150+
from + dif
151+
end
152+
153+
def create_spotlight
154+
size = 60
155+
spotlight = create_graphics size, size, P2D
156+
spotlight.begin_draw
157+
spotlight.no_stroke
158+
spotlight.fill 255, 60
159+
# spotlight.fill 255, 40
160+
half_size = size / 2
161+
spotlight.ellipse half_size, half_size, half_size, half_size
162+
spotlight.filter BLUR, 4
163+
spotlight.end_draw
164+
spotlight
165+
end

0 commit comments

Comments
 (0)