RubyMan 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 +15 -0
- data/Gemfile +6 -0
- data/Rakefile +2 -0
- data/RubyMan.gemspec +24 -0
- data/bin/rubyman +4 -0
- data/lib/ruby_man.rb +5 -0
- data/lib/ruby_man/GameObjects/door.rb +11 -0
- data/lib/ruby_man/GameObjects/food.rb +24 -0
- data/lib/ruby_man/GameObjects/game_object.rb +29 -0
- data/lib/ruby_man/GameObjects/game_over.rb +44 -0
- data/lib/ruby_man/GameObjects/ghost.rb +123 -0
- data/lib/ruby_man/GameObjects/ghost_corpse.rb +30 -0
- data/lib/ruby_man/GameObjects/grid_object.rb +69 -0
- data/lib/ruby_man/GameObjects/hud.rb +26 -0
- data/lib/ruby_man/GameObjects/menu.rb +82 -0
- data/lib/ruby_man/GameObjects/moving_object.rb +50 -0
- data/lib/ruby_man/GameObjects/player.rb +90 -0
- data/lib/ruby_man/GameObjects/super_food.rb +16 -0
- data/lib/ruby_man/GameObjects/wall.rb +24 -0
- data/lib/ruby_man/aabb.rb +17 -0
- data/lib/ruby_man/direction.rb +102 -0
- data/lib/ruby_man/game_main.rb +213 -0
- data/lib/ruby_man/level_loader.rb +49 -0
- data/lib/ruby_man/resource_manager.rb +103 -0
- data/lib/ruby_man/sprite.rb +26 -0
- data/lib/ruby_man/version.rb +4 -0
- data/media/door_strip2.png +0 -0
- data/media/gem_strip9.png +0 -0
- data/media/ghost_death_strip15.png +0 -0
- data/media/ghost_down_strip2.png +0 -0
- data/media/ghost_left_strip2.png +0 -0
- data/media/ghost_right_strip2.png +0 -0
- data/media/ghost_scared_strip2.png +0 -0
- data/media/ghost_stopscared_strip3.png +0 -0
- data/media/ghost_up_strip2.png +0 -0
- data/media/levellist.txt +4 -0
- data/media/levels/level_1.txt +19 -0
- data/media/levels/level_2.txt +19 -0
- data/media/levels/level_3.txt +19 -0
- data/media/levels/level_4.txt +19 -0
- data/media/levels/level_empty.txt +19 -0
- data/media/logo.png +0 -0
- data/media/resource.cfg +18 -0
- data/media/rubyman_strip11.png +0 -0
- data/media/sfx/pacman_beginning.wav +0 -0
- data/media/sfx/pacman_chomp.wav +0 -0
- data/media/sfx/pacman_death.wav +0 -0
- data/media/sfx/pacman_eatghost.wav +0 -0
- data/media/walls_strip16.png +0 -0
- data/test/aabb_spec.rb +41 -0
- data/test/direction_spec.rb +48 -0
- data/test/game_main_spec.rb +126 -0
- metadata +142 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a03426f79e26e9df419b99b564062de38e2a17d1
|
4
|
+
data.tar.gz: 6d5a6118f6fb3a5db10eaa7aac549b0217835f17
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 807f1d45014a8a63c1894424d93ffc4f41ba7832d3a404b4f58e4f6b55b0a311e76d24d81eb04e64b3aced57c0cfe6ea5644a11bfd654a03eb5e96ae93fe3416
|
7
|
+
data.tar.gz: 04711b7c9ebfa87dc67e1976e59e06dbb57a445b640d24a5367fd3cb89637c842b1f7abeef97bfc1566537589151f70c75194fcad1297bd36f04c849e7a3f905
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
data/RubyMan.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'ruby_man/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "RubyMan"
|
8
|
+
spec.version = RubyMan::VERSION
|
9
|
+
spec.authors = ["Bc. Marek Manukjan"]
|
10
|
+
spec.email = ["manukmar@fit.cvut.cz"]
|
11
|
+
spec.summary = %q{Ruby-themed PacMan}
|
12
|
+
spec.description = %q{Simple Ruby-themed implementation of PacMan}
|
13
|
+
spec.homepage = "https://gitlab.fit.cvut.cz/manukmar/rubyman"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
spec.add_runtime_dependency "gosu", "~> 0.8"
|
24
|
+
end
|
data/bin/rubyman
ADDED
data/lib/ruby_man.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'ruby_man/GameObjects/grid_object'
|
2
|
+
|
3
|
+
module RubyMan
|
4
|
+
# Food eatable by player
|
5
|
+
class Food < GridObject
|
6
|
+
def self.persistent
|
7
|
+
true
|
8
|
+
end
|
9
|
+
|
10
|
+
def created
|
11
|
+
super
|
12
|
+
self.sprite = Sprite['gem']
|
13
|
+
@scale = 0.5
|
14
|
+
@depth = 1
|
15
|
+
@game.food_created
|
16
|
+
end
|
17
|
+
|
18
|
+
def destroyed
|
19
|
+
super
|
20
|
+
ResourceManager['sfx_eat'].play
|
21
|
+
@game.food_destroyed
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module RubyMan
|
2
|
+
# Generic object attachable to game loop
|
3
|
+
class GameObject
|
4
|
+
attr_accessor :game
|
5
|
+
|
6
|
+
def self.persistent
|
7
|
+
false
|
8
|
+
end
|
9
|
+
|
10
|
+
def button_down(_key)
|
11
|
+
end
|
12
|
+
|
13
|
+
def draw
|
14
|
+
end
|
15
|
+
|
16
|
+
def update(_delta)
|
17
|
+
end
|
18
|
+
|
19
|
+
def destroy
|
20
|
+
@game.destroy_object(self)
|
21
|
+
end
|
22
|
+
|
23
|
+
def destroyed
|
24
|
+
end
|
25
|
+
|
26
|
+
def created
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'ruby_man/GameObjects/menu'
|
2
|
+
|
3
|
+
module RubyMan
|
4
|
+
# Helper object for inputting player name
|
5
|
+
class PlayerName < Gosu::TextInput
|
6
|
+
def filter(text_in)
|
7
|
+
return '' if text.size >= 10
|
8
|
+
text_in.gsub(/[^A-Za-z0-9]/, '')
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Game Over screen with enterable player name
|
13
|
+
class GameOver < GameObject
|
14
|
+
def created
|
15
|
+
super
|
16
|
+
@text = ResourceManager['text_normal']
|
17
|
+
@large_text = ResourceManager['text_large']
|
18
|
+
@name = ''
|
19
|
+
@input = PlayerName.new
|
20
|
+
@game.text_input = @input
|
21
|
+
end
|
22
|
+
|
23
|
+
def main_menu
|
24
|
+
@game.add_score(@input.text)
|
25
|
+
@game.text_input = nil
|
26
|
+
@game.main_menu
|
27
|
+
end
|
28
|
+
|
29
|
+
def draw
|
30
|
+
super
|
31
|
+
@large_text.draw_centered('Game over!', x_center, @game.y_res / 6, 0)
|
32
|
+
@text.draw_centered('Enter name:', x_center, @game.y_res / 2, 0)
|
33
|
+
@text.draw_centered(@input.text, x_center, @game.y_res / 2 + 32, 0)
|
34
|
+
end
|
35
|
+
|
36
|
+
def x_center
|
37
|
+
@game.x_res / 2
|
38
|
+
end
|
39
|
+
|
40
|
+
def button_down(id)
|
41
|
+
main_menu if id == Gosu::KbEnter || id == Gosu::KbReturn
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'ruby_man/GameObjects/moving_object'
|
2
|
+
require 'ruby_man/GameObjects/ghost_corpse'
|
3
|
+
|
4
|
+
module RubyMan
|
5
|
+
# Ghost that chases player
|
6
|
+
class Ghost < MovingObject
|
7
|
+
def created
|
8
|
+
self.sprite = Sprite['ghost_left']
|
9
|
+
@spawn_x, @spawn_y = @grid_x, @grid_y
|
10
|
+
stop_scared
|
11
|
+
end
|
12
|
+
|
13
|
+
def update(delta)
|
14
|
+
super
|
15
|
+
update_scared(delta) unless @dead
|
16
|
+
end
|
17
|
+
|
18
|
+
def grid_step
|
19
|
+
select_direction!
|
20
|
+
end
|
21
|
+
|
22
|
+
def possible_directions
|
23
|
+
directions = []
|
24
|
+
Direction.each do |dir|
|
25
|
+
next unless dir != @direction.opposite && direction_free(dir)
|
26
|
+
directions.push(dir)
|
27
|
+
end
|
28
|
+
directions
|
29
|
+
end
|
30
|
+
|
31
|
+
def scared_directions
|
32
|
+
to_pl = directions_to_player
|
33
|
+
possible = possible_directions
|
34
|
+
away = possible - to_pl
|
35
|
+
return possible if away.empty?
|
36
|
+
away
|
37
|
+
end
|
38
|
+
|
39
|
+
def chase_directions
|
40
|
+
directions = possible_directions
|
41
|
+
directions_to_player.each do |dir|
|
42
|
+
2.times { directions.push(dir) } if directions.include?(dir)
|
43
|
+
end
|
44
|
+
directions
|
45
|
+
end
|
46
|
+
|
47
|
+
def weighted_directions
|
48
|
+
directions = @scared ? scared_directions : chase_directions
|
49
|
+
directions.push(Direction.none) if directions.empty?
|
50
|
+
directions
|
51
|
+
end
|
52
|
+
|
53
|
+
def directions_to_player
|
54
|
+
return [] unless @game.player
|
55
|
+
rel_x = @game.player.grid_x - @grid_x
|
56
|
+
rel_y = @game.player.grid_y - @grid_y
|
57
|
+
directions = []
|
58
|
+
directions.push(Direction.right) if rel_x > 0
|
59
|
+
directions.push(Direction.left) if rel_x < 0
|
60
|
+
directions.push(Direction.down) if rel_y > 0
|
61
|
+
directions.push(Direction.up) if rel_y < 0
|
62
|
+
directions
|
63
|
+
end
|
64
|
+
|
65
|
+
def select_direction!
|
66
|
+
directions = weighted_directions
|
67
|
+
change_direction(directions[rand(directions.size)])
|
68
|
+
end
|
69
|
+
|
70
|
+
def change_direction(direction)
|
71
|
+
@direction = direction
|
72
|
+
return if @scared
|
73
|
+
case direction
|
74
|
+
when Direction.left then self.sprite = Sprite['ghost_left']
|
75
|
+
when Direction.right then self.sprite = Sprite['ghost_right']
|
76
|
+
when Direction.up then self.sprite = Sprite['ghost_up']
|
77
|
+
when Direction.down then self.sprite = Sprite['ghost_down']
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def set_pos(x, y)
|
82
|
+
super
|
83
|
+
select_direction! if @game
|
84
|
+
end
|
85
|
+
|
86
|
+
def scare
|
87
|
+
@scared = 7.0
|
88
|
+
@speed = 1.5
|
89
|
+
update_scared(0.0)
|
90
|
+
end
|
91
|
+
|
92
|
+
def scared?
|
93
|
+
@scared != nil
|
94
|
+
end
|
95
|
+
|
96
|
+
def update_scared(delta)
|
97
|
+
return unless @scared
|
98
|
+
@scared -= delta
|
99
|
+
return stop_scared if @scared <= 0.0
|
100
|
+
if @scared > 2.0
|
101
|
+
self.sprite = Sprite['ghost_scared']
|
102
|
+
else
|
103
|
+
self.sprite = Sprite['ghost_stop_scared']
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def stop_scared
|
108
|
+
@speed = 2.5
|
109
|
+
@scared = nil
|
110
|
+
# reset sprite according to current direction
|
111
|
+
change_direction(@direction)
|
112
|
+
end
|
113
|
+
|
114
|
+
def die
|
115
|
+
ResourceManager['sfx_eatghost'].play
|
116
|
+
@game.score += 500
|
117
|
+
@game.add_object(GhostCorpse.new(@grid_x, @grid_y,
|
118
|
+
@phase, @direction,
|
119
|
+
@spawn_x, @spawn_y))
|
120
|
+
destroy
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'ruby_man/GameObjects/moving_object'
|
2
|
+
|
3
|
+
module RubyMan
|
4
|
+
# simple object representing dying ghost with respawn functionality
|
5
|
+
class GhostCorpse < MovingObject
|
6
|
+
def initialize(x, y, phase, direction, res_x, res_y)
|
7
|
+
super()
|
8
|
+
@grid_x, @grid_y, = x, y
|
9
|
+
@phase, @direction = phase, direction
|
10
|
+
@res_x, @res_y = res_x, res_y
|
11
|
+
self.sprite = Sprite['ghost_death']
|
12
|
+
end
|
13
|
+
|
14
|
+
def update(delta)
|
15
|
+
next_index = @image_index + @image_speed * delta * @sprite.frames.size
|
16
|
+
if next_index < @sprite.frames.size
|
17
|
+
@image_index = next_index
|
18
|
+
else
|
19
|
+
respawn
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def respawn
|
24
|
+
ghost = Ghost.new
|
25
|
+
ghost.set_pos(@res_x, @res_y)
|
26
|
+
@game.add_object(ghost)
|
27
|
+
destroy
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'ruby_man/GameObjects/game_object'
|
2
|
+
require 'ruby_man/aabb'
|
3
|
+
|
4
|
+
module RubyMan
|
5
|
+
# GameObject aligned to game's grid
|
6
|
+
class GridObject < GameObject
|
7
|
+
attr_accessor :grid_x, :grid_y, :depth
|
8
|
+
attr_reader :sprite
|
9
|
+
attr_accessor :image_index, :image_speed, :image_angle
|
10
|
+
attr_accessor :solid
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
super
|
14
|
+
@grid_x = -1
|
15
|
+
@grid_y = -1
|
16
|
+
@depth = 0
|
17
|
+
@image_index = 0
|
18
|
+
@image_speed = 1
|
19
|
+
@image_angle = 0
|
20
|
+
@solid = false
|
21
|
+
@scale = 1.0
|
22
|
+
end
|
23
|
+
|
24
|
+
def update(delta)
|
25
|
+
super
|
26
|
+
return unless sprite
|
27
|
+
@image_index += @image_speed * delta * @sprite.frames.size
|
28
|
+
@image_index %= @sprite.frames.size
|
29
|
+
end
|
30
|
+
|
31
|
+
def draw
|
32
|
+
super
|
33
|
+
return unless sprite
|
34
|
+
sprite.draw(pixel_x, pixel_y, depth,
|
35
|
+
image_angle, image_index.to_i, @scale)
|
36
|
+
end
|
37
|
+
|
38
|
+
def sprite=(new_sprite)
|
39
|
+
return if @sprite == new_sprite
|
40
|
+
@image_index = 0
|
41
|
+
@sprite = new_sprite
|
42
|
+
end
|
43
|
+
|
44
|
+
def pixel_x
|
45
|
+
@grid_x * 32
|
46
|
+
end
|
47
|
+
|
48
|
+
def pixel_y
|
49
|
+
@grid_y * 32
|
50
|
+
end
|
51
|
+
|
52
|
+
def bbox
|
53
|
+
AABB.new(pixel_x, pixel_y,
|
54
|
+
pixel_x + @sprite.width, pixel_y + @sprite.height)
|
55
|
+
end
|
56
|
+
|
57
|
+
def distance_to(other)
|
58
|
+
rel_x = other.pixel_x - pixel_x
|
59
|
+
rel_y = other.pixel_y - pixel_y
|
60
|
+
Math.sqrt(rel_x.abs2 + rel_y.abs2)
|
61
|
+
end
|
62
|
+
|
63
|
+
def set_pos(x, y)
|
64
|
+
@grid_x = x
|
65
|
+
@grid_y = y
|
66
|
+
@phase = 0
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'ruby_man/GameObjects/game_object'
|
2
|
+
require 'ruby_man/resource_manager'
|
3
|
+
|
4
|
+
module RubyMan
|
5
|
+
# Game overlay showing number of lives and score
|
6
|
+
class Hud < GameObject
|
7
|
+
def initialize
|
8
|
+
super
|
9
|
+
@text = ResourceManager['text_normal']
|
10
|
+
@life_sprite = ResourceManager['rubyman']
|
11
|
+
end
|
12
|
+
|
13
|
+
def draw
|
14
|
+
y_offset = 608
|
15
|
+
@text.draw("Score: #{@game.score}", 8, y_offset + 2, 0)
|
16
|
+
x_offset = 160
|
17
|
+
lives_text = 'Lives: '
|
18
|
+
@text.draw(lives_text, x_offset, y_offset + 2, 0)
|
19
|
+
x_offset += @text.text_width(lives_text)
|
20
|
+
@game.lives.times do
|
21
|
+
@life_sprite.draw(x_offset + 2, y_offset)
|
22
|
+
x_offset += @life_sprite.width
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'ruby_man/resource_manager'
|
2
|
+
require 'ruby_man/GameObjects/moving_object'
|
3
|
+
|
4
|
+
module RubyMan
|
5
|
+
# RubyMan object for decorating main menu
|
6
|
+
class MenuRubyMan < MovingObject
|
7
|
+
def created
|
8
|
+
self.sprite = Sprite['rubyman']
|
9
|
+
set_pos(-4, 8)
|
10
|
+
change_direction(Direction.right)
|
11
|
+
@speed = 3
|
12
|
+
@image_speed = 3
|
13
|
+
end
|
14
|
+
|
15
|
+
def grid_step
|
16
|
+
if @direction == Direction.right
|
17
|
+
change_direction(Direction.left) if @grid_x >= 31
|
18
|
+
else
|
19
|
+
change_direction(Direction.right) if @grid_x <= -4
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Ghost object for decorating main menu
|
25
|
+
class MenuGhost < MovingObject
|
26
|
+
def created
|
27
|
+
set_pos(-6, 8)
|
28
|
+
@speed = 3
|
29
|
+
@image_speed = 3
|
30
|
+
set_chase
|
31
|
+
end
|
32
|
+
|
33
|
+
def set_chase
|
34
|
+
@direction = Direction.right
|
35
|
+
self.sprite = Sprite['ghost_right']
|
36
|
+
end
|
37
|
+
|
38
|
+
def set_run
|
39
|
+
@direction = Direction.left
|
40
|
+
self.sprite = Sprite['ghost_scared']
|
41
|
+
end
|
42
|
+
|
43
|
+
def grid_step
|
44
|
+
if @direction == Direction.right
|
45
|
+
set_run if @grid_x >= 29
|
46
|
+
else
|
47
|
+
set_chase if @grid_x <= -6
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# title screen showing high scores
|
53
|
+
class Menu < GameObject
|
54
|
+
def created
|
55
|
+
@logo = Sprite['logo']
|
56
|
+
@text = ResourceManager['text_normal']
|
57
|
+
@large_text = ResourceManager['text_large']
|
58
|
+
@game.add_object(MenuRubyMan.new)
|
59
|
+
@game.add_object(MenuGhost.new)
|
60
|
+
end
|
61
|
+
|
62
|
+
def button_down(id)
|
63
|
+
@game.start if id == Gosu::KbEnter || id == Gosu::KbReturn
|
64
|
+
end
|
65
|
+
|
66
|
+
def draw
|
67
|
+
@logo.draw_centered(@game.x_res / 2, 92)
|
68
|
+
@large_text.draw_centered('Press Enter to start!', @game.x_res / 2, 200)
|
69
|
+
draw_scores(@game.x_res / 2 - 192, @game.y_res / 2)
|
70
|
+
end
|
71
|
+
|
72
|
+
def draw_scores(x, y)
|
73
|
+
y_offset = 0
|
74
|
+
@game.scores.each do |entry|
|
75
|
+
@text.draw(entry[0], x, y + y_offset, 0)
|
76
|
+
@text.draw(entry[1], x + 128, y + y_offset, 0)
|
77
|
+
@text.draw(entry[2], x + 320, y + y_offset, 0)
|
78
|
+
y_offset += 32
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|