asteroids 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +19 -0
- data/Rakefile +2 -0
- data/assets/fonts/victor-pixel.ttf +0 -0
- data/assets/images/asteroid.png +0 -0
- data/assets/images/asteroid_medium.png +0 -0
- data/assets/images/asteroid_small.png +0 -0
- data/assets/images/background.png +0 -0
- data/assets/images/explosion.png +0 -0
- data/assets/images/ship.png +0 -0
- data/assets/images/ship_small.png +0 -0
- data/assets/images/simple_missile.png +0 -0
- data/asteroids.gemspec +30 -0
- data/bin/asteroids +17 -0
- data/lib/asteroids.rb +28 -0
- data/lib/asteroids/asteroid/asteroid.rb +23 -0
- data/lib/asteroids/asteroid/asteroid_graphics.rb +26 -0
- data/lib/asteroids/asteroid/asteroid_physics.rb +51 -0
- data/lib/asteroids/componenets/component.rb +29 -0
- data/lib/asteroids/componenets/game_object.rb +37 -0
- data/lib/asteroids/componenets/game_pool.rb +34 -0
- data/lib/asteroids/explosion/explosion.rb +14 -0
- data/lib/asteroids/explosion/explosion_graphics.rb +48 -0
- data/lib/asteroids/menu/menu.rb +46 -0
- data/lib/asteroids/menu/menu_item.rb +55 -0
- data/lib/asteroids/missile/missile.rb +21 -0
- data/lib/asteroids/missile/missile_graphics.rb +15 -0
- data/lib/asteroids/missile/missile_physics.rb +42 -0
- data/lib/asteroids/ship/ship.rb +51 -0
- data/lib/asteroids/ship/ship_graphics.rb +20 -0
- data/lib/asteroids/ship/ship_physics.rb +58 -0
- data/lib/asteroids/states/game_state.rb +29 -0
- data/lib/asteroids/states/menu_state.rb +41 -0
- data/lib/asteroids/states/play_state.rb +61 -0
- data/lib/asteroids/utils/utils.rb +37 -0
- data/lib/asteroids/version.rb +3 -0
- data/saves/save.yaml +0 -0
- metadata +128 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 653e006ed4b1952a181301ff0b0ebacdc6683cd5
|
4
|
+
data.tar.gz: e8426442c2d7eb1e8a94e2b158e59305258bff9e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c34ba4d438fe0304320a429c7c82ea5fed1d6f7e56b54d40fed78b3352a6a071e71020ccfdbc007ea8008a4b3e4bb49b5b0405706728391c8a1b0111c2b546b1
|
7
|
+
data.tar.gz: 7ade9c273e94d6a5fcd51d0d6c06569e87ad86e96c27c9e31b90a14c55042aab065490fbd65537b9391563077aac0c9e94062b8104175c12cdbb1f09bbe30591
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Svetoslav Kuzmanov
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# Asteroids
|
2
|
+
|
3
|
+
This is my take on the classic arcade space shooted Asteroids by Atari.
|
4
|
+
In the game the player controls a spaceship in an asteroid field which is periodically traversed by flying saucers.
|
5
|
+
The object of the game is to shoot and destroy asteroids and saucers while not colliding with either,
|
6
|
+
or being hit by the saucers counter-fire. The game becomes harder as the number of asteroids increases.
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
To install the game run:
|
11
|
+
$ gem install asteroids
|
12
|
+
|
13
|
+
## Starting the game
|
14
|
+
$ asteroids
|
15
|
+
|
16
|
+
## Controls
|
17
|
+
Use the arrow keys to control the ship
|
18
|
+
Space shoots
|
19
|
+
ESC goes to menu.
|
data/Rakefile
ADDED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/asteroids.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'asteroids/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "asteroids"
|
8
|
+
spec.version = Asteroids::VERSION
|
9
|
+
spec.authors = ["Svetoslav Kuzmanov"]
|
10
|
+
spec.email = ["svetoslav.kuzmanov@gmail.com"]
|
11
|
+
spec.summary = <<-EOS
|
12
|
+
This is my take on the classic arcade space shooter Asteroids by Atari
|
13
|
+
EOS
|
14
|
+
spec.description = <<-EOS
|
15
|
+
This game is build with Gosu library as a final project for the
|
16
|
+
"Programming with Ruby" course.
|
17
|
+
EOS
|
18
|
+
spec.homepage = ""
|
19
|
+
spec.license = "MIT"
|
20
|
+
|
21
|
+
spec.files = `git ls-files -z`.split("\x0")
|
22
|
+
spec.executables = 'asteroids'
|
23
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
24
|
+
spec.require_paths = ["lib"]
|
25
|
+
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
27
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
28
|
+
|
29
|
+
spec.add_runtime_dependency 'gosu'
|
30
|
+
end
|
data/bin/asteroids
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'gosu'
|
4
|
+
require 'yaml'
|
5
|
+
|
6
|
+
root_dir = File.expand_path(File.join(
|
7
|
+
File.dirname(File.dirname(__FILE__)), 'lib'))
|
8
|
+
require_pattern_components = File.join(root_dir, '*/componenets/*.rb')
|
9
|
+
require_pattern = File.join(root_dir, '**/*.rb')
|
10
|
+
|
11
|
+
Dir.glob(require_pattern_components).each { |file| require file }
|
12
|
+
|
13
|
+
Dir.glob(require_pattern).each { |file| require file }
|
14
|
+
|
15
|
+
$window = Asteroids::GameWindow.new
|
16
|
+
Asteroids::GameState.switch(Asteroids::MenuState.instance)
|
17
|
+
$window.show
|
data/lib/asteroids.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
module Asteroids
|
2
|
+
class GameWindow < Gosu::Window
|
3
|
+
|
4
|
+
attr_accessor :state
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
super(800, 600, false)
|
8
|
+
self.caption = 'Asteroids'
|
9
|
+
end
|
10
|
+
|
11
|
+
def update
|
12
|
+
@state.update
|
13
|
+
end
|
14
|
+
|
15
|
+
def draw
|
16
|
+
@state.draw
|
17
|
+
end
|
18
|
+
|
19
|
+
def needs_redraw?
|
20
|
+
@state.needs_redraw?
|
21
|
+
end
|
22
|
+
|
23
|
+
def button_down(id)
|
24
|
+
@state.button_down(id)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Asteroids
|
2
|
+
class Asteroid < GameObject
|
3
|
+
|
4
|
+
attr_accessor :x, :y, :vel_x, :vel_y, :angle, :radius
|
5
|
+
|
6
|
+
def initialize(object_pool, x, y, vel_x, vel_y, angle, radius = 45)
|
7
|
+
super(object_pool)
|
8
|
+
@x = x
|
9
|
+
@y = y
|
10
|
+
@angle = angle
|
11
|
+
@vel_x = vel_x
|
12
|
+
@vel_y = vel_y
|
13
|
+
@physics = AsteroidPhysics.new(self, object_pool)
|
14
|
+
@graphics = AsteroidGraphics.new(self)
|
15
|
+
@radius = radius
|
16
|
+
end
|
17
|
+
|
18
|
+
def explode
|
19
|
+
Explosion.new(object_pool, @x, @y)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Asteroids
|
2
|
+
class AsteroidGraphics < Component
|
3
|
+
|
4
|
+
def initialize(game_object)
|
5
|
+
super(game_object)
|
6
|
+
@image = Gosu::Image.new($window,
|
7
|
+
Utils.get_image_path("asteroid.png"), true)
|
8
|
+
@image_medium = Gosu::Image.new($window,
|
9
|
+
Utils.get_image_path("asteroid_medium.png"), true)
|
10
|
+
@image_small = Gosu::Image.new($window,
|
11
|
+
Utils.get_image_path("asteroid_small.png"), true)
|
12
|
+
end
|
13
|
+
|
14
|
+
def draw
|
15
|
+
case object.radius
|
16
|
+
when 45
|
17
|
+
@image.draw_rot(object.x, object.y, 1, object.angle)
|
18
|
+
when 30
|
19
|
+
@image_medium.draw_rot(object.x, object.y, 1, object.angle)
|
20
|
+
when 17.5
|
21
|
+
@image_small.draw_rot(object.x, object.y, 1, object.angle)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Asteroids
|
2
|
+
class AsteroidPhysics < Component
|
3
|
+
|
4
|
+
def initialize(game_object, object_pool)
|
5
|
+
super(game_object)
|
6
|
+
@object_pool = object_pool
|
7
|
+
end
|
8
|
+
|
9
|
+
def update
|
10
|
+
if detect_collision?
|
11
|
+
@explosion_time = Gosu.milliseconds
|
12
|
+
object.explode
|
13
|
+
end
|
14
|
+
if @explosion_time
|
15
|
+
if Gosu.milliseconds - @explosion_time > 100
|
16
|
+
object.mark_for_removal
|
17
|
+
if object.radius == 45
|
18
|
+
2.times do |n|
|
19
|
+
Asteroid.new(@object_pool, object.x + rand(20),
|
20
|
+
object.y + rand(20), rand * (-1.5), rand() * 1.5, rand * 3,
|
21
|
+
(object.radius - 15))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
if object.radius == 30
|
25
|
+
2.times do |n|
|
26
|
+
Asteroid.new(@object_pool, object.x + rand(20),
|
27
|
+
object.y + rand(20), rand() * (-2.2), rand() * 2.2, rand * 3,
|
28
|
+
(object.radius - 12.5))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
object.x += Gosu::offset_x(object.angle, 0.0001) + object.vel_x
|
34
|
+
object.y += Gosu::offset_y(object.angle, 0.0001) + object.vel_y
|
35
|
+
object.x %= 800
|
36
|
+
object.y %= 600
|
37
|
+
end
|
38
|
+
|
39
|
+
def detect_collision?
|
40
|
+
@object_pool.objects.each do |other_object|
|
41
|
+
if other_object.is_a? Asteroids::Missile or
|
42
|
+
other_object.is_a? Asteroids::Ship and
|
43
|
+
Utils.collide(object, other_object)
|
44
|
+
return true
|
45
|
+
end
|
46
|
+
end
|
47
|
+
return false
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Asteroids
|
2
|
+
class Component
|
3
|
+
|
4
|
+
def initialize(game_object = nil)
|
5
|
+
self.object = game_object
|
6
|
+
end
|
7
|
+
|
8
|
+
def update
|
9
|
+
end
|
10
|
+
|
11
|
+
def draw
|
12
|
+
end
|
13
|
+
|
14
|
+
protected
|
15
|
+
|
16
|
+
def object=(obj)
|
17
|
+
if obj
|
18
|
+
@object = obj
|
19
|
+
obj.components << self
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def object
|
24
|
+
@object
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Asteroids
|
2
|
+
class GameObject
|
3
|
+
|
4
|
+
def initialize(object_pool)
|
5
|
+
@components = []
|
6
|
+
@object_pool = object_pool
|
7
|
+
@object_pool.objects << self
|
8
|
+
end
|
9
|
+
|
10
|
+
def components
|
11
|
+
@components
|
12
|
+
end
|
13
|
+
|
14
|
+
def update
|
15
|
+
@components.map(&:update)
|
16
|
+
end
|
17
|
+
|
18
|
+
def draw
|
19
|
+
@components.map(&:draw)
|
20
|
+
end
|
21
|
+
|
22
|
+
def removable?
|
23
|
+
@removable
|
24
|
+
end
|
25
|
+
|
26
|
+
def mark_for_removal
|
27
|
+
@removable = true
|
28
|
+
end
|
29
|
+
|
30
|
+
protected
|
31
|
+
|
32
|
+
def object_pool
|
33
|
+
@object_pool
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Asteroids
|
2
|
+
class ObjectPool
|
3
|
+
attr_accessor :objects
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@objects = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def update_all
|
10
|
+
@objects.map(&:update)
|
11
|
+
@objects.delete_if { |object| object.removable?}
|
12
|
+
end
|
13
|
+
|
14
|
+
def find_empty_space
|
15
|
+
x = Gosu::random(0, 800)
|
16
|
+
y = Gosu::random(0, 600)
|
17
|
+
while is_not_empty(x, y)
|
18
|
+
x = Gosu::random(0, 800)
|
19
|
+
y = Gosu::random(0, 600)
|
20
|
+
end
|
21
|
+
{x: x, y: y}
|
22
|
+
end
|
23
|
+
|
24
|
+
def is_not_empty(x, y)
|
25
|
+
@objects.each do |object|
|
26
|
+
if object.is_a? Asteroids::Asteroid and object.x == x and object.y == y
|
27
|
+
return true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
false
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Asteroids
|
2
|
+
class ExplosionGraphics < Component
|
3
|
+
|
4
|
+
FRAME_DELAY = 17
|
5
|
+
|
6
|
+
def initialize(game_object)
|
7
|
+
super
|
8
|
+
@current_frame = 0
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
def draw()
|
13
|
+
image = current_frame
|
14
|
+
image.draw(
|
15
|
+
object.x - image.width / 2.0,
|
16
|
+
object.y - image.height / 2.0,
|
17
|
+
100)
|
18
|
+
end
|
19
|
+
|
20
|
+
def update
|
21
|
+
now = Gosu.milliseconds
|
22
|
+
delta = now - (@last_frame ||= now)
|
23
|
+
if delta > FRAME_DELAY
|
24
|
+
@last_frame = now
|
25
|
+
end
|
26
|
+
@current_frame += (delta / FRAME_DELAY).floor
|
27
|
+
object.mark_for_removal if done?
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def current_frame
|
33
|
+
animation[@current_frame % animation.size]
|
34
|
+
end
|
35
|
+
|
36
|
+
def done?
|
37
|
+
@done ||= @current_frame >= animation.size
|
38
|
+
end
|
39
|
+
|
40
|
+
def animation
|
41
|
+
@@animation ||=
|
42
|
+
Gosu::Image.load_tiles(
|
43
|
+
$window, Utils.get_image_path("explosion.png"),
|
44
|
+
128, 128, false)
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Asteroids
|
2
|
+
class Menu
|
3
|
+
def initialize ()
|
4
|
+
@items = []
|
5
|
+
end
|
6
|
+
|
7
|
+
def add_item (image, callback, selected)
|
8
|
+
item = MenuItem.new(image, callback, selected)
|
9
|
+
@items << item
|
10
|
+
item.x = position[:x]
|
11
|
+
item.y = position[:y]
|
12
|
+
end
|
13
|
+
|
14
|
+
def draw
|
15
|
+
@items.each do |i|
|
16
|
+
i.draw
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def position
|
21
|
+
{x: $window.width / 2 - @items[@items.count - 1].width / 2,
|
22
|
+
y: $window.height / 3 - @items[@items.count - 1].height / 3 +
|
23
|
+
@items.count * 60 }
|
24
|
+
end
|
25
|
+
|
26
|
+
def select_item(which)
|
27
|
+
@items.each_with_index do |item, index|
|
28
|
+
if item.is_selected?
|
29
|
+
if @items[index.send(which, 1) % 3].select
|
30
|
+
item.deselect
|
31
|
+
return true
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def confirm
|
38
|
+
@items.each do |item|
|
39
|
+
if item.is_selected?
|
40
|
+
item.execute
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Asteroids
|
2
|
+
class MenuItem
|
3
|
+
attr_writer :x, :y
|
4
|
+
|
5
|
+
def initialize (text, callback, selected)
|
6
|
+
@image = Gosu::Image.from_text($window, text,
|
7
|
+
Utils.get_font_path('victor-pixel.ttf'), 65)
|
8
|
+
@x = 0
|
9
|
+
@y = 0
|
10
|
+
@callback = callback
|
11
|
+
@selected = selected
|
12
|
+
end
|
13
|
+
|
14
|
+
def draw
|
15
|
+
if @selected
|
16
|
+
@image.draw(@x, @y, 10, 1, 1, 0xffffff00)
|
17
|
+
else
|
18
|
+
@image.draw(@x, @y, 10)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def is_selected?
|
23
|
+
@selected
|
24
|
+
end
|
25
|
+
|
26
|
+
def select
|
27
|
+
@selected = true
|
28
|
+
end
|
29
|
+
|
30
|
+
def deselect
|
31
|
+
@selected = false
|
32
|
+
end
|
33
|
+
|
34
|
+
def execute
|
35
|
+
if @selected
|
36
|
+
@callback.call
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def width
|
41
|
+
@image.width
|
42
|
+
end
|
43
|
+
|
44
|
+
def height
|
45
|
+
@image.height
|
46
|
+
end
|
47
|
+
|
48
|
+
def execute
|
49
|
+
if @selected
|
50
|
+
@callback.call
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Asteroids
|
2
|
+
class Missile < GameObject
|
3
|
+
|
4
|
+
attr_accessor :ship, :x, :y, :vel_x, :vel_y, :angle, :lifespan, :radius
|
5
|
+
|
6
|
+
def initialize(ship, object_pool, x, y, vel_x, vel_y, angle)
|
7
|
+
super(object_pool)
|
8
|
+
@x = x
|
9
|
+
@y = y
|
10
|
+
@angle = angle
|
11
|
+
@vel_x = vel_x
|
12
|
+
@vel_y = vel_y
|
13
|
+
@lifespan = 3
|
14
|
+
@radius = 3
|
15
|
+
@ship = ship
|
16
|
+
@physics = MissilePhysics.new(self, object_pool)
|
17
|
+
@graphics = MissileGraphics.new(self)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Asteroids
|
2
|
+
class MissileGraphics < Component
|
3
|
+
|
4
|
+
def initialize(game_object)
|
5
|
+
super(game_object)
|
6
|
+
@image = Gosu::Image.new($window,
|
7
|
+
Utils.get_image_path("simple_missile.png"), true)
|
8
|
+
end
|
9
|
+
|
10
|
+
def draw
|
11
|
+
@image.draw_rot(object.x, object.y, 0, object.angle)
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Asteroids
|
2
|
+
class MissilePhysics < Component
|
3
|
+
|
4
|
+
def initialize(game_object, object_pool)
|
5
|
+
super(game_object)
|
6
|
+
@object_pool = object_pool
|
7
|
+
end
|
8
|
+
|
9
|
+
def update
|
10
|
+
object.mark_for_removal if detect_collision?
|
11
|
+
object.x += Gosu::offset_x(object.angle, 10) + object.vel_x
|
12
|
+
object.y += Gosu::offset_y(object.angle, 10) + object.vel_y
|
13
|
+
object.x %= 800
|
14
|
+
object.y %= 600
|
15
|
+
object.lifespan -= 0.1
|
16
|
+
object.mark_for_removal if object.lifespan <= 0
|
17
|
+
end
|
18
|
+
|
19
|
+
def detect_collision?
|
20
|
+
@object_pool.objects.each do |other_object|
|
21
|
+
if other_object.is_a? Asteroids::Asteroid and
|
22
|
+
Utils.collide(object, other_object)
|
23
|
+
object.ship.add_score(calculate_points(other_object))
|
24
|
+
return true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
return false
|
28
|
+
end
|
29
|
+
|
30
|
+
def calculate_points(asteroid)
|
31
|
+
case asteroid.radius
|
32
|
+
when 45
|
33
|
+
20
|
34
|
+
when 30
|
35
|
+
50
|
36
|
+
when 17.5
|
37
|
+
100
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Asteroids
|
2
|
+
class Ship < GameObject
|
3
|
+
|
4
|
+
SHOOT_DELAY = 600
|
5
|
+
|
6
|
+
attr_accessor :x, :y, :vel_x, :vel_y, :angle, :thrust, :radius,
|
7
|
+
:score, :lives
|
8
|
+
|
9
|
+
def initialize(object_pool)
|
10
|
+
super(object_pool)
|
11
|
+
@physics = ShipPhysics.new(self, object_pool)
|
12
|
+
@graphics = ShipGraphics.new(self)
|
13
|
+
@vel_x = @vel_y = @angle = 0.0
|
14
|
+
@radius = 35
|
15
|
+
@lives = 3
|
16
|
+
@score = 0
|
17
|
+
@object_pool = object_pool
|
18
|
+
end
|
19
|
+
|
20
|
+
def shoot
|
21
|
+
if can_shoot?
|
22
|
+
@last_shot = Gosu.milliseconds
|
23
|
+
Missile.new(self, object_pool, @x, @y, @vel_x, @vel_y, @angle)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def can_shoot?
|
28
|
+
Gosu.milliseconds - (@last_shot || 0) > SHOOT_DELAY
|
29
|
+
end
|
30
|
+
|
31
|
+
def explode
|
32
|
+
Explosion.new(object_pool, @x, @y)
|
33
|
+
@lives -= 1
|
34
|
+
spawn
|
35
|
+
end
|
36
|
+
|
37
|
+
def is_alive?
|
38
|
+
return true if @lives != 0 or @lives > 0
|
39
|
+
end
|
40
|
+
|
41
|
+
def spawn
|
42
|
+
@x = object_pool.find_empty_space[:x]
|
43
|
+
@y = object_pool.find_empty_space[:y]
|
44
|
+
end
|
45
|
+
|
46
|
+
def add_score(points)
|
47
|
+
@score += points
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Asteroids
|
2
|
+
class ShipGraphics < Component
|
3
|
+
|
4
|
+
def initialize(game_object)
|
5
|
+
super(game_object)
|
6
|
+
@image = Gosu::Image.load_tiles($window,
|
7
|
+
Utils.get_image_path("ship.png"), 90, 90, true)
|
8
|
+
end
|
9
|
+
|
10
|
+
def draw
|
11
|
+
if object.thrust
|
12
|
+
@image[0].draw_rot(object.x, object.y, 1, object.angle)
|
13
|
+
else
|
14
|
+
@image[1].draw_rot(object.x, object.y, 1, object.angle)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Asteroids
|
2
|
+
class ShipPhysics < Component
|
3
|
+
|
4
|
+
def initialize(game_object, object_pool)
|
5
|
+
super(game_object)
|
6
|
+
@object_pool = object_pool
|
7
|
+
object.spawn
|
8
|
+
end
|
9
|
+
|
10
|
+
def update
|
11
|
+
object.explode if detect_collision?
|
12
|
+
if $window.button_down? Gosu::KbUp
|
13
|
+
accelerate
|
14
|
+
object.thrust = true
|
15
|
+
else
|
16
|
+
object.thrust = false
|
17
|
+
end
|
18
|
+
if $window.button_down? Gosu::KbLeft
|
19
|
+
object.angle -= 4.5
|
20
|
+
end
|
21
|
+
if $window.button_down? Gosu::KbRight
|
22
|
+
object.angle += 4.5
|
23
|
+
end
|
24
|
+
if $window.button_down? Gosu::Button::KbSpace
|
25
|
+
object.shoot
|
26
|
+
end
|
27
|
+
@object.mark_for_removal unless object.is_alive?
|
28
|
+
move
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def detect_collision?
|
34
|
+
@object_pool.objects.each do |other_object|
|
35
|
+
if other_object.is_a? Asteroids::Asteroid and
|
36
|
+
Utils.collide(object, other_object)
|
37
|
+
return true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
return false
|
41
|
+
end
|
42
|
+
|
43
|
+
def accelerate
|
44
|
+
object.vel_x += Gosu::offset_x(object.angle, 0.5)
|
45
|
+
object.vel_y += Gosu::offset_y(object.angle, 0.5)
|
46
|
+
end
|
47
|
+
|
48
|
+
def move
|
49
|
+
object.x += object.vel_x
|
50
|
+
object.y += object.vel_y
|
51
|
+
object.x %= 800
|
52
|
+
object.y %= 600
|
53
|
+
object.vel_x *= 0.95
|
54
|
+
object.vel_y *= 0.95
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Asteroids
|
2
|
+
class GameState
|
3
|
+
|
4
|
+
def self.switch(new_state)
|
5
|
+
$window.state && $window.state.leave
|
6
|
+
$window.state = new_state
|
7
|
+
new_state.enter
|
8
|
+
end
|
9
|
+
|
10
|
+
def enter
|
11
|
+
end
|
12
|
+
|
13
|
+
def leave
|
14
|
+
end
|
15
|
+
|
16
|
+
def draw
|
17
|
+
end
|
18
|
+
|
19
|
+
def update
|
20
|
+
end
|
21
|
+
|
22
|
+
def needs_redraw?
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
def button_down(id)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module Asteroids
|
4
|
+
class MenuState < GameState
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@title = Gosu::Image.from_text($window, "Asteroids",
|
9
|
+
Utils.get_font_path('victor-pixel.ttf'), 100)
|
10
|
+
@background = Gosu::Image.new($window,
|
11
|
+
Utils.get_image_path('background.png'), false)
|
12
|
+
@menu = Menu.new
|
13
|
+
@menu.add_item("New Game", lambda { GameState.switch(PlayState.new) },
|
14
|
+
true)
|
15
|
+
@menu.add_item("Load Game", lambda { puts 'load game' }, false)
|
16
|
+
@menu.add_item("Exit", lambda { $window.close }, false)
|
17
|
+
end
|
18
|
+
|
19
|
+
def draw
|
20
|
+
@background.draw(0, 0, 0)
|
21
|
+
@title.draw(
|
22
|
+
$window.width / 2 - @title.width / 2,
|
23
|
+
$window.height / 5 - @title.height / 5,
|
24
|
+
10)
|
25
|
+
@menu.draw
|
26
|
+
end
|
27
|
+
|
28
|
+
def button_down(id)
|
29
|
+
if id == Gosu::KbDown
|
30
|
+
@menu.select_item(:+)
|
31
|
+
end
|
32
|
+
if id == Gosu::KbUp
|
33
|
+
@menu.select_item(:-)
|
34
|
+
end
|
35
|
+
if id == Gosu::KbReturn
|
36
|
+
@menu.confirm
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Asteroids
|
2
|
+
class PlayState < GameState
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@background = Gosu::Image.new($window,
|
6
|
+
Utils.get_image_path('background.png'), false)
|
7
|
+
@live_image = Gosu::Image.new($window,
|
8
|
+
Utils.get_image_path('ship_small.png'), false)
|
9
|
+
@object_pool = ObjectPool.new
|
10
|
+
@ship = Ship.new(@object_pool)
|
11
|
+
Utils.create_asteroids(@object_pool, 4)
|
12
|
+
@font = Gosu::Font.new($window,
|
13
|
+
Utils.get_font_path('victor-pixel.ttf'),
|
14
|
+
34)
|
15
|
+
@level = 1
|
16
|
+
@level_compleate = false
|
17
|
+
end
|
18
|
+
|
19
|
+
def draw
|
20
|
+
@background.draw(0, 0, 0)
|
21
|
+
@object_pool.objects.map(&:draw)
|
22
|
+
if !@ship.is_alive?
|
23
|
+
@font.draw("Game Over", 210, 250, 50, 2.0, 2.0, 0xffffff00)
|
24
|
+
else
|
25
|
+
@font.draw("Score: ", 580, 10, 50, 1.0, 1.0, 0xffffff00)
|
26
|
+
@font.draw(@ship.score, 700, 10, 50, 1.0, 1.0, 0xffffff00)
|
27
|
+
@font.draw("Lives: ", 10, 10, 50, 1.0, 1.0, 0xffffff00)
|
28
|
+
@ship.lives.times do |n|
|
29
|
+
@live_image.draw(110 + n * 50, 10, 50)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def update
|
35
|
+
check_level_compleate
|
36
|
+
if @level_compleate == true
|
37
|
+
Utils.create_asteroids(@object_pool, 4 + @level)
|
38
|
+
@level += 1
|
39
|
+
@level_compleate = false
|
40
|
+
end
|
41
|
+
@object_pool.update_all
|
42
|
+
end
|
43
|
+
|
44
|
+
def check_level_compleate
|
45
|
+
@level_compleate = !@object_pool.objects.any? { |object| object.is_a? Asteroids::Asteroid }
|
46
|
+
end
|
47
|
+
|
48
|
+
def button_down(id)
|
49
|
+
if id == Gosu::KbEscape
|
50
|
+
Asteroids::GameState.switch(Asteroids::MenuState.instance)
|
51
|
+
end
|
52
|
+
if id == Gosu::KbS
|
53
|
+
serialized_object = ::YAML::dump(@object_pool)
|
54
|
+
File.open(Utils.saves_path + '/save.yaml', 'w+') do |file|
|
55
|
+
file.write(serialized_object)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Asteroids
|
2
|
+
class Utils
|
3
|
+
|
4
|
+
def self.assets_path
|
5
|
+
File.expand_path("../../../../assets/", __FILE__)
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.saves_path
|
9
|
+
File.expand_path("../../../../saves/", __FILE__)
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
def self.get_image_path(image_name)
|
14
|
+
"#{assets_path}/images/#{image_name}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.get_font_path(font_name)
|
18
|
+
"#{assets_path}/fonts/#{font_name}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.collide(object_a, object_b)
|
22
|
+
if Gosu::distance(object_a.x, object_a.y, object_b.x, object_b.y) <
|
23
|
+
object_a.radius + object_b.radius
|
24
|
+
return true
|
25
|
+
end
|
26
|
+
false
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.create_asteroids(object_pool, amount)
|
30
|
+
amount.times do |n|
|
31
|
+
Asteroid.new(object_pool, rand(800), rand(600),
|
32
|
+
rand() * 0.6 - 0.3, rand() * 0.6 - 0.3, 0)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
data/saves/save.yaml
ADDED
File without changes
|
metadata
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: asteroids
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Svetoslav Kuzmanov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-02-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: gosu
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: |2
|
56
|
+
This game is build with Gosu library as a final project for the
|
57
|
+
"Programming with Ruby" course.
|
58
|
+
email:
|
59
|
+
- svetoslav.kuzmanov@gmail.com
|
60
|
+
executables:
|
61
|
+
- asteroids
|
62
|
+
extensions: []
|
63
|
+
extra_rdoc_files: []
|
64
|
+
files:
|
65
|
+
- ".gitignore"
|
66
|
+
- Gemfile
|
67
|
+
- LICENSE.txt
|
68
|
+
- README.md
|
69
|
+
- Rakefile
|
70
|
+
- assets/fonts/victor-pixel.ttf
|
71
|
+
- assets/images/asteroid.png
|
72
|
+
- assets/images/asteroid_medium.png
|
73
|
+
- assets/images/asteroid_small.png
|
74
|
+
- assets/images/background.png
|
75
|
+
- assets/images/explosion.png
|
76
|
+
- assets/images/ship.png
|
77
|
+
- assets/images/ship_small.png
|
78
|
+
- assets/images/simple_missile.png
|
79
|
+
- asteroids.gemspec
|
80
|
+
- bin/asteroids
|
81
|
+
- lib/asteroids.rb
|
82
|
+
- lib/asteroids/asteroid/asteroid.rb
|
83
|
+
- lib/asteroids/asteroid/asteroid_graphics.rb
|
84
|
+
- lib/asteroids/asteroid/asteroid_physics.rb
|
85
|
+
- lib/asteroids/componenets/component.rb
|
86
|
+
- lib/asteroids/componenets/game_object.rb
|
87
|
+
- lib/asteroids/componenets/game_pool.rb
|
88
|
+
- lib/asteroids/explosion/explosion.rb
|
89
|
+
- lib/asteroids/explosion/explosion_graphics.rb
|
90
|
+
- lib/asteroids/menu/menu.rb
|
91
|
+
- lib/asteroids/menu/menu_item.rb
|
92
|
+
- lib/asteroids/missile/missile.rb
|
93
|
+
- lib/asteroids/missile/missile_graphics.rb
|
94
|
+
- lib/asteroids/missile/missile_physics.rb
|
95
|
+
- lib/asteroids/ship/ship.rb
|
96
|
+
- lib/asteroids/ship/ship_graphics.rb
|
97
|
+
- lib/asteroids/ship/ship_physics.rb
|
98
|
+
- lib/asteroids/states/game_state.rb
|
99
|
+
- lib/asteroids/states/menu_state.rb
|
100
|
+
- lib/asteroids/states/play_state.rb
|
101
|
+
- lib/asteroids/utils/utils.rb
|
102
|
+
- lib/asteroids/version.rb
|
103
|
+
- saves/save.yaml
|
104
|
+
homepage: ''
|
105
|
+
licenses:
|
106
|
+
- MIT
|
107
|
+
metadata: {}
|
108
|
+
post_install_message:
|
109
|
+
rdoc_options: []
|
110
|
+
require_paths:
|
111
|
+
- lib
|
112
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - ">="
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
requirements: []
|
123
|
+
rubyforge_project:
|
124
|
+
rubygems_version: 2.2.2
|
125
|
+
signing_key:
|
126
|
+
specification_version: 4
|
127
|
+
summary: This is my take on the classic arcade space shooter Asteroids by Atari
|
128
|
+
test_files: []
|