graphics 1.0.0b1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,86 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ require "graphics"
4
+
5
+ class Ball < Graphics::Body
6
+ COUNT = 50
7
+
8
+ G = V[0, -18 / 60.0]
9
+
10
+ attr_accessor :g
11
+
12
+ def initialize w
13
+ super
14
+
15
+ self.a = rand 180
16
+ self.m = rand 100
17
+ self.g = G
18
+ end
19
+
20
+ def update
21
+ fall
22
+ move
23
+ bounce
24
+ end
25
+
26
+ def fall
27
+ self.velocity += g
28
+ end
29
+
30
+ def label
31
+ l = "%.1f %.1f" % dx_dy
32
+ w.text l, x-10, y-40, :white
33
+ end
34
+
35
+ def draw
36
+ # w.angle x, y, a, 3*m, :red
37
+ w.angle x, y, a, 50, :red
38
+ w.circle x, y, 5, :white, :filled
39
+ # label
40
+ end
41
+ end
42
+
43
+ class BounceSimulation < Graphics::Simulation
44
+ attr_accessor :bs
45
+
46
+ def initialize
47
+ super 640, 640, 16, "Bounce"
48
+
49
+ self.bs = populate Ball
50
+ end
51
+
52
+ def update n
53
+ bs.each(&:update)
54
+ end
55
+
56
+ def draw n
57
+ clear
58
+ bs.each(&:draw)
59
+ bs.first.label
60
+ fps n
61
+ end
62
+
63
+ def handle_keys
64
+ super
65
+ randomize if SDL::Key.press? SDL::Key::SPACE
66
+ reverse if SDL::Key.press? SDL::Key::R
67
+ end
68
+
69
+ def randomize
70
+ bs.each do |b|
71
+ b.m = rand(100)
72
+ b.a = rand(180)
73
+ end
74
+ end
75
+
76
+ def reverse
77
+ return if @guard
78
+ @guard = true
79
+ bs.each do |b|
80
+ b.g *= -1
81
+ end
82
+ @guard = false
83
+ end
84
+ end
85
+
86
+ BounceSimulation.new.run
@@ -0,0 +1,74 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ require "graphics"
4
+
5
+ class Sprite < Graphics::Body
6
+ COUNT = 8
7
+
8
+ attr_accessor :image
9
+
10
+ def initialize w
11
+ super w
12
+
13
+ self.a = random_angle
14
+ self.m = 5
15
+ end
16
+
17
+ def update
18
+ move
19
+ bounce
20
+ end
21
+
22
+ def collide
23
+ self.a = (a + 180).degrees
24
+ end
25
+
26
+ def draw
27
+ w.blit image, x, y, a
28
+ end
29
+
30
+ def collide_with? other
31
+ w.cmap.collision_check(x, y, w.cmap, other.x, other.y) != nil
32
+ end
33
+ end
34
+
35
+ class Collision < Graphics::Simulation
36
+ attr_accessor :sprites, :cmap, :image
37
+
38
+ def initialize
39
+ super 850, 850, 16, "Collision"
40
+
41
+ self.image = SDL::Surface.load "resources/images/body.png"
42
+ self.cmap = image.make_collision_map
43
+
44
+ self.sprites = populate Sprite do |s|
45
+ s.image = image
46
+ end
47
+ end
48
+
49
+ def inspect
50
+ "<Screen ...>"
51
+ end
52
+
53
+ def detect_collisions(sprites)
54
+ collisions = []
55
+ sprites.combination(2).each do |a, b|
56
+ collisions << a << b if a.collide_with? b
57
+ end
58
+ collisions.uniq
59
+ end
60
+
61
+ def update n
62
+ sprites.each(&:update)
63
+ detect_collisions(sprites).each(&:collide)
64
+ end
65
+
66
+ def draw n
67
+ clear
68
+
69
+ sprites.each(&:draw)
70
+ fps n
71
+ end
72
+ end
73
+
74
+ Collision.new.run
@@ -0,0 +1,90 @@
1
+ #!/usr/local/bin/ruby -w
2
+ # -*- coding: utf-8 -*-
3
+
4
+ require "graphics"
5
+
6
+ class Ball < Graphics::Body
7
+ def initialize w
8
+ super
9
+
10
+ self.x = 50
11
+ self.y = 50
12
+
13
+ self.a = 60
14
+ self.m = 3
15
+ end
16
+
17
+ def update
18
+ move
19
+ wrap
20
+ end
21
+
22
+ def draw n
23
+ a = n % 360
24
+
25
+ w.angle x, y, a, 50, :green
26
+ w.circle x, y, 5, :white, :filled
27
+ end
28
+ end
29
+
30
+ class Demo < Graphics::Simulation
31
+ attr_accessor :ball, :img
32
+
33
+ def initialize
34
+ super 800, 800, 16, "Boid"
35
+ self.ball = Ball.new self
36
+
37
+ r = color[:red]
38
+
39
+ self.img = sprite 10, 10 do
40
+ circle 5, 5, 5, :white, :filled
41
+ end
42
+ end
43
+
44
+ def update n
45
+ ball.update
46
+ end
47
+
48
+ def draw n
49
+ clear
50
+
51
+ line 100, 50, 125, 75, :white
52
+
53
+ hline 100, :white
54
+
55
+ vline 100, :white
56
+
57
+ angle 125, 50, 45, 10, :white
58
+
59
+ fast_rect 150, 50, 10, 10, :white
60
+
61
+ point 175, 50, :green
62
+
63
+ rect 200, 50, 10, 10, :white
64
+
65
+ circle 225, 50, 10, :white
66
+
67
+ ellipse 250, 50, 10, 10, :white
68
+
69
+ bezier 275, 50, 275, 100, 285, 0, 300, 50, :white
70
+
71
+ rect 300, 25, 50, 50, :white
72
+ blit img, 325, 50, 0
73
+
74
+ text "blah", 350, 50, :white
75
+
76
+ x, y, * = mouse
77
+ rect x, y, 150, 50, :white
78
+ text "#{x}/#{y}", x, y, :white
79
+
80
+ debug "debug"
81
+
82
+ ball.draw n
83
+
84
+ fps n
85
+ end
86
+ end
87
+
88
+ if $0 == __FILE__
89
+ Demo.new.run
90
+ end
@@ -0,0 +1,70 @@
1
+ #!/usr/local/bin/ruby -w
2
+ # -*- coding: utf-8 -*-
3
+
4
+ require "graphics"
5
+
6
+ class Editor < Graphics::Simulation
7
+ attr_accessor :overlay, :s, :lines
8
+
9
+ alias :overlay? :overlay
10
+
11
+ def initialize
12
+ super 850, 850, 16, self.class.name
13
+
14
+ self.overlay = true
15
+ self.s = ""
16
+ self.lines = []
17
+ end
18
+
19
+ def handle_event e, n
20
+ case e
21
+ when SDL::Event::KeyDown then
22
+ if e.mod & (SDL::Key::MOD_LCTRL | SDL::Key::MOD_RCTRL) != 0 then
23
+ case e.sym.chr
24
+ when "t" then
25
+ self.overlay = ! self.overlay
26
+ end
27
+ else
28
+ c = e.sym.chr rescue ""
29
+ c.upcase! if e.mod & (SDL::Key::MOD_LSHIFT | SDL::Key::MOD_RSHIFT) != 0
30
+ case c
31
+ when "\r" then
32
+ c = "\n"
33
+ lines << s.dup
34
+ s.clear
35
+ return
36
+ when "\b" then
37
+ self.s = s[0..-2]
38
+ return
39
+ end
40
+ s << c
41
+ end
42
+ else
43
+ super
44
+ end
45
+ end
46
+
47
+ def draw n
48
+ clear
49
+
50
+ draw_scene
51
+ draw_overlay
52
+ end
53
+
54
+ def draw_scene
55
+ end
56
+
57
+ def draw_overlay
58
+ if overlay? then
59
+ lines.each_with_index do |l, i|
60
+ text l, 10, ((lines.size-i)*font.height), :gray
61
+ end
62
+
63
+ text "> #{s}_", 10, 0, :white
64
+ end
65
+ end
66
+ end
67
+
68
+ if $0 == __FILE__
69
+ Editor.new.run
70
+ end
@@ -0,0 +1,246 @@
1
+ require "graphics"
2
+
3
+ class Float
4
+ ##
5
+ # A floating-point friendly `between?` function that excludes
6
+ # the lower bound.
7
+ # Equivalent to `min < x <= max`
8
+ ##
9
+ def xbetween? min, max
10
+ min < self && self <= max
11
+ end
12
+ end
13
+
14
+ class Particle
15
+ attr_accessor :density, :position, :velocity,
16
+ :pressure_force, :viscosity_force
17
+ def initialize pos
18
+ # Scalars
19
+ @density = 0
20
+
21
+ # Forces
22
+ @position = pos
23
+ @velocity = V::ZERO
24
+ @pressure_force = V::ZERO
25
+ @viscosity_force = V::ZERO
26
+ end
27
+ end
28
+
29
+ class SPH
30
+ ##
31
+ # Constants
32
+ #
33
+
34
+ MASS = 5 # Particle mass
35
+ DENSITY = 1 # Rest density
36
+ GRAVITY = V[0, -0.5]
37
+ H = 1 # Smoothing cutoff- essentially, particle size
38
+ K = 20 # Temperature constant- higher means particle repel more strongly
39
+ ETA = 1 # Viscosity constant- higher for more viscous
40
+
41
+ attr_reader :particles
42
+
43
+ def initialize
44
+ # Instantiate particles!
45
+ @particles = []
46
+ (0..10).each do |x|
47
+ (0..10).each do |y|
48
+ jitter = rand * 0.1
49
+ particles << Particle.new(V[x+1+jitter, y+5])
50
+ end
51
+ end
52
+ end
53
+
54
+ ##
55
+ # A weighting function (kernel) for the contribution of each neighbor
56
+ # to a particle's density. Forms a nice smooth gradient from the center
57
+ # of a particle to H, where it's 0
58
+ #
59
+
60
+ def weight r, h
61
+ len_r = r.magnitude
62
+
63
+ if len_r.xbetween? 0, h
64
+ 315.0 / (64 * Math::PI * h**9) * (h**2 - len_r**2)**3
65
+ else
66
+ 0.0
67
+ end
68
+ end
69
+
70
+ ##
71
+ # Gradient ( that is, V(dx, dy) ) of a weighting function for
72
+ # a particle's pressure. This weight function is spiky (not flat or
73
+ # smooth at x=0) so particles close together repel strongly.
74
+ #
75
+
76
+ def gradient_weight_spiky r, h
77
+ len_r = r.magnitude
78
+
79
+ if len_r.xbetween? 0, h
80
+ r * (45.0 / (Math::PI * h**6 * len_r)) * (h - len_r)**2 * (-1.0)
81
+ else
82
+ V::ZERO
83
+ end
84
+ end
85
+
86
+ ##
87
+ # The laplacian of a weighting function that tends towards infinity when
88
+ # approching 0 (slows down particles moving faster than their neighbors)
89
+ #
90
+
91
+ def laplacian_weight_viscosity r, h
92
+ len_r = r.magnitude
93
+
94
+ if len_r.xbetween? 0, h
95
+ 45.0 / (2 * Math::PI * h**5) * (1 - len_r / h)
96
+ else
97
+ 0.0
98
+ end
99
+ end
100
+
101
+ def clear
102
+ # Clear everything
103
+ particles.each do |particle|
104
+ particle.density = DENSITY
105
+ particle.pressure_force = V::ZERO
106
+ particle.viscosity_force = V::ZERO
107
+ end
108
+ end
109
+
110
+ def calculate_density
111
+ # Calculate fluid density around each particle
112
+ particles.each do |particle|
113
+ particles.each do |neighbor|
114
+
115
+ # If particles are close together, density increases
116
+ distance = particle.position - neighbor.position
117
+
118
+ if distance.magnitude < H # Particles are close enough to matter
119
+ particle.density += MASS * weight(distance, H)
120
+ end
121
+ end
122
+ # p particle.density if particle.density > 2*H
123
+ end
124
+ end
125
+
126
+ def calculate_forces
127
+ # Calculate forces on each particle based on density
128
+ particles.each do |particle|
129
+ particles.each do |neighbor|
130
+ distance = particle.position - neighbor.position
131
+ if distance.magnitude <= H then
132
+ # Temporary terms used to caclulate forces
133
+ density_p = particle.density
134
+ density_n = neighbor.density
135
+
136
+ # This *should* never happen, but it's good to check,
137
+ # because we're dividing by density later
138
+ raise "Particle density is, impossibly, 0" unless density_n != 0
139
+
140
+ # Pressure derived from the ideal gas law (constant temp)
141
+ pressure_p = K * (density_p - DENSITY)
142
+ pressure_n = K * (density_n - DENSITY)
143
+
144
+ # Navier-Stokes equations for pressure and viscosity
145
+ # (ignoring surface tension)
146
+ particle.pressure_force += gradient_weight_spiky(distance, H) *
147
+ (-1.0 * MASS * (pressure_p + pressure_n) / (2 * density_n))
148
+
149
+ particle.viscosity_force +=
150
+ (neighbor.velocity - particle.velocity) *
151
+ (ETA * MASS * (1/density_n) * laplacian_weight_viscosity(distance, H))
152
+ end
153
+ end
154
+ end
155
+ end
156
+
157
+ def apply_forces delta_time
158
+ # Apply forces to particles- make them move!
159
+ particles.each do |particle|
160
+ total_force = particle.pressure_force + particle.viscosity_force
161
+
162
+ # 'Eulerian' style momentum:
163
+
164
+ # Calculate acceleration from forces
165
+ acceleration = (total_force * (1.0 / particle.density * delta_time)) + GRAVITY
166
+
167
+ # Update position and velocity
168
+ particle.velocity += acceleration * delta_time
169
+ particle.position += particle.velocity * delta_time
170
+ end
171
+ end
172
+
173
+ def step delta_time
174
+ clear
175
+ calculate_density
176
+ calculate_forces
177
+ apply_forces delta_time
178
+ end
179
+
180
+ ##
181
+ # The walls nudge particles back in-bounds, plus a little jitter
182
+ # so nothing gets stuck
183
+ #
184
+
185
+ def make_particles_stay_in_bounds scale
186
+ # TODO: Better boundary conditions (THESE ARE A LAME WORKAROUND)
187
+ particles.each do |particle|
188
+ if particle.position.x >= scale - 0.01
189
+ particle.position.x = scale - (0.01 + 0.1*rand)
190
+ particle.velocity.x = 0
191
+ elsif particle.position.x < 0.01
192
+ particle.position.x = 0.01 + 0.1*rand
193
+ particle.velocity.x = 0
194
+ end
195
+
196
+ if particle.position.y >= scale - 0.01
197
+ particle.position.y = scale - (0.01+rand*0.1)
198
+ particle.velocity.y = 0
199
+ elsif particle.position.y < 0.01
200
+ particle.position.y = 0.01 + rand*0.1
201
+ particle.velocity.y = 0
202
+ end
203
+ end
204
+ end
205
+ end
206
+
207
+ class SimulationWindow < Graphics::Simulation
208
+ WINSIZE = 500
209
+
210
+ attr_reader :simulation, :s
211
+
212
+ DELTA_TIME = 0.1
213
+
214
+ def initialize
215
+ super WINSIZE, WINSIZE, 16, "Smoothed Particle Hydrodynamics"
216
+ @simulation = SPH.new
217
+ @scale = 15
218
+ @s = WINSIZE.div @scale
219
+ end
220
+
221
+ def update time
222
+ simulation.step DELTA_TIME
223
+ simulation.make_particles_stay_in_bounds @scale
224
+ end
225
+
226
+ def draw time
227
+ clear
228
+
229
+ simulation.particles.each do |particle|
230
+ pos = particle.position * s
231
+ vel = particle.velocity * s
232
+
233
+ # Particles
234
+ circle(pos.x, pos.y, 5, :white)
235
+ circle(pos.x, pos.y, particle.density, :gray)
236
+
237
+ # Velocity vectors
238
+ p2 = pos + vel
239
+ line(pos.x, pos.y, p2.x, p2.y, :red)
240
+
241
+ fps time
242
+ end
243
+ end
244
+ end
245
+
246
+ SimulationWindow.new.run