space_invaders 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +38 -0
- data/Rakefile +1 -0
- data/assets/fonts/unifont.ttf +0 -0
- data/assets/images/Bullet.png +0 -0
- data/assets/images/FullBlock.png +0 -0
- data/assets/images/InvaderA1.png +0 -0
- data/assets/images/InvaderA2.png +0 -0
- data/assets/images/InvaderB1.png +0 -0
- data/assets/images/InvaderB2.png +0 -0
- data/assets/images/InvaderC1.png +0 -0
- data/assets/images/InvaderC2.png +0 -0
- data/assets/images/OkBlock.png +0 -0
- data/assets/images/RedInvader.png +0 -0
- data/assets/images/Ship.png +0 -0
- data/assets/images/ShipCrushedLeft.png +0 -0
- data/assets/images/ShipCrushedRight.png +0 -0
- data/assets/images/WeakBlock.png +0 -0
- data/assets/sounds/InvaderBullet.wav +0 -0
- data/assets/sounds/InvaderHit.wav +0 -0
- data/assets/sounds/ShipBullet.wav +0 -0
- data/assets/sounds/ShipHit.wav +0 -0
- data/bin/space-invaders +9 -0
- data/go.rb +5 -0
- data/lib/space_invaders.rb +4 -0
- data/lib/space_invaders/app.rb +99 -0
- data/lib/space_invaders/base.rb +14 -0
- data/lib/space_invaders/behaviors/centerable.rb +13 -0
- data/lib/space_invaders/behaviors/collideable.rb +18 -0
- data/lib/space_invaders/behaviors/fireable.rb +35 -0
- data/lib/space_invaders/behaviors/mesurable.rb +17 -0
- data/lib/space_invaders/blocks/block.rb +62 -0
- data/lib/space_invaders/blocks/u_block.rb +37 -0
- data/lib/space_invaders/blocks/u_block_container.rb +46 -0
- data/lib/space_invaders/bullets/bullet.rb +46 -0
- data/lib/space_invaders/bullets/bullet_collection.rb +23 -0
- data/lib/space_invaders/invaders/invader.rb +38 -0
- data/lib/space_invaders/invaders/invader_abc.rb +27 -0
- data/lib/space_invaders/invaders/invader_row.rb +52 -0
- data/lib/space_invaders/invaders/invaders_container.rb +146 -0
- data/lib/space_invaders/invaders/red_invader.rb +66 -0
- data/lib/space_invaders/screens/game_over_screen.rb +42 -0
- data/lib/space_invaders/screens/next_level_screen.rb +39 -0
- data/lib/space_invaders/screens/welcome_screen.rb +46 -0
- data/lib/space_invaders/ship/drowned_ship_animator.rb +46 -0
- data/lib/space_invaders/ship/ship.rb +99 -0
- data/lib/space_invaders/statics/button_controller.rb +33 -0
- data/lib/space_invaders/statics/game_status.rb +52 -0
- data/lib/space_invaders/statics/images.rb +39 -0
- data/lib/space_invaders/statics/sounds.rb +37 -0
- data/lib/space_invaders/trackers/lives_tracker.rb +27 -0
- data/lib/space_invaders/trackers/score_tracker.rb +27 -0
- data/lib/space_invaders/utils.rb +19 -0
- data/space_invaders.gemspec +23 -0
- 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
|