space_invaders 0.0.2

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.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +38 -0
  6. data/Rakefile +1 -0
  7. data/assets/fonts/unifont.ttf +0 -0
  8. data/assets/images/Bullet.png +0 -0
  9. data/assets/images/FullBlock.png +0 -0
  10. data/assets/images/InvaderA1.png +0 -0
  11. data/assets/images/InvaderA2.png +0 -0
  12. data/assets/images/InvaderB1.png +0 -0
  13. data/assets/images/InvaderB2.png +0 -0
  14. data/assets/images/InvaderC1.png +0 -0
  15. data/assets/images/InvaderC2.png +0 -0
  16. data/assets/images/OkBlock.png +0 -0
  17. data/assets/images/RedInvader.png +0 -0
  18. data/assets/images/Ship.png +0 -0
  19. data/assets/images/ShipCrushedLeft.png +0 -0
  20. data/assets/images/ShipCrushedRight.png +0 -0
  21. data/assets/images/WeakBlock.png +0 -0
  22. data/assets/sounds/InvaderBullet.wav +0 -0
  23. data/assets/sounds/InvaderHit.wav +0 -0
  24. data/assets/sounds/ShipBullet.wav +0 -0
  25. data/assets/sounds/ShipHit.wav +0 -0
  26. data/bin/space-invaders +9 -0
  27. data/go.rb +5 -0
  28. data/lib/space_invaders.rb +4 -0
  29. data/lib/space_invaders/app.rb +99 -0
  30. data/lib/space_invaders/base.rb +14 -0
  31. data/lib/space_invaders/behaviors/centerable.rb +13 -0
  32. data/lib/space_invaders/behaviors/collideable.rb +18 -0
  33. data/lib/space_invaders/behaviors/fireable.rb +35 -0
  34. data/lib/space_invaders/behaviors/mesurable.rb +17 -0
  35. data/lib/space_invaders/blocks/block.rb +62 -0
  36. data/lib/space_invaders/blocks/u_block.rb +37 -0
  37. data/lib/space_invaders/blocks/u_block_container.rb +46 -0
  38. data/lib/space_invaders/bullets/bullet.rb +46 -0
  39. data/lib/space_invaders/bullets/bullet_collection.rb +23 -0
  40. data/lib/space_invaders/invaders/invader.rb +38 -0
  41. data/lib/space_invaders/invaders/invader_abc.rb +27 -0
  42. data/lib/space_invaders/invaders/invader_row.rb +52 -0
  43. data/lib/space_invaders/invaders/invaders_container.rb +146 -0
  44. data/lib/space_invaders/invaders/red_invader.rb +66 -0
  45. data/lib/space_invaders/screens/game_over_screen.rb +42 -0
  46. data/lib/space_invaders/screens/next_level_screen.rb +39 -0
  47. data/lib/space_invaders/screens/welcome_screen.rb +46 -0
  48. data/lib/space_invaders/ship/drowned_ship_animator.rb +46 -0
  49. data/lib/space_invaders/ship/ship.rb +99 -0
  50. data/lib/space_invaders/statics/button_controller.rb +33 -0
  51. data/lib/space_invaders/statics/game_status.rb +52 -0
  52. data/lib/space_invaders/statics/images.rb +39 -0
  53. data/lib/space_invaders/statics/sounds.rb +37 -0
  54. data/lib/space_invaders/trackers/lives_tracker.rb +27 -0
  55. data/lib/space_invaders/trackers/score_tracker.rb +27 -0
  56. data/lib/space_invaders/utils.rb +19 -0
  57. data/space_invaders.gemspec +23 -0
  58. metadata +143 -0
