graphics 1.0.0b5 → 1.0.0b6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/History.rdoc +38 -0
- data/Manifest.txt +5 -0
- data/Rakefile +2 -0
- data/examples/boid.rb +14 -15
- data/examples/bounce.rb +9 -11
- data/examples/canvas.rb +3 -1
- data/examples/collision.rb +10 -8
- data/examples/demo.rb +12 -12
- data/examples/fluid2.rb +13 -8
- data/examples/gol2.rb +0 -2
- data/examples/math.rb +3 -1
- data/examples/pi_polygon.rb +145 -0
- data/examples/radar.rb +3 -1
- data/examples/rainbow_fluid.rb +243 -0
- data/examples/tank.rb +19 -17
- data/examples/tank2.rb +25 -21
- data/examples/targeting.rb +3 -1
- data/examples/vants.rb +5 -21
- data/examples/walker.rb +15 -12
- data/examples/walker2.rb +28 -26
- data/examples/zombies.rb +0 -2
- data/ext/sdl/sdl.c +10 -3
- data/ext/sdl/sge/sge_primitives.cpp +11 -0
- data/ext/sdl/sge/sge_primitives.h +3 -0
- data/lib/graphics.rb +2 -1
- data/lib/graphics/body.rb +10 -25
- data/lib/graphics/decorators.rb +21 -0
- data/lib/graphics/rainbows.rb +128 -0
- data/lib/graphics/simulation.rb +139 -15
- data/test/test_graphics.rb +45 -9
- data/test/test_rainbows.rb +95 -0
- metadata +20 -28
- metadata.gz.sig +0 -0
data/examples/walker.rb
CHANGED
@@ -37,15 +37,6 @@ class Person < Graphics::Body
|
|
37
37
|
self.m += D_M unless m >= M_M
|
38
38
|
end
|
39
39
|
|
40
|
-
def draw
|
41
|
-
trail.draw
|
42
|
-
|
43
|
-
w.angle x, y, ga, 60, :red
|
44
|
-
|
45
|
-
# the blit looks HORRIBLE when rotated... dunno why
|
46
|
-
w.blit w.body_img, x, y
|
47
|
-
end
|
48
|
-
|
49
40
|
def turn_towards_goal
|
50
41
|
turn a.relative_angle(ga, D_A)
|
51
42
|
end
|
@@ -66,6 +57,17 @@ class Person < Graphics::Body
|
|
66
57
|
self.a = (a + 180).degrees
|
67
58
|
change_goal
|
68
59
|
end
|
60
|
+
|
61
|
+
class View
|
62
|
+
def self.draw w, b
|
63
|
+
b.trail.draw
|
64
|
+
|
65
|
+
w.angle b.x, b.y, b.ga, 60, :red
|
66
|
+
|
67
|
+
# the blit looks HORRIBLE when rotated... dunno why
|
68
|
+
w.blit w.body_img, b.x, b.y
|
69
|
+
end
|
70
|
+
end
|
69
71
|
end
|
70
72
|
|
71
73
|
class WalkerSimulation < Graphics::Simulation
|
@@ -75,6 +77,7 @@ class WalkerSimulation < Graphics::Simulation
|
|
75
77
|
super 850, 850, 16, "Walker"
|
76
78
|
|
77
79
|
self.ps = populate Person
|
80
|
+
register_bodies ps
|
78
81
|
|
79
82
|
self.body_img = sprite 20, 20 do
|
80
83
|
circle 10, 10, 5, :white, :filled
|
@@ -84,14 +87,14 @@ class WalkerSimulation < Graphics::Simulation
|
|
84
87
|
end
|
85
88
|
|
86
89
|
def update n
|
87
|
-
|
90
|
+
super
|
91
|
+
|
88
92
|
detect_collisions(ps).each(&:collide)
|
89
93
|
end
|
90
94
|
|
91
95
|
def draw n
|
92
|
-
|
96
|
+
super
|
93
97
|
|
94
|
-
ps.each(&:draw)
|
95
98
|
fps n
|
96
99
|
end
|
97
100
|
|
data/examples/walker2.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
#!/usr/local/bin/ruby -w
|
2
2
|
|
3
|
-
# srand 42
|
4
|
-
|
5
3
|
require "graphics"
|
6
4
|
require "graphics/trail"
|
7
5
|
|
@@ -90,26 +88,6 @@ class Person < Graphics::Body
|
|
90
88
|
self.m += D_M unless m >= max
|
91
89
|
end
|
92
90
|
|
93
|
-
def draw
|
94
|
-
if debug? and attack? then
|
95
|
-
w.angle x, y, a-75, VISIBILITY, :yellow
|
96
|
-
w.angle x, y, a-25, VISIBILITY, :yellow
|
97
|
-
w.angle x, y, a+25, VISIBILITY, :yellow
|
98
|
-
w.angle x, y, a+75, VISIBILITY, :yellow
|
99
|
-
nearby.each do |o|
|
100
|
-
w.line x, y, o.x, o.y, :yellow
|
101
|
-
end
|
102
|
-
# sleep 0.25 unless nearby.empty?
|
103
|
-
end
|
104
|
-
|
105
|
-
w.angle x, y, a, 20, :green
|
106
|
-
w.angle x, y, ga, 10, :red
|
107
|
-
|
108
|
-
# the blit looks HORRIBLE when rotated... dunno why
|
109
|
-
w.blit w.body_img, x, y
|
110
|
-
w.circle x, y, 5, :red, :filled if attack?
|
111
|
-
end
|
112
|
-
|
113
91
|
def turn_towards_goal
|
114
92
|
turn a.relative_angle(ga, D_A)
|
115
93
|
end
|
@@ -133,6 +111,30 @@ class Person < Graphics::Body
|
|
133
111
|
self.a = (a + 180).degrees
|
134
112
|
change_goal
|
135
113
|
end
|
114
|
+
|
115
|
+
class View
|
116
|
+
def self.draw w, b
|
117
|
+
x, y, a, ga = b.x, b.y, b.a, b.ga
|
118
|
+
|
119
|
+
if b.debug? and b.attack? then
|
120
|
+
w.angle x, y, a-75, VISIBILITY, :yellow
|
121
|
+
w.angle x, y, a-25, VISIBILITY, :yellow
|
122
|
+
w.angle x, y, a+25, VISIBILITY, :yellow
|
123
|
+
w.angle x, y, a+75, VISIBILITY, :yellow
|
124
|
+
b.nearby.each do |o|
|
125
|
+
w.line x, y, o.x, o.y, :yellow
|
126
|
+
end
|
127
|
+
# sleep 0.25 unless nearby.empty?
|
128
|
+
end
|
129
|
+
|
130
|
+
w.angle x, y, a, 20, :green
|
131
|
+
w.angle x, y, ga, 10, :red
|
132
|
+
|
133
|
+
# the blit looks HORRIBLE when rotated... dunno why
|
134
|
+
w.blit w.body_img, x, y
|
135
|
+
w.circle x, y, 5, :red, :filled if b.attack?
|
136
|
+
end
|
137
|
+
end
|
136
138
|
end
|
137
139
|
|
138
140
|
class WalkerSimulation < Graphics::Simulation
|
@@ -142,6 +144,7 @@ class WalkerSimulation < Graphics::Simulation
|
|
142
144
|
super 850, 850, 16, "Walker"
|
143
145
|
|
144
146
|
self.ps = populate Person, 2
|
147
|
+
register_bodies ps
|
145
148
|
|
146
149
|
# 5.times do |n|
|
147
150
|
# ps[n].attack = true
|
@@ -168,7 +171,8 @@ class WalkerSimulation < Graphics::Simulation
|
|
168
171
|
end
|
169
172
|
|
170
173
|
def update n
|
171
|
-
|
174
|
+
super
|
175
|
+
|
172
176
|
detect_collisions(ps).each do |a, b|
|
173
177
|
a.collide b
|
174
178
|
end
|
@@ -177,9 +181,7 @@ class WalkerSimulation < Graphics::Simulation
|
|
177
181
|
end
|
178
182
|
|
179
183
|
def draw n
|
180
|
-
|
181
|
-
|
182
|
-
ps.each(&:draw)
|
184
|
+
super
|
183
185
|
|
184
186
|
debug "#{ps.size}"
|
185
187
|
fps n
|
data/examples/zombies.rb
CHANGED
data/ext/sdl/sdl.c
CHANGED
@@ -727,6 +727,12 @@ static VALUE Surface_transform(VALUE self, VALUE bgcolor, VALUE angle,
|
|
727
727
|
return TypedData_Wrap_Struct(cSurface, &_Surface_type, result);
|
728
728
|
}
|
729
729
|
|
730
|
+
static VALUE Surface_save(VALUE self, VALUE path) {
|
731
|
+
DEFINE_SELF(Surface, surface, self);
|
732
|
+
|
733
|
+
return INT2NUM(SDL_SaveBMP(surface, RSTRING_PTR(path)));
|
734
|
+
}
|
735
|
+
|
730
736
|
//// SDL::TTFFont methods:
|
731
737
|
|
732
738
|
static void _TTFFont_free(void* font) {
|
@@ -909,9 +915,10 @@ void Init_sdl() {
|
|
909
915
|
rb_define_method(cSurface, "w", Surface_w, 0);
|
910
916
|
rb_define_method(cSurface, "[]", Surface_index, 2);
|
911
917
|
rb_define_method(cSurface, "[]=", Surface_index_equals, 3);
|
912
|
-
rb_define_method(cSurface, "transform",
|
913
|
-
rb_define_method(cSurface, "
|
914
|
-
rb_define_method(cSurface, "
|
918
|
+
rb_define_method(cSurface, "transform", Surface_transform, 5);
|
919
|
+
rb_define_method(cSurface, "save", Surface_save, 1);
|
920
|
+
rb_define_method(cSurface, "flags", Surface_flags, 0);
|
921
|
+
rb_define_method(cSurface, "set_alpha", Surface_set_alpha, 2);
|
915
922
|
|
916
923
|
//// SDL::TTFFont methods:
|
917
924
|
|
@@ -2514,3 +2514,14 @@ void sge_AABezier(SDL_Surface *surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16
|
|
2514
2514
|
sge_AABezierAlpha(surface,x1,y1,x2,y2,x3,y3,x4,y4,level, SDL_MapRGB(surface->format,R,G,B),255);
|
2515
2515
|
}
|
2516
2516
|
|
2517
|
+
//==================================================================================
|
2518
|
+
// Added by zenspider:
|
2519
|
+
//==================================================================================
|
2520
|
+
|
2521
|
+
void sge_FastFilledRect(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color) {
|
2522
|
+
for (Sint16 y = y1; y <= y2; y++) {
|
2523
|
+
_HLine(Surface, x1, x2, y, color);
|
2524
|
+
}
|
2525
|
+
|
2526
|
+
sge_UpdateRect(Surface, x1, y1, x2, y2);
|
2527
|
+
}
|
@@ -105,6 +105,9 @@ DECLSPEC void sge_Bezier(SDL_Surface *surface, Sint16 x1, Sint16 y1, Sint16 x2,
|
|
105
105
|
DECLSPEC void sge_BezierAlpha(SDL_Surface *surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,Sint16 x3, Sint16 y3, Sint16 x4, Sint16 y4, int level, Uint8 R, Uint8 G, Uint8 B, Uint8 alpha);
|
106
106
|
DECLSPEC void sge_AABezier(SDL_Surface *surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,Sint16 x3, Sint16 y3, Sint16 x4, Sint16 y4, int level, Uint8 R, Uint8 G, Uint8 B);
|
107
107
|
DECLSPEC void sge_AABezierAlpha(SDL_Surface *surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,Sint16 x3, Sint16 y3, Sint16 x4, Sint16 y4, int level, Uint8 R, Uint8 G, Uint8 B, Uint8 alpha);
|
108
|
+
|
109
|
+
// Added by zenspider
|
110
|
+
DECLSPEC void sge_FastFilledRect(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color);
|
108
111
|
#endif /* sge_C_ONLY */
|
109
112
|
|
110
113
|
|
data/lib/graphics.rb
CHANGED
data/lib/graphics/body.rb
CHANGED
@@ -177,18 +177,18 @@ class Graphics::Body
|
|
177
177
|
max_h, max_w = w.h, w.w
|
178
178
|
|
179
179
|
if x < 0 then
|
180
|
-
self.x =
|
180
|
+
self.x = x.abs
|
181
181
|
return :west
|
182
182
|
elsif x > max_w then
|
183
|
-
self.x = max_w
|
183
|
+
self.x = 2 * max_w - x
|
184
184
|
return :east
|
185
185
|
end
|
186
186
|
|
187
187
|
if y < 0 then
|
188
|
-
self.y =
|
188
|
+
self.y = y.abs
|
189
189
|
return :south
|
190
190
|
elsif y > max_h then
|
191
|
-
self.y = max_h
|
191
|
+
self.y = 2 * max_h - y
|
192
192
|
return :north
|
193
193
|
end
|
194
194
|
|
@@ -223,28 +223,13 @@ class Graphics::Body
|
|
223
223
|
|
224
224
|
##
|
225
225
|
# Like clip, keep the body in bounds of the window, but set the
|
226
|
-
# angle to the angle of reflection. Also slows momentum by
|
226
|
+
# angle to the angle of reflection. Also slows momentum by +friction+%.
|
227
227
|
|
228
|
-
def bounce
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
if x < 0 then
|
234
|
-
self.x, normal = 0, 0
|
235
|
-
elsif x > max_w then
|
236
|
-
self.x, normal = max_w, 180
|
237
|
-
end
|
238
|
-
|
239
|
-
if y < 0 then
|
240
|
-
self.y, normal = 0, 90
|
241
|
-
elsif y > max_h then
|
242
|
-
self.y, normal = max_h, 270
|
243
|
-
end
|
244
|
-
|
245
|
-
if normal then
|
246
|
-
self.a = (2 * normal - 180 - a).degrees
|
247
|
-
self.m *= 0.8
|
228
|
+
def bounce friction = 0.2
|
229
|
+
if wall = clip then
|
230
|
+
self.a = (2 * NORMAL[wall] - 180 - a).degrees
|
231
|
+
self.m *= (1.0 - friction) if friction and friction > 0
|
232
|
+
true
|
248
233
|
end
|
249
234
|
end
|
250
235
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ShowFPS
|
2
|
+
def draw n
|
3
|
+
super
|
4
|
+
fps n
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
module DrawGrid
|
9
|
+
def pre_draw n
|
10
|
+
super
|
11
|
+
|
12
|
+
(0...w).step(self.class::GRID_WIDTH).each do |x|
|
13
|
+
hline x, :gray
|
14
|
+
vline x, :gray
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module WhiteBackground
|
20
|
+
CLEAR_COLOR = :white
|
21
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
class Graphics::Rainbow
|
2
|
+
attr_reader :cache
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@cache = self.cache_colors
|
6
|
+
end
|
7
|
+
|
8
|
+
def clamp d, min, max
|
9
|
+
[[min, d].max, max].min
|
10
|
+
end
|
11
|
+
|
12
|
+
##
|
13
|
+
# Takes a value and a range,
|
14
|
+
# and scales that range to 0-360
|
15
|
+
def scale d, min, max
|
16
|
+
range = max - min
|
17
|
+
if range != 0
|
18
|
+
scaled = (d.to_f / range) * 360
|
19
|
+
return clamp(scaled, 0, 360).round
|
20
|
+
else
|
21
|
+
0
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def cache_colors
|
26
|
+
# Saves all the colors to a hash
|
27
|
+
cache = {}
|
28
|
+
(0..360).each do |degree|
|
29
|
+
cache[degree] = _color degree
|
30
|
+
end
|
31
|
+
cache
|
32
|
+
end
|
33
|
+
|
34
|
+
def color d, min=0, max=360
|
35
|
+
scaled = scale d, min, max
|
36
|
+
@cache[scaled]
|
37
|
+
end
|
38
|
+
|
39
|
+
def _color degree
|
40
|
+
raise "Subclass responsibility"
|
41
|
+
end
|
42
|
+
private :_color
|
43
|
+
end
|
44
|
+
|
45
|
+
##
|
46
|
+
# Black to white gradient
|
47
|
+
#
|
48
|
+
class Graphics::Greyscale < Graphics::Rainbow
|
49
|
+
def initialize
|
50
|
+
super
|
51
|
+
end
|
52
|
+
|
53
|
+
def _color degree
|
54
|
+
brightness_unit = degree/360.0
|
55
|
+
brightness = (brightness_unit*255.0).floor # Scale back to RGB
|
56
|
+
|
57
|
+
[brightness, brightness, brightness]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
##
|
62
|
+
# The full RGB spectrum
|
63
|
+
#
|
64
|
+
class Graphics::Hue < Graphics::Rainbow
|
65
|
+
|
66
|
+
def initialize
|
67
|
+
super
|
68
|
+
end
|
69
|
+
|
70
|
+
def _color degree
|
71
|
+
main_color = 1 * 255 # Let chroma (saturation * brightness) always == 1
|
72
|
+
second_strongest_color = ((1 - (degree/60.0 % 2 - 1).abs) * 255).floor
|
73
|
+
|
74
|
+
case degree
|
75
|
+
when 0..60
|
76
|
+
[main_color, second_strongest_color, 0]
|
77
|
+
when 61..120
|
78
|
+
[second_strongest_color, main_color, 0]
|
79
|
+
when 121..180
|
80
|
+
[0, main_color, second_strongest_color]
|
81
|
+
when 181..240
|
82
|
+
[0, second_strongest_color, main_color]
|
83
|
+
when 241..300
|
84
|
+
[second_strongest_color, 0, main_color]
|
85
|
+
when 301..360
|
86
|
+
[main_color, 0, second_strongest_color]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
##
|
93
|
+
# Spectrum with linearly increasing brightness
|
94
|
+
#
|
95
|
+
class Graphics::Cubehelix < Graphics::Rainbow
|
96
|
+
|
97
|
+
def initialize
|
98
|
+
super
|
99
|
+
end
|
100
|
+
|
101
|
+
def _color degree
|
102
|
+
d = degree/360.0
|
103
|
+
start = 0.5 # Starting position in color space - 0=blue, 1=red, 2=green
|
104
|
+
rotations = -1.5 # How many rotations through the rainbow?
|
105
|
+
saturation = 1.2
|
106
|
+
gamma = 1.0
|
107
|
+
fract = d**gamma # Position on the spectrum
|
108
|
+
|
109
|
+
# Amplitude of the helix
|
110
|
+
amp = saturation * fract * (1 - fract) / 2.0
|
111
|
+
angle = 2*Math::PI*(start/3.0 + 1.0 + rotations*fract)
|
112
|
+
# From the CubeHelix Equations
|
113
|
+
r = fract + amp * (-0.14861 * Math.cos(angle) + 1.78277 * Math.sin(angle))
|
114
|
+
g = fract + amp * (-0.29227 * Math.cos(angle) - 0.90649 * Math.sin(angle))
|
115
|
+
b = fract + amp * (1.97294 * Math.cos(angle))
|
116
|
+
|
117
|
+
[(r * 255).round, (g * 255).round, (b * 255).round]
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
class Graphics::Simulation
|
122
|
+
def initialize_rainbow rainbow, name
|
123
|
+
rainbow.cache.each do |degree, color|
|
124
|
+
color_name = "#{name}_#{degree}".to_sym
|
125
|
+
self.register_color(color_name, *color, 255)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
data/lib/graphics/simulation.rb
CHANGED
@@ -5,10 +5,12 @@ require "sdl/sdl"
|
|
5
5
|
module SDL; end # :nodoc: -- stupid rdoc :(
|
6
6
|
|
7
7
|
##
|
8
|
-
#
|
9
|
-
# convenience methods to make life easier.
|
8
|
+
# An abstract simulation. See Graphics::Simulation and Graphics::Drawing.
|
10
9
|
|
11
|
-
class Graphics::
|
10
|
+
class Graphics::AbstractSimulation
|
11
|
+
|
12
|
+
# The default color to clear the screen.
|
13
|
+
CLEAR_COLOR = :black
|
12
14
|
|
13
15
|
# degrees to radians
|
14
16
|
D2R = Math::PI / 180.0
|
@@ -19,6 +21,9 @@ class Graphics::Simulation
|
|
19
21
|
# Call +log+ every N ticks, if +log+ is defined.
|
20
22
|
LOG_INTERVAL = 60
|
21
23
|
|
24
|
+
# Collection of collections of Bodies to auto-update and draw.
|
25
|
+
attr_accessor :_bodies
|
26
|
+
|
22
27
|
# The window the simulation is drawing in.
|
23
28
|
attr_accessor :screen
|
24
29
|
|
@@ -49,6 +54,9 @@ class Graphics::Simulation
|
|
49
54
|
# Procs registered to handle keydown events.
|
50
55
|
attr_accessor :keydown_handler
|
51
56
|
|
57
|
+
# Is the application done?
|
58
|
+
attr_accessor :done
|
59
|
+
|
52
60
|
##
|
53
61
|
# Create a new simulation of a certain width and height. Optionally,
|
54
62
|
# you can set the bits per pixel (0 for current screen settings),
|
@@ -61,11 +69,13 @@ class Graphics::Simulation
|
|
61
69
|
|
62
70
|
full = full ? SDL::FULLSCREEN : 0
|
63
71
|
|
72
|
+
self._bodies = []
|
73
|
+
|
64
74
|
self.font = find_font("Menlo", 32)
|
65
75
|
|
66
76
|
SDL::WM.set_caption name, name
|
67
77
|
|
68
|
-
self.screen = SDL::Screen.open w, h, bpp,
|
78
|
+
self.screen = SDL::Screen.open w, h, bpp, self.class::SCREEN_FLAGS|full
|
69
79
|
self.w, self.h = screen.w, screen.h
|
70
80
|
|
71
81
|
self.color = {}
|
@@ -85,8 +95,8 @@ class Graphics::Simulation
|
|
85
95
|
# Register default key events. Handles ESC & Q (quit) and P (pause).
|
86
96
|
|
87
97
|
def initialize_keys
|
88
|
-
add_keydown_handler("\e") {
|
89
|
-
add_keydown_handler("q") {
|
98
|
+
add_keydown_handler("\e") { self.done = true }
|
99
|
+
add_keydown_handler("q") { self.done = true }
|
90
100
|
add_keydown_handler("p") { self.paused = !paused }
|
91
101
|
add_keydown_handler("/") { self.iter_per_tick += 1 }
|
92
102
|
add_keydown_handler("-") { self.iter_per_tick -= 1; self.iter_per_tick = 1 if iter_per_tick < 1 }
|
@@ -95,10 +105,12 @@ class Graphics::Simulation
|
|
95
105
|
def initialize_colors # :nodoc:
|
96
106
|
register_color :black, 0, 0, 0
|
97
107
|
register_color :white, 255, 255, 255
|
108
|
+
register_color :gray, 127, 127, 127
|
98
109
|
register_color :red, 255, 0, 0
|
99
110
|
register_color :green, 0, 255, 0
|
100
111
|
register_color :blue, 0, 0, 255
|
101
|
-
register_color :
|
112
|
+
register_color :cyan, 0, 255, 255
|
113
|
+
register_color :magenta, 255, 0, 255
|
102
114
|
register_color :yellow, 255, 255, 0
|
103
115
|
register_color :alpha, 0, 0, 0, 0
|
104
116
|
|
@@ -108,6 +120,20 @@ class Graphics::Simulation
|
|
108
120
|
register_color(("red%02d" % n).to_sym, m, 0, 0)
|
109
121
|
register_color(("green%02d" % n).to_sym, 0, m, 0)
|
110
122
|
register_color(("blue%02d" % n).to_sym, 0, 0, m)
|
123
|
+
register_color(("cyan%02d" % n).to_sym, 0, m, m)
|
124
|
+
register_color(("magenta%02d" % n).to_sym, m, 0, m)
|
125
|
+
register_color(("yellow%02d" % n).to_sym, m, m, 0)
|
126
|
+
end
|
127
|
+
|
128
|
+
(0...256).each do |n|
|
129
|
+
m = (256 * n / 255.0).to_i
|
130
|
+
register_color(("gray%03d" % n).to_sym, m, m, m)
|
131
|
+
register_color(("red%03d" % n).to_sym, m, 0, 0)
|
132
|
+
register_color(("green%03d" % n).to_sym, 0, m, 0)
|
133
|
+
register_color(("blue%03d" % n).to_sym, 0, 0, m)
|
134
|
+
register_color(("cyan%03d" % n).to_sym, 0, m, m)
|
135
|
+
register_color(("magenta%03d" % n).to_sym, m, 0, m)
|
136
|
+
register_color(("yellow%03d" % n).to_sym, m, m, 0)
|
111
137
|
end
|
112
138
|
end
|
113
139
|
|
@@ -127,6 +153,22 @@ class Graphics::Simulation
|
|
127
153
|
SDL::TTF.open(font, size)
|
128
154
|
end
|
129
155
|
|
156
|
+
##
|
157
|
+
# Register a collection of bodies to be auto-updated and drawn.
|
158
|
+
|
159
|
+
def register_bodies ary
|
160
|
+
_bodies << ary
|
161
|
+
ary
|
162
|
+
end
|
163
|
+
|
164
|
+
##
|
165
|
+
# Register a single Body to be auto-updated and drawn.
|
166
|
+
|
167
|
+
def register_body obj
|
168
|
+
_bodies << [obj]
|
169
|
+
obj
|
170
|
+
end
|
171
|
+
|
130
172
|
##
|
131
173
|
# Name a color w/ rgba values.
|
132
174
|
|
@@ -203,6 +245,7 @@ class Graphics::Simulation
|
|
203
245
|
self.start_time = Time.now
|
204
246
|
n = 0
|
205
247
|
event = nil
|
248
|
+
self.done = false
|
206
249
|
|
207
250
|
logger = respond_to? :log
|
208
251
|
log_interval = self.class::LOG_INTERVAL
|
@@ -217,6 +260,8 @@ class Graphics::Simulation
|
|
217
260
|
draw_and_flip n
|
218
261
|
|
219
262
|
log if logger and n % log_interval == 0
|
263
|
+
|
264
|
+
break if done
|
220
265
|
end
|
221
266
|
end
|
222
267
|
|
@@ -226,25 +271,54 @@ class Graphics::Simulation
|
|
226
271
|
end
|
227
272
|
|
228
273
|
##
|
229
|
-
# Draw the scene
|
230
|
-
#
|
274
|
+
# Draw the scene by clearing the window and drawing all registered
|
275
|
+
# bodies. You are free to completely override this or call super and
|
276
|
+
# add any extras at the end.
|
231
277
|
|
232
278
|
def draw n
|
233
|
-
|
279
|
+
pre_draw n
|
280
|
+
post_draw n
|
281
|
+
end
|
282
|
+
|
283
|
+
def pre_draw n
|
284
|
+
clear
|
285
|
+
end
|
286
|
+
|
287
|
+
def post_draw n
|
288
|
+
_bodies.each do |ary|
|
289
|
+
draw_collection ary
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
##
|
294
|
+
# Draw a homogeneous collection of bodies. This assumes that the MVC
|
295
|
+
# pattern described on this class is being used.
|
296
|
+
|
297
|
+
def draw_collection ary
|
298
|
+
return if ary.empty?
|
299
|
+
|
300
|
+
cls = ary.first.class.const_get :View
|
301
|
+
|
302
|
+
ary.each do |obj|
|
303
|
+
cls.draw self, obj
|
304
|
+
end
|
234
305
|
end
|
235
306
|
|
236
307
|
##
|
237
|
-
# Update the simulation
|
238
|
-
#
|
308
|
+
# Update the simulation by telling all registered bodies to update.
|
309
|
+
# You are free to completely override this or call super and add any
|
310
|
+
# extras at the end.
|
239
311
|
|
240
312
|
def update n
|
241
|
-
|
313
|
+
_bodies.each do |ary|
|
314
|
+
ary.each(&:update)
|
315
|
+
end
|
242
316
|
end
|
243
317
|
|
244
318
|
##
|
245
|
-
# Clear the whole screen
|
319
|
+
# Clear the whole screen. Defaults to CLEAR_COLOR.
|
246
320
|
|
247
|
-
def clear c =
|
321
|
+
def clear c = self.class::CLEAR_COLOR
|
248
322
|
fast_rect 0, 0, w, h, c
|
249
323
|
end
|
250
324
|
|
@@ -454,6 +528,13 @@ class Graphics::Simulation
|
|
454
528
|
SDL::Surface.blit img, 0, 0, 0, 0, screen, x-1, h-y-img.h
|
455
529
|
end
|
456
530
|
|
531
|
+
##
|
532
|
+
# Save the current screen to a bmp
|
533
|
+
|
534
|
+
def save path
|
535
|
+
screen.save path
|
536
|
+
end
|
537
|
+
|
457
538
|
##
|
458
539
|
# Create a new sprite with a given width and height and yield to a
|
459
540
|
# block with the new sprite as the current screen. All drawing
|
@@ -477,6 +558,49 @@ class Graphics::Simulation
|
|
477
558
|
end
|
478
559
|
end
|
479
560
|
|
561
|
+
##
|
562
|
+
# A simulation. This ties everything together and provides a bunch of
|
563
|
+
# convenience methods to make life easier.
|
564
|
+
#
|
565
|
+
# In the Model View Controller (MVC) pattern, the simulation is the
|
566
|
+
# Controller and controls both the window and all bodies involved in
|
567
|
+
# the simulation. The bodies are the Model and each body class is
|
568
|
+
# expected to have an inner View class w/ a #draw class method for the
|
569
|
+
# View.
|
570
|
+
#
|
571
|
+
# For example, in examples/bounce.rb:
|
572
|
+
#
|
573
|
+
# + BounceSimulation subclasses Graphics::Simulation
|
574
|
+
# + BounceSimulation has many Balls
|
575
|
+
# + Ball#update maintains all ball movement.
|
576
|
+
# + BounceSimulation#draw automatically calls Ball::View.draw on all balls.
|
577
|
+
# + Ball::View.draw takes a window and a ball and draws it.
|
578
|
+
|
579
|
+
class Graphics::Simulation < Graphics::AbstractSimulation
|
580
|
+
SCREEN_FLAGS = SDL::HWSURFACE|SDL::DOUBLEBUF
|
581
|
+
end
|
582
|
+
|
583
|
+
##
|
584
|
+
# A drawing. Like a Simulation, but on a canvas that doesn't have
|
585
|
+
# double buffering or clearing on each tick.
|
586
|
+
#
|
587
|
+
# See AbstractSimulation for most methods.
|
588
|
+
|
589
|
+
class Graphics::Drawing < Graphics::AbstractSimulation
|
590
|
+
SCREEN_FLAGS = SDL::HWSURFACE
|
591
|
+
|
592
|
+
def initialize(*a)
|
593
|
+
super
|
594
|
+
|
595
|
+
clear
|
596
|
+
end
|
597
|
+
|
598
|
+
def draw_and_flip n
|
599
|
+
screen.update 0, 0, 0, 0
|
600
|
+
# no flip
|
601
|
+
end
|
602
|
+
end
|
603
|
+
|
480
604
|
if $0 == __FILE__ then
|
481
605
|
SDL.init SDL::INIT_EVERYTHING
|
482
606
|
SDL.set_video_mode(640, 480, 16, SDL::SWSURFACE)
|