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.
- 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,42 @@
|
|
1
|
+
require 'space_invaders/base'
|
2
|
+
require 'space_invaders/behaviors/centerable'
|
3
|
+
|
4
|
+
module SpaceInvaders
|
5
|
+
class GameOverScreen < Base
|
6
|
+
include Centerable
|
7
|
+
|
8
|
+
attr_reader :game_over_message, :result, :control_index, :press_play
|
9
|
+
|
10
|
+
def initialize app
|
11
|
+
super
|
12
|
+
@game_over_message = Gosu::Image.from_text app, "G A M E O V E R", App::DEFAULT_FONT, 50
|
13
|
+
@press_play = Gosu::Image.from_text app, "PRESS SPACE TO PLAY AGAIN", App::DEFAULT_FONT, 30
|
14
|
+
@press_play_counter = 0
|
15
|
+
end
|
16
|
+
|
17
|
+
def draw
|
18
|
+
set_result
|
19
|
+
horizontal_center_draw game_over_message, 100
|
20
|
+
horizontal_center_draw result, 200
|
21
|
+
|
22
|
+
horizontal_center_draw press_play, 300 if press_play_counter.between?(30,60)
|
23
|
+
update_press_play_counter
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
attr_reader :press_play_counter
|
29
|
+
|
30
|
+
def update_press_play_counter
|
31
|
+
if press_play_counter == 60
|
32
|
+
@press_play_counter = 0
|
33
|
+
else
|
34
|
+
@press_play_counter += 1
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def set_result
|
39
|
+
@result ||= Gosu::Image.from_text app, "SCORE: #{app.score_tracker.score}", App::DEFAULT_FONT, 40
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'space_invaders/base'
|
2
|
+
require 'space_invaders/behaviors/centerable'
|
3
|
+
|
4
|
+
module SpaceInvaders
|
5
|
+
class NextLevelScreen < Base
|
6
|
+
include Centerable
|
7
|
+
|
8
|
+
attr_reader :next_level_message
|
9
|
+
|
10
|
+
def initialize app
|
11
|
+
super
|
12
|
+
@next_level_message = Gosu::Image.from_text app, "NEXT LEVEL", App::DEFAULT_FONT, 50
|
13
|
+
end
|
14
|
+
|
15
|
+
def draw
|
16
|
+
if time_passed?
|
17
|
+
timer_stop!
|
18
|
+
game_status.continue!
|
19
|
+
else
|
20
|
+
horizontal_center_draw next_level_message, 300
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def timer_start!
|
25
|
+
@timeout = Time.now
|
26
|
+
end
|
27
|
+
|
28
|
+
def timer_stop!
|
29
|
+
app.invaders_container.reinitialize!
|
30
|
+
@timeout = nil
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def time_passed?
|
36
|
+
Time.now - @timeout > 3
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'space_invaders/base'
|
2
|
+
require 'space_invaders/behaviors/centerable'
|
3
|
+
|
4
|
+
module SpaceInvaders
|
5
|
+
class WelcomeScreen < Base
|
6
|
+
include Centerable
|
7
|
+
|
8
|
+
attr_reader :welcome_message, :control_index, :press_play
|
9
|
+
|
10
|
+
def initialize app
|
11
|
+
super
|
12
|
+
@welcome_message = Gosu::Image.from_text app, "SpaceInvaders.rb", App::DEFAULT_FONT, 50
|
13
|
+
@control_index = Gosu::Image.from_text app, control_index_string, App::DEFAULT_FONT, 20
|
14
|
+
@press_play = Gosu::Image.from_text app, "PRESS SPACE TO PLAY", App::DEFAULT_FONT, 30
|
15
|
+
@press_play_counter = 0
|
16
|
+
end
|
17
|
+
|
18
|
+
def draw
|
19
|
+
horizontal_center_draw welcome_message, 100
|
20
|
+
horizontal_center_draw control_index, 200
|
21
|
+
|
22
|
+
|
23
|
+
horizontal_center_draw press_play, 350 if press_play_counter.between?(30,60)
|
24
|
+
update_press_play_counter
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
attr_reader :press_play_counter
|
30
|
+
|
31
|
+
def control_index_string
|
32
|
+
" :space => :fire \n" +
|
33
|
+
" :left_arrow => :move_left \n" +
|
34
|
+
":right_arrow => :move_right\n"
|
35
|
+
end
|
36
|
+
|
37
|
+
def update_press_play_counter
|
38
|
+
if press_play_counter == 60
|
39
|
+
@press_play_counter = 0
|
40
|
+
else
|
41
|
+
@press_play_counter += 1
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module SpaceInvaders
|
2
|
+
class DrownedShipAnimator < Base
|
3
|
+
|
4
|
+
ANIMATION_LENGTH_IN_SECONDS = 2
|
5
|
+
|
6
|
+
attr_accessor :ship
|
7
|
+
|
8
|
+
def initialize(app, ship)
|
9
|
+
super(app)
|
10
|
+
@ship = ship
|
11
|
+
end
|
12
|
+
|
13
|
+
def start!
|
14
|
+
@start_time = Time.now
|
15
|
+
end
|
16
|
+
|
17
|
+
def animation_time_is_over?
|
18
|
+
passed_time > ANIMATION_LENGTH_IN_SECONDS
|
19
|
+
end
|
20
|
+
|
21
|
+
def reset!
|
22
|
+
@start_time = nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def update
|
26
|
+
ship.image = if animation_time_is_over?
|
27
|
+
app.game_status.continue!
|
28
|
+
app.images.ship
|
29
|
+
elsif left_image_time?
|
30
|
+
app.images.ship_crushed_left
|
31
|
+
else
|
32
|
+
app.images.ship_crushed_right
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def passed_time
|
39
|
+
Time.now - @start_time
|
40
|
+
end
|
41
|
+
|
42
|
+
def left_image_time?
|
43
|
+
(passed_time * 10 % 10).round.even?
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'space_invaders/ship/drowned_ship_animator'
|
2
|
+
require 'space_invaders/behaviors/mesurable'
|
3
|
+
require 'space_invaders/behaviors/collideable'
|
4
|
+
require 'space_invaders/behaviors/fireable'
|
5
|
+
module SpaceInvaders
|
6
|
+
class Ship < Base
|
7
|
+
include Mesurable
|
8
|
+
include Fireable
|
9
|
+
include Collideable
|
10
|
+
|
11
|
+
attr_accessor :lives, :image, :drowned_ship_animator
|
12
|
+
|
13
|
+
def initialize app
|
14
|
+
super
|
15
|
+
@image = app.images.ship
|
16
|
+
@x_position = app.width/2 - 40
|
17
|
+
@y_position = app.height - 50
|
18
|
+
@lives = 3
|
19
|
+
@drowned_ship_animator = DrownedShipAnimator.new app, self
|
20
|
+
end
|
21
|
+
|
22
|
+
def update
|
23
|
+
if game_status.drowned_ship?
|
24
|
+
drowned_ship_animator.update
|
25
|
+
else
|
26
|
+
if collides_with? rival_bullets
|
27
|
+
handle_collision
|
28
|
+
else
|
29
|
+
move_ship
|
30
|
+
bullet_collection.update
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def no_more_lives?
|
36
|
+
lives == 0
|
37
|
+
end
|
38
|
+
|
39
|
+
def shooter
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
def sound
|
44
|
+
app.sounds.ship_bullet_sound
|
45
|
+
end
|
46
|
+
|
47
|
+
def bullets_going_down?
|
48
|
+
false
|
49
|
+
end
|
50
|
+
|
51
|
+
def bullet_offset_speed
|
52
|
+
10
|
53
|
+
end
|
54
|
+
|
55
|
+
def draw
|
56
|
+
@image.draw @x_position, @y_position, 1
|
57
|
+
bullet_collection.draw
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def rival_bullets
|
63
|
+
app.invaders_container.bullets
|
64
|
+
end
|
65
|
+
|
66
|
+
def decrease_lives!
|
67
|
+
@lives -= 1
|
68
|
+
app.lives_tracker.decrease_lives!
|
69
|
+
end
|
70
|
+
|
71
|
+
def animate_drowned_ship!
|
72
|
+
if @image == app.images.ship_crushed_left
|
73
|
+
@image = app.images.ship_crushed_right
|
74
|
+
else
|
75
|
+
@image = app.images.ship_crushed_left
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def handle_collision
|
80
|
+
app.sounds.play_ship_hit!
|
81
|
+
decrease_lives!
|
82
|
+
if no_more_lives?
|
83
|
+
game_status.finished!
|
84
|
+
else
|
85
|
+
drowned_ship_animator.start!
|
86
|
+
game_status.drowned_ship!
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def move_ship
|
91
|
+
if app.button_down? Gosu::KbLeft and x_position > 20
|
92
|
+
@x_position += -5
|
93
|
+
elsif app.button_down? Gosu::KbRight and x_position < app.width - 90
|
94
|
+
@x_position += 5
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'space_invaders/base'
|
2
|
+
|
3
|
+
module SpaceInvaders
|
4
|
+
class ButtonController < Base
|
5
|
+
|
6
|
+
def button_down id
|
7
|
+
case id
|
8
|
+
when Gosu::KbEscape
|
9
|
+
escape
|
10
|
+
when Gosu::KbSpace
|
11
|
+
space
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def escape
|
18
|
+
app.close
|
19
|
+
end
|
20
|
+
|
21
|
+
def space
|
22
|
+
if game_status.hasnt_started?
|
23
|
+
game_status.start!
|
24
|
+
elsif game_status.being_played?
|
25
|
+
app.ship.fire!
|
26
|
+
elsif game_status.finished?
|
27
|
+
app.initialize_dynamics_and_trackers
|
28
|
+
game_status.start!
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module SpaceInvaders
|
2
|
+
class GameStatus < Base
|
3
|
+
|
4
|
+
attr_accessor :started, :finished, :drowned_ship, :next_level
|
5
|
+
|
6
|
+
alias_method :started?, :started
|
7
|
+
alias_method :finished?, :finished
|
8
|
+
alias_method :drowned_ship?, :drowned_ship
|
9
|
+
alias_method :next_level?, :next_level
|
10
|
+
|
11
|
+
def initialze app
|
12
|
+
super
|
13
|
+
@started = false
|
14
|
+
@finished = false
|
15
|
+
@drowned_ship = false
|
16
|
+
@next_level = false
|
17
|
+
end
|
18
|
+
|
19
|
+
def being_played?
|
20
|
+
started? && !drowned_ship && !next_level? && !finished?
|
21
|
+
end
|
22
|
+
|
23
|
+
def hasnt_started?
|
24
|
+
not started?
|
25
|
+
end
|
26
|
+
|
27
|
+
def next_level!
|
28
|
+
@next_level = true
|
29
|
+
end
|
30
|
+
|
31
|
+
def start!
|
32
|
+
@started = true
|
33
|
+
@finished = false
|
34
|
+
end
|
35
|
+
|
36
|
+
def finished!
|
37
|
+
@finished = true
|
38
|
+
end
|
39
|
+
|
40
|
+
def drowned_ship!
|
41
|
+
@drowned_ship = true
|
42
|
+
end
|
43
|
+
|
44
|
+
def continue!
|
45
|
+
@drowned_ship = false
|
46
|
+
@next_level = false
|
47
|
+
end
|
48
|
+
|
49
|
+
def status
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'space_invaders/base'
|
2
|
+
require 'space_invaders/utils'
|
3
|
+
|
4
|
+
module SpaceInvaders
|
5
|
+
class Images < Base
|
6
|
+
|
7
|
+
IMAGES = [ :invader_a1,
|
8
|
+
:invader_a2,
|
9
|
+
:invader_b1,
|
10
|
+
:invader_b2,
|
11
|
+
:invader_c1,
|
12
|
+
:invader_c2,
|
13
|
+
:red_invader,
|
14
|
+
:ship,
|
15
|
+
:ship_crushed_left,
|
16
|
+
:ship_crushed_right,
|
17
|
+
:bullet,
|
18
|
+
:full_block,
|
19
|
+
:ok_block,
|
20
|
+
:weak_block
|
21
|
+
]
|
22
|
+
|
23
|
+
IMAGES.each do |image|
|
24
|
+
define_method image do
|
25
|
+
if instance_variable_get("@#{image}").nil?
|
26
|
+
instance_variable_set("@#{image}", Gosu::Image.new(app, asset_path(image)))
|
27
|
+
end
|
28
|
+
instance_variable_get("@#{image}")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def asset_path(image_name)
|
35
|
+
camel_case_name = Utils.camelcase(image_name)
|
36
|
+
File.join("assets", "images", "#{camel_case_name}.png")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'space_invaders/base'
|
2
|
+
module SpaceInvaders
|
3
|
+
class Sounds < Base
|
4
|
+
|
5
|
+
def ship_hit_sound
|
6
|
+
@ship_hit_sound ||= Gosu::Sample.new(app, "assets/sounds/ShipHit.wav")
|
7
|
+
end
|
8
|
+
|
9
|
+
def ship_bullet_sound
|
10
|
+
@ship_bullet_sound ||= Gosu::Sample.new(app, "assets/sounds/ShipBullet.wav")
|
11
|
+
end
|
12
|
+
|
13
|
+
def invader_hit_sound
|
14
|
+
@invader_hit_sound ||= Gosu::Sample.new(app, "assets/sounds/InvaderHit.wav")
|
15
|
+
end
|
16
|
+
|
17
|
+
def invader_bullet_sound
|
18
|
+
@invader_bullet_sound ||= Gosu::Sample.new(app, "assets/sounds/InvaderBullet.wav")
|
19
|
+
end
|
20
|
+
|
21
|
+
def play_ship_hit!
|
22
|
+
ship_hit_sound.play volume=0.5
|
23
|
+
end
|
24
|
+
|
25
|
+
def play_ship_fire!
|
26
|
+
ship_bullet_sound.play volume=0.05
|
27
|
+
end
|
28
|
+
|
29
|
+
def play_invader_hit!
|
30
|
+
invader_hit_sound.play volume=0.5
|
31
|
+
end
|
32
|
+
|
33
|
+
def play_invader_fire!
|
34
|
+
invader_bullet_sound.play volume=0.05
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module SpaceInvaders
|
2
|
+
class LivesTracker < Base
|
3
|
+
|
4
|
+
attr_reader :lives
|
5
|
+
|
6
|
+
def initialize app
|
7
|
+
@app = app
|
8
|
+
@lives = app.ship.lives
|
9
|
+
@lives_headline = Gosu::Image.from_text @app, "Lives:", App::DEFAULT_FONT, 30
|
10
|
+
set_lives_number
|
11
|
+
end
|
12
|
+
|
13
|
+
def decrease_lives!
|
14
|
+
@lives -= 1
|
15
|
+
set_lives_number
|
16
|
+
end
|
17
|
+
|
18
|
+
def set_lives_number
|
19
|
+
@lives_number = Gosu::Image.from_text @app, @lives, App::DEFAULT_FONT, 30
|
20
|
+
end
|
21
|
+
|
22
|
+
def draw
|
23
|
+
@lives_headline.draw app.width - 150, 10, 1
|
24
|
+
@lives_number.draw app.width - 50, 10, 1, 1, 1, Gosu::Color::GREEN
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|