retrograph_easy 0.1

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/COPYING ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2009 MenTaLguY <mental@rydia.net>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,13 @@
1
+ == What is Retrograph? ==
2
+
3
+ Retrograph is a Ruby library which emulates the video
4
+ display unit from a hypothetical late-80s 8-bit game
5
+ console. It is similar in capability to the Sega Master
6
+ System's VDP, with some additional features and direct
7
+ support for text modes.
8
+
9
+ == What is Retrograph/EASY? ==
10
+
11
+ Retrograph/EASY is a simple API for creating games based
12
+ on Retrograph. Currently, it is based atop Ruby/SDL, but
13
+ support for other backends may be possible in the future.
data/Rakefile ADDED
@@ -0,0 +1,64 @@
1
+ require 'rake'
2
+ require 'rake/gempackagetask'
3
+ begin
4
+ require 'spec/rake/spectask'
5
+ have_rspec = true
6
+ rescue LoadError
7
+ $stderr.puts "*** The rspec gem is required to run specs. ***"
8
+ have_rspec = false
9
+ end
10
+ require 'rake/clean'
11
+
12
+ GEM_VERSION = '0.1'
13
+
14
+ task :clobber => [:clean]
15
+
16
+ gemspec = Gem::Specification.new do |gemspec|
17
+ gemspec.name = "retrograph_easy"
18
+ gemspec.version = GEM_VERSION
19
+ gemspec.author = "MenTaLguY <mental@rydia.net>"
20
+ gemspec.summary = "Retrograph/EASY, a simple API for Retrograph games."
21
+ gemspec.description = <<EOS
22
+ Retrograph/EASY is a simple API built atop Retrograph, a software renderer
23
+ which simulates a late-era 8-bit display with capabilities similar to those
24
+ of the Sega Master System.
25
+ EOS
26
+ gemspec.homepage = "http://rubyforge.org/projects/retrograph"
27
+ gemspec.email = "mental@rydia.net"
28
+ gemspec.rubyforge_project = 'retrograph'
29
+ gemspec.files = FileList['Rakefile', 'README', 'COPYING', 'lib/**/*.rb',
30
+ 'spec/**/*_spec.rb', 'spec/**/*.case',
31
+ 'spec/**/*.png', 'demos/**/*.rb']
32
+ gemspec.require_paths = ['lib']
33
+ gemspec.platform = Gem::Platform::RUBY
34
+ gemspec.add_dependency("retrograph", ">= 0.5")
35
+ end
36
+
37
+ Rake::GemPackageTask.new(gemspec) do |pkg|
38
+ pkg.need_tar = true
39
+ end
40
+
41
+ def make_demo_task(taskname, filename)
42
+ namespace :demo do
43
+ desc "Run the #{taskname} demo"
44
+ task taskname.intern do
45
+ system 'ruby', '-Ilib', filename
46
+ end
47
+ end
48
+ end
49
+
50
+ for filename in Dir.glob('demos/*.rb')
51
+ basename = File.basename(filename)
52
+ extension = File.extname(basename)
53
+ taskname = basename[0...(-extension.size)]
54
+ make_demo_task(taskname, filename)
55
+ end
56
+
57
+ if have_rspec
58
+ Spec::Rake::SpecTask.new do |task|
59
+ task.ruby_opts << '-rrubygems'
60
+ task.libs << 'lib'
61
+ task.spec_files = FileList["spec/**/*_spec.rb"]
62
+ end
63
+ task :default => [:clean, :spec]
64
+ end
data/demos/defense.rb ADDED
@@ -0,0 +1,413 @@
1
+ # Earth Defense
2
+ #
3
+ # Copyright (c) 2009 MenTaLguY <mental@rydia.net>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+ #
23
+ require 'rubygems'
24
+ require 'retrograph/easy'
25
+
26
+ SHIP_PATTERN = [
27
+ 0x00022000,
28
+ 0x00222200,
29
+ 0x02200220,
30
+ 0x22200222,
31
+ 0x22222222,
32
+ 0x22033022,
33
+ 0x20033002,
34
+ 0x00033000
35
+ ].pack("V8")
36
+
37
+ SHOT_PATTERN = [
38
+ 0x00000000,
39
+ 0x00044000,
40
+ 0x00044000,
41
+ 0x00044000,
42
+ 0x00044000,
43
+ 0x00044000,
44
+ 0x00044000,
45
+ 0x00000000
46
+ ].pack("V8")
47
+
48
+ ENEMY_PATTERN = [
49
+ 0x00000000,
50
+ 0x00000000,
51
+ 0x11000011,
52
+ 0x01100110,
53
+ 0x00111100,
54
+ 0x11100111,
55
+ 0x01111110,
56
+ 0x00100100
57
+ ].pack("V8")
58
+
59
+ ENEMY_PATTERN2 = [
60
+ 0x00000000,
61
+ 0x01000010,
62
+ 0x01100110,
63
+ 0x01100110,
64
+ 0x00111100,
65
+ 0x11100111,
66
+ 0x01111110,
67
+ 0x01000010
68
+ ].pack("V8")
69
+
70
+ EXPLOSION_PATTERN = [
71
+ 0x00030000,
72
+ 0x30030030,
73
+ 0x03300300,
74
+ 0x00333033,
75
+ 0x30333330,
76
+ 0x03303300,
77
+ 0x03000330,
78
+ 0x30000030
79
+ ].pack("V8")
80
+
81
+ AMMO_FULL_PATTERN = [
82
+ 0x00000000,
83
+ 0x04444440,
84
+ 0x04444440,
85
+ 0x04444440,
86
+ 0x04444440,
87
+ 0x04444440,
88
+ 0x04444440,
89
+ 0x00000000
90
+ ].pack("V8")
91
+
92
+ AMMO_EMPTY_PATTERN = [
93
+ 0x00000000,
94
+ 0x04444440,
95
+ 0x04000040,
96
+ 0x04000040,
97
+ 0x04000040,
98
+ 0x04000040,
99
+ 0x04444440,
100
+ 0x00000000
101
+ ].pack("V8")
102
+
103
+ DIGIT_PATTERNS = [
104
+ 0x00555550,
105
+ 0x05500055,
106
+ 0x05550055,
107
+ 0x05505055,
108
+ 0x05500555,
109
+ 0x05500055,
110
+ 0x00555550,
111
+ 0x00000000,
112
+
113
+ 0x00055000,
114
+ 0x00055500,
115
+ 0x00055000,
116
+ 0x00055000,
117
+ 0x00055000,
118
+ 0x00055000,
119
+ 0x00555500,
120
+ 0x00000000,
121
+
122
+ 0x00555550,
123
+ 0x05500055,
124
+ 0x05500000,
125
+ 0x00550000,
126
+ 0x00005500,
127
+ 0x00000550,
128
+ 0x05555555,
129
+ 0x00000000,
130
+
131
+ 0x00555550,
132
+ 0x05500055,
133
+ 0x05500000,
134
+ 0x00555000,
135
+ 0x05500000,
136
+ 0x05500055,
137
+ 0x00555550,
138
+ 0x00000000,
139
+
140
+ 0x00550000,
141
+ 0x00555000,
142
+ 0x00550500,
143
+ 0x00550550,
144
+ 0x05555555,
145
+ 0x00550000,
146
+ 0x05555000,
147
+ 0x00000000,
148
+
149
+ 0x05555555,
150
+ 0x00000055,
151
+ 0x00555555,
152
+ 0x05500055,
153
+ 0x05500000,
154
+ 0x05500055,
155
+ 0x00555550,
156
+ 0x00000000,
157
+
158
+ 0x00555550,
159
+ 0x05500055,
160
+ 0x00000055,
161
+ 0x00555555,
162
+ 0x05500055,
163
+ 0x05500055,
164
+ 0x00555550,
165
+ 0x00000000,
166
+
167
+ 0x05555555,
168
+ 0x00550055,
169
+ 0x00055000,
170
+ 0x00055000,
171
+ 0x00005500,
172
+ 0x00005500,
173
+ 0x00055550,
174
+ 0x00000000,
175
+
176
+ 0x00555550,
177
+ 0x05500055,
178
+ 0x05500055,
179
+ 0x00555550,
180
+ 0x05500055,
181
+ 0x05500055,
182
+ 0x00555550,
183
+ 0x00000000,
184
+
185
+ 0x00555550,
186
+ 0x05500055,
187
+ 0x05500055,
188
+ 0x05555550,
189
+ 0x05500000,
190
+ 0x05500055,
191
+ 0x00555550,
192
+ 0x00000000
193
+ ].pack("V*")
194
+
195
+ MAX_SHOTS = 3
196
+ MAX_LIVES = 5
197
+ SCORE_DIGITS = 7
198
+
199
+ SHIP_PATTERN_INDEX = 1
200
+ SHOT_PATTERN_INDEX = 2
201
+ ENEMY_PATTERN_INDEX = 3
202
+ EXPLOSION_PATTERN_INDEX = 5
203
+ AMMO_PATTERN_INDEX = 6
204
+ DIGIT_PATTERN_INDEX = 8
205
+
206
+ BG_COLOR = 0
207
+ ENEMY_COLOR = 17
208
+ SHIP_COLOR = 18
209
+ FIRE_COLOR = 19
210
+ SHOT_COLOR = 20
211
+ SCORE_COLOR = 21
212
+
213
+ class Entity < Struct.new :x, :y, :health
214
+ def alive?
215
+ health > 0
216
+ end
217
+
218
+ def dead?
219
+ not alive?
220
+ end
221
+
222
+ def kill
223
+ self.health = 0
224
+ self
225
+ end
226
+ end
227
+
228
+ def main_game
229
+ lives = MAX_LIVES
230
+ score = 0
231
+ ship = Entity.new 128, 200, 1
232
+ shots = []
233
+ enemies = []
234
+ escaped_enemies = []
235
+ explosions = []
236
+
237
+ controller = controllers[0]
238
+
239
+ start :spawning_enemies, 50
240
+ start :enemy_animation, 10, 2
241
+ start :flickering, 3, 2
242
+
243
+ lives_name_offset = 0x0800 + (26 * 32 + 2) * 2
244
+ ammo_name_offset = 0x0800 + (26 * 32 + (32 - 2 - MAX_SHOTS)) * 2
245
+ score_name_offset = 0x0800 + (2 * 32 + (32 - 2 - SCORE_DIGITS)) * 2
246
+
247
+ for life in 0...MAX_LIVES
248
+ write_vdu_byte(lives_name_offset+life*2+1, 0b01001001)
249
+ end
250
+ for shot in 0...MAX_SHOTS
251
+ write_vdu_byte(ammo_name_offset+shot*2+1, 0b01001001)
252
+ end
253
+ for digit in 0...SCORE_DIGITS
254
+ write_vdu_byte(score_name_offset+digit*2+1, 0b01001001)
255
+ end
256
+
257
+ each_frame do
258
+ break unless lives >= 0
259
+
260
+ if controller.b_pressed?
261
+ start :firing, 6 unless already? :firing
262
+ else
263
+ stop :firing
264
+ end
265
+
266
+ hvelocity = controller.horizontal * 3
267
+ ship.x += hvelocity
268
+ if hvelocity > 0
269
+ ship.x = 256-4 if ship.x >= (256-4)
270
+ elsif hvelocity < 0
271
+ ship.x = 4 if ship.x <= 4
272
+ end
273
+
274
+ explosions.each do |explosion|
275
+ explosion.health -= 1
276
+ end
277
+ shots.each do |shot|
278
+ shot.y -= 6
279
+ end
280
+ enemies.each do |enemy|
281
+ enemy.y += 1
282
+ end
283
+ escaped_enemies.each do |enemy|
284
+ enemy.y += 1
285
+ end
286
+
287
+ enemies.each do |enemy|
288
+ next unless enemy.alive?
289
+ shots.each do |shot|
290
+ next unless shot.alive?
291
+ if (shot.x - enemy.x).abs < 4 and (shot.y - enemy.y).abs < 4
292
+ shot.kill
293
+ enemy.kill
294
+ explosions.push Entity.new(enemy.x, enemy.y, 5)
295
+ score += 15
296
+ break
297
+ end
298
+ end
299
+ if enemy.alive?
300
+ if (ship.x - enemy.x).abs < 8 and (ship.y - enemy.y).abs < 6
301
+ lives -= 1
302
+ enemy.kill
303
+ explosions.push Entity.new(enemy.x, enemy.y, 5)
304
+ score -= 100
305
+ score = 0 if score < 0
306
+ elsif enemy.y > (ship.y + 4)
307
+ lives -= 1
308
+ enemy.kill
309
+ escaped_enemies.push Entity.new(enemy.x, enemy.y, 1)
310
+ score -= 50
311
+ score = 0 if score < 0
312
+ end
313
+ end
314
+ end
315
+
316
+ explosions.reject! { |e| e.dead? }
317
+ shots.reject! { |s| s.y < 0 or s.dead? }
318
+ enemies.reject! { |e| e.dead? }
319
+ escaped_enemies.reject! { |e| e.y >= 224 }
320
+
321
+ if frame_for? :firing and shots.size < MAX_SHOTS
322
+ shots.push Entity.new(ship.x, ship.y, 1)
323
+ end
324
+
325
+ if frame_for? :spawning_enemies
326
+ enemies.push Entity.new(rand(224)+16, 0, 1)
327
+ end
328
+
329
+ for life in 0...lives
330
+ write_vdu_byte(lives_name_offset+life*2, SHIP_PATTERN_INDEX)
331
+ end
332
+ for life in lives...MAX_LIVES
333
+ write_vdu_byte(lives_name_offset+life*2, 0)
334
+ end
335
+
336
+ for shot in 0...(shots.size)
337
+ write_vdu_byte(ammo_name_offset+shot*2, AMMO_PATTERN_INDEX+1)
338
+ end
339
+ for shot in (shots.size)...MAX_SHOTS
340
+ write_vdu_byte(ammo_name_offset+shot*2, AMMO_PATTERN_INDEX)
341
+ end
342
+
343
+ score_accum = score
344
+ for digit in 0...SCORE_DIGITS
345
+ offset = (SCORE_DIGITS-digit-1)*2
346
+ digit_value = score_accum % 10
347
+ write_vdu_byte(score_name_offset+offset, DIGIT_PATTERN_INDEX + digit_value)
348
+ score_accum /= 10
349
+ end
350
+
351
+ clear_sprites
352
+ explosions.each do |explosion|
353
+ sprite explosion.x - 4, explosion.y - 4, EXPLOSION_PATTERN_INDEX, 0
354
+ end
355
+ sprite ship.x - 4, ship.y - 4, SHIP_PATTERN_INDEX, 0
356
+ shots.each do |shot|
357
+ sprite shot.x - 4, shot.y - 4, SHOT_PATTERN_INDEX, 0
358
+ end
359
+ enemy_phase = phase_of :enemy_animation
360
+ enemies.each do |enemy|
361
+ sprite enemy.x - 4, enemy.y - 4, ENEMY_PATTERN_INDEX + enemy_phase, 0
362
+ end
363
+ escaped_enemies.each do |enemy|
364
+ sprite enemy.x - 4, enemy.y - 4, ENEMY_PATTERN_INDEX + enemy_phase, 0
365
+ end
366
+
367
+ if frame_for? :flickering
368
+ case phase_of :flickering
369
+ when 0
370
+ palette_entry_rgb FIRE_COLOR, 0xff, 0xaa, 0x00
371
+ palette_entry_rgb SHOT_COLOR, 0x55, 0xaa, 0xff
372
+ when 1
373
+ palette_entry_rgb FIRE_COLOR, 0xff, 0xff, 0x00
374
+ palette_entry_rgb SHOT_COLOR, 0x00, 0x55, 0xff
375
+ end
376
+ end
377
+
378
+ wait_scanlines 208
379
+
380
+ palette_entry_rgb FIRE_COLOR, 0xff, 0xaa, 0x00
381
+ palette_entry_rgb SHOT_COLOR, 0x00, 0x55, 0xff
382
+ end
383
+ end
384
+
385
+ Retrograph.app do
386
+ title "Earth Defense"
387
+
388
+ show_retrograph_logo
389
+ each_of_n_frames(25) do
390
+ break if controllers.first.start_pressed?
391
+ end
392
+
393
+ reset_vdu
394
+ vdu_mode 0x0f # mode 3 + sprites + bg
395
+
396
+ sprite_pattern(0x0000, SHIP_PATTERN_INDEX, SHIP_PATTERN)
397
+ sprite_pattern(0x0000, SHOT_PATTERN_INDEX, SHOT_PATTERN)
398
+ sprite_pattern(0x0000, ENEMY_PATTERN_INDEX, ENEMY_PATTERN)
399
+ sprite_pattern(0x0000, ENEMY_PATTERN_INDEX+1, ENEMY_PATTERN2)
400
+ sprite_pattern(0x0000, EXPLOSION_PATTERN_INDEX, EXPLOSION_PATTERN)
401
+ sprite_pattern(0x0000, AMMO_PATTERN_INDEX, AMMO_FULL_PATTERN)
402
+ sprite_pattern(0x0000, AMMO_PATTERN_INDEX+1, AMMO_EMPTY_PATTERN)
403
+ sprite_pattern(0x0000, DIGIT_PATTERN_INDEX, DIGIT_PATTERNS)
404
+
405
+ palette_entry_rgb BG_COLOR, 0x55, 0x55, 0x55
406
+ palette_entry_rgb ENEMY_COLOR, 0xaa, 0x00, 0x00
407
+ palette_entry_rgb SHIP_COLOR, 0xaa, 0xaa, 0xaa
408
+ palette_entry_rgb SCORE_COLOR, 0xff, 0xff, 0xff
409
+
410
+ loop do
411
+ main_game
412
+ end
413
+ end
data/demos/logo.rb ADDED
@@ -0,0 +1,34 @@
1
+ # Retrograph logo demo
2
+ #
3
+ # Copyright (c) 2009 MenTaLguY <mental@rydia.net>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+ #
23
+ require 'rubygems'
24
+ require 'retrograph/easy'
25
+
26
+ Retrograph.app do
27
+ title "Retrograph Logo"
28
+ loop do
29
+ show_retrograph_logo
30
+ each_frame do
31
+ break if controllers.first.start_pressed?
32
+ end
33
+ end
34
+ end