@@ -0,0 +1,46 @@
1
+ require 'space_invaders/base'
2
+ require 'space_invaders/blocks/u_block'
3
+
4
+ module SpaceInvaders
5
+ class UBlockContainer < Base
6
+
7
+ attr_reader :u_blocks
8
+
9
+ def initialize app
10
+ super
11
+ initialize_u_blocks
12
+ end
13
+
14
+ def update
15
+ @u_blocks.each { |item| item.update }
16
+ end
17
+
18
+ def draw
19
+ @u_blocks.each {|item| item.draw }
20
+ end
21
+
22
+ def initialize_u_blocks
23
+ @u_blocks = [
24
+ UBlock.new(app, 150, 400),
25
+ UBlock.new(app, 350, 400),
26
+ UBlock.new(app, 550, 400)
27
+ ]
28
+ end
29
+
30
+ def each(&block)
31
+ @u_blocks.each(&block)
32
+ end
33
+
34
+ def delete(item)
35
+ @u_blocks.delete(item)
36
+ end
37
+
38
+ def <<(item)
39
+ @u_blocks << item
40
+ end
41
+
42
+ alias_method :push, :<<
43
+ alias_method :add, :<<
44
+
45
+ end
46
+ end
@@ -0,0 +1,46 @@
1
+ module SpaceInvaders
2
+ class Bullet < Base
3
+
4
+ attr_reader :x_position, :y_position, :going_down, :bullet_offset, :bullet_collection, :image, :fireing_vehicle
5
+
6
+ alias_method :going_down?, :going_down
7
+
8
+ def initialize fireing_vehicle, going_down, bullet_collection, bullet_offset=10
9
+ super(fireing_vehicle.app)
10
+ @fireing_vehicle = fireing_vehicle
11
+ @image = app.images.bullet
12
+ @bullet_offset = bullet_offset
13
+ @going_down = going_down
14
+ @bullet_collection = bullet_collection
15
+ @bullet_collection << self
16
+ set_position
17
+ end
18
+
19
+ def update
20
+ @y_position += going_down? ? bullet_offset : -bullet_offset
21
+ end
22
+
23
+ def draw
24
+ image.draw x_position, y_position, 1
25
+ end
26
+
27
+ def delete
28
+ bullet_collection.delete(self)
29
+ end
30
+
31
+ def out_of_screen
32
+ if going_down
33
+ y_position > app.height
34
+ else
35
+ y_position < 0
36
+ end
37
+ end
38
+
39
+ def set_position
40
+ @x_position = fireing_vehicle.x_middle - image.width/2
41
+ @y_position = fireing_vehicle.y_position
42
+ @y_position += fireing_vehicle.height if going_down
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,23 @@
1
+ require 'forwardable'
2
+
3
+ module SpaceInvaders
4
+ class BulletCollection
5
+ extend Forwardable
6
+ attr_reader :bullets
7
+
8
+ def initialize
9
+ @bullets = []
10
+ end
11
+
12
+ def update
13
+ @bullets.delete_if {|bullet| bullet.out_of_screen}
14
+ @bullets.each { |bullet| bullet.update }
15
+ end
16
+
17
+ def draw
18
+ @bullets.each {|bullet| bullet.draw }
19
+ end
20
+
21
+ def_delegators :@bullets, :each, :delete, :<<, :clear
22
+ end
23
+ end
@@ -0,0 +1,38 @@
1
+ require 'space_invaders/behaviors/mesurable'
2
+ require 'space_invaders/behaviors/collideable'
3
+ module SpaceInvaders
4
+ class Invader < Base
5
+ include Mesurable
6
+ include Collideable
7
+
8
+ attr_reader :original_x_position
9
+
10
+ def initialize app, x_position, y_position
11
+ super app
12
+
13
+ @was_first_image = true
14
+ @x_position = x_position
15
+ @original_x_position = x_position
16
+ @y_position = y_position
17
+ @image = @first_image
18
+ end
19
+
20
+ def update(direction, y_offset=0)
21
+ x_offset = direction == :right ? 10 : -10
22
+ @x_position += x_offset
23
+ @y_position += y_offset
24
+
25
+ @was_first_image = !@was_first_image
26
+ @image = @was_first_image ? @first_image : @second_image
27
+ end
28
+
29
+ def draw
30
+ @image.draw x_position, y_position, 1
31
+ end
32
+
33
+ def points
34
+ raise NotImplementedError.new("You must implement the inherited points method")
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,27 @@
1
+ require 'space_invaders/invaders/invader'
2
+ require 'space_invaders/utils'
3
+
4
+ module SpaceInvaders
5
+ [:invader_a, :invader_b, :invader_c].each do |invader_name|
6
+ clazz_name = Utils.camelcase(invader_name)
7
+ clazz = Class.new(Invader) do
8
+ def initialize app, x_position=0, y_position=0
9
+ @first_image = Gosu::Image.new app, app.images.send("#{Utils.snake_klazz_name(self.class)}1")
10
+ @second_image = Gosu::Image.new app, app.images.send("#{Utils.snake_klazz_name(self.class)}2")
11
+ super
12
+ end
13
+
14
+ def points
15
+ case self
16
+ when InvaderA
17
+ 40
18
+ when InvaderB
19
+ 20
20
+ when InvaderC
21
+ 10
22
+ end
23
+ end
24
+ end
25
+ Object.const_set(clazz_name, clazz)
26
+ end
27
+ end
@@ -0,0 +1,52 @@
1
+ require 'forwardable'
2
+ require 'space_invaders/base'
3
+
4
+ module SpaceInvaders
5
+ class InvaderRow < Base
6
+ extend Forwardable
7
+
8
+ attr_accessor :direction
9
+ attr_reader :invader_clazz
10
+
11
+ X_POSITIONS = [40, 110, 180, 250, 320, 390, 460, 530]
12
+
13
+ def initialize app, y_position, invader_clazz
14
+ super(app)
15
+ @y_position = y_position
16
+ @direction = :right
17
+ @invader_clazz = invader_clazz
18
+ @invaders = []
19
+ X_POSITIONS.each do |x_position|
20
+ @invaders << invader_clazz.new(app, x_position, y_position)
21
+ end
22
+ end
23
+
24
+ def_delegators :@invaders, :each, :count, :select, :find, :empty?
25
+
26
+ def update direction, y_offset
27
+ @invaders.each {|invader| invader.update direction, y_offset }
28
+ end
29
+
30
+ def draw
31
+ @invaders.each {|invader| invader.draw }
32
+ end
33
+
34
+ def farmost_right_position
35
+ @invaders.max_by {|invader| invader.x_position }.x_position
36
+ end
37
+
38
+ def farmost_left_position
39
+ @invaders.min_by {|invader| invader.x_position }.x_position
40
+ end
41
+
42
+ def check_collision(bullets)
43
+ @invaders.delete_if do |invader|
44
+ if invader.collides_with? bullets
45
+ app.score_tracker.increase_by(invader.points)
46
+ app.sounds.play_invader_hit!
47
+ end
48
+ end
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,146 @@
1
+ require 'space_invaders/invaders/invader_row'
2
+ require 'space_invaders/invaders/invader_abc'
3
+ require 'space_invaders/behaviors/fireable'
4
+
5
+ module SpaceInvaders
6
+ class InvadersContainer < Base
7
+ include Fireable
8
+ attr_reader :invader_rows
9
+
10
+ def initialize app
11
+ super
12
+ create_invader_rows
13
+ @change_time = Time.now
14
+ @can_fire = Time.now
15
+ @direction = :right
16
+ @y_offset = 0
17
+ end
18
+
19
+ def update
20
+ check_collision
21
+
22
+ if no_invaders?
23
+ app.next_level_screen.timer_start!
24
+ return game_status.next_level!
25
+ end
26
+
27
+ if can_change?
28
+ change_direction
29
+ @change_time = Time.now
30
+ end
31
+
32
+ if can_fire?
33
+ fire!
34
+ @can_fire = Time.now
35
+ end
36
+
37
+ bullets.update
38
+ end
39
+
40
+ def draw
41
+ invader_rows.each {|invader_row| invader_row.draw }
42
+ bullets.draw
43
+ end
44
+
45
+ def count
46
+ invader_rows.map {|invader_row| invader_row.count}.inject(:+) || 0
47
+ end
48
+
49
+ def any_invaders?
50
+ not count.zero?
51
+ end
52
+
53
+ def no_invaders?
54
+ count.zero?
55
+ end
56
+
57
+ def reinitialize!
58
+ create_invader_rows
59
+ bullets.clear
60
+ rival_bullets.clear
61
+ @change_time = Time.now
62
+ @can_fire = Time.now
63
+ end
64
+
65
+ private
66
+
67
+ def check_collision
68
+ invader_rows.each { |invader_row| invader_row.check_collision(rival_bullets) }
69
+ invader_rows.delete_if {|invader_row| invader_row.empty?}
70
+ hit_rock_bottom? if any_invaders?
71
+ end
72
+
73
+ def hit_rock_bottom?
74
+ if any_invaders? and fireable_invaders.first.y_position == app.height
75
+ app.game_status.finished!
76
+ end
77
+ end
78
+
79
+ def change_direction
80
+ if farmost_right_position >= app.width - 80
81
+ @direction = :left
82
+ @y_offset = 10
83
+ elsif farmost_left_position <= 20
84
+ @direction = :right
85
+ @y_offset = 10
86
+ else
87
+ @y_offset = 0
88
+ end
89
+ update_direction(@direction, @y_offset)
90
+ end
91
+
92
+ def update_direction direction, y_offset
93
+ invader_rows.each {|invader_row| invader_row.update direction, y_offset }
94
+ end
95
+
96
+ def shooter
97
+ fireable_invaders.sample
98
+ end
99
+
100
+ def sound
101
+ app.sounds.invader_bullet_sound
102
+ end
103
+
104
+ def can_fire?
105
+ Time.now > @can_fire + 2
106
+ end
107
+
108
+ def can_change?
109
+ Time.now > @change_time + 0.25
110
+ end
111
+
112
+ def fireable_invaders
113
+ InvaderRow::X_POSITIONS.map do |x_position|
114
+ invader_rows.reverse.map do |invader_row|
115
+ invader_row.find {|invader| invader.original_x_position == x_position }
116
+ end.compact.first
117
+ end.compact
118
+ end
119
+
120
+ def create_invader_rows
121
+ @invader_rows = [
122
+ InvaderRow.new(app, 100, InvaderA),
123
+ InvaderRow.new(app, 150, InvaderB),
124
+ InvaderRow.new(app, 200, InvaderB),
125
+ InvaderRow.new(app, 250, InvaderC),
126
+ InvaderRow.new(app, 300, InvaderC),
127
+ ]
128
+ end
129
+
130
+ def rival_bullets
131
+ app.ship.bullets
132
+ end
133
+
134
+ def farmost_right_position
135
+ invader_rows.max_by do |invader_row|
136
+ invader_row.farmost_right_position
137
+ end.farmost_right_position
138
+ end
139
+
140
+ def farmost_left_position
141
+ invader_rows.min_by do |invader_row|
142
+ invader_row.farmost_left_position
143
+ end.farmost_left_position
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,66 @@
1
+ require 'space_invaders/invaders/invader'
2
+
3
+ module SpaceInvaders
4
+ class RedInvader < Invader
5
+ attr_accessor :dead
6
+
7
+ alias_method :dead?, :dead
8
+
9
+ def initialize app, x_position=0, y_position=50
10
+ @first_image = app.images.red_invader
11
+ @second_image = app.images.red_invader
12
+ @can_move = Time.now
13
+ @direction = :right
14
+ @dead = false
15
+ super
16
+ end
17
+
18
+ def points
19
+ 100
20
+ end
21
+
22
+ def alive?
23
+ not dead?
24
+ end
25
+
26
+ def update
27
+ return if dead?
28
+
29
+ if collides_with? rival_bullets
30
+ handle_death
31
+ elsif can_move?
32
+ set_direction
33
+ @x_position += @direction == :right ? 10 : -10
34
+ @can_move = Time.now
35
+ end
36
+ end
37
+
38
+ def draw
39
+ return if dead?
40
+ @image.draw @x_position, @y_position, 1
41
+ end
42
+
43
+ def handle_death
44
+ @dead = true
45
+ app.score_tracker.increase_by(points)
46
+ app.sounds.play_invader_hit!
47
+ end
48
+
49
+ def set_direction
50
+ if @x_position >= app.width - 80
51
+ @direction = :left
52
+ elsif @x_position <= 20
53
+ @direction = :right
54
+ end
55
+ end
56
+
57
+ def rival_bullets
58
+ app.ship.bullets
59
+ end
60
+
61
+ def can_move?
62
+ Time.now - @can_move > 0.1
63
+ end
64
+
65
+ end
66
+ end