asteroids 0.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.
- 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: []
|