pacmanx 1.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.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +5 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +19 -0
  5. data/Rakefile +2 -0
  6. data/bin/pacmanx +7 -0
  7. data/bin/pacman~ +7 -0
  8. data/lib/pacman/animated_object.rb +10 -0
  9. data/lib/pacman/cage.rb +14 -0
  10. data/lib/pacman/controller.rb +127 -0
  11. data/lib/pacman/ghost.rb +41 -0
  12. data/lib/pacman/ghosts_controller.rb +253 -0
  13. data/lib/pacman/ghosts_renderer.rb +70 -0
  14. data/lib/pacman/level.rb +62 -0
  15. data/lib/pacman/level_builder.rb +129 -0
  16. data/lib/pacman/level_renderer.rb +100 -0
  17. data/lib/pacman/levels/level1.lvl +98 -0
  18. data/lib/pacman/media/bg2_2.jpg +0 -0
  19. data/lib/pacman/media/blinky_down.png +0 -0
  20. data/lib/pacman/media/blinky_left.png +0 -0
  21. data/lib/pacman/media/blinky_right.png +0 -0
  22. data/lib/pacman/media/blinky_up.png +0 -0
  23. data/lib/pacman/media/clyde_down.png +0 -0
  24. data/lib/pacman/media/clyde_left.png +0 -0
  25. data/lib/pacman/media/clyde_right.png +0 -0
  26. data/lib/pacman/media/clyde_up.png +0 -0
  27. data/lib/pacman/media/inky_down.png +0 -0
  28. data/lib/pacman/media/inky_left.png +0 -0
  29. data/lib/pacman/media/inky_right.png +0 -0
  30. data/lib/pacman/media/inky_up.png +0 -0
  31. data/lib/pacman/media/pacman_down.png +0 -0
  32. data/lib/pacman/media/pacman_left.png +0 -0
  33. data/lib/pacman/media/pacman_right.png +0 -0
  34. data/lib/pacman/media/pacman_up.png +0 -0
  35. data/lib/pacman/media/pellet.png +0 -0
  36. data/lib/pacman/media/pinky_down.png +0 -0
  37. data/lib/pacman/media/pinky_left.png +0 -0
  38. data/lib/pacman/media/pinky_right.png +0 -0
  39. data/lib/pacman/media/pinky_up.png +0 -0
  40. data/lib/pacman/media/power_pellet.png +0 -0
  41. data/lib/pacman/media/wall.png +0 -0
  42. data/lib/pacman/pacman.rb +4 -0
  43. data/lib/pacman/pellet.rb +16 -0
  44. data/lib/pacman/player.rb +12 -0
  45. data/lib/pacman/version.rb +4 -0
  46. data/lib/pacman/wall.rb +8 -0
  47. data/pacman_classes.png +0 -0
  48. data/pacmanx.gemspec +24 -0
  49. data/spec/level_builder_spec.rb +111 -0
  50. data/spec/level_spec.rb +69 -0
  51. data/spec/spec_helper.rb +7 -0
  52. metadata +141 -0
@@ -0,0 +1,70 @@
1
+ module Pacman
2
+ # ghosts viewer
3
+ class GhostsRenderer
4
+ def initialize(window, rel_path = '')
5
+ @blinky = { left: Gosu::Image.load_tiles(window, rel_path + 'media/blinky_left.png',
6
+ 50, 50, false),
7
+ right: Gosu::Image.load_tiles(window, rel_path + 'media/blinky_right.png',
8
+ 50, 50, false),
9
+ up: Gosu::Image.load_tiles(window, rel_path + 'media/blinky_up.png',
10
+ 50, 50, false),
11
+ down: Gosu::Image.load_tiles(window, rel_path + 'media/blinky_down.png',
12
+ 50, 50, false)
13
+ }
14
+
15
+ @pinky = { left: Gosu::Image.load_tiles(window, rel_path + 'media/pinky_left.png',
16
+ 50, 50, false),
17
+ right: Gosu::Image.load_tiles(window, rel_path + 'media/pinky_right.png',
18
+ 50, 50, false),
19
+ up: Gosu::Image.load_tiles(window, rel_path + 'media/pinky_up.png',
20
+ 50, 50, false),
21
+ down: Gosu::Image.load_tiles(window, rel_path + 'media/pinky_down.png',
22
+ 50, 50, false)
23
+ }
24
+
25
+ @inky = { left: Gosu::Image.load_tiles(window, rel_path + 'media/inky_left.png',
26
+ 50, 50, false),
27
+ right: Gosu::Image.load_tiles(window, rel_path + 'media/inky_right.png',
28
+ 50, 50, false),
29
+ up: Gosu::Image.load_tiles(window, rel_path + 'media/inky_up.png',
30
+ 50, 50, false),
31
+ down: Gosu::Image.load_tiles(window, rel_path + 'media/inky_down.png',
32
+ 50, 50, false)
33
+ }
34
+
35
+ @clyde = { left: Gosu::Image.load_tiles(window, rel_path + 'media/clyde_left.png',
36
+ 50, 50, false),
37
+ right: Gosu::Image.load_tiles(window, rel_path + 'media/clyde_right.png',
38
+ 50, 50, false),
39
+ up: Gosu::Image.load_tiles(window, rel_path + 'media/clyde_up.png',
40
+ 50, 50, false),
41
+ down: Gosu::Image.load_tiles(window, rel_path + 'media/clyde_down.png',
42
+ 50, 50, false)
43
+ }
44
+ end
45
+
46
+ def render(level, _state, next_frame)
47
+ if next_frame
48
+ ghosts = level.ghosts
49
+ [ghosts[:blinky], ghosts[:pinky], ghosts[:inky], ghosts[:clyde]].each do |ghost|
50
+ ghost.animation_index = (ghost.animation_index + 1) % @blinky[:left].size
51
+ end
52
+ end
53
+
54
+ # render ghosts
55
+ render_ghost(level.ghosts[:blinky], @blinky)
56
+ render_ghost(level.ghosts[:pinky], @pinky)
57
+ render_ghost(level.ghosts[:inky], @inky)
58
+ render_ghost(level.ghosts[:clyde], @clyde)
59
+ end
60
+
61
+ private
62
+
63
+ def render_ghost(ghost_model, ghost_graphics)
64
+ x = LevelRenderer.x_min + ghost_model.x * LevelRenderer.field_size
65
+ y = LevelRenderer.y_min + ghost_model.y * LevelRenderer.field_size
66
+ ghost_graphics[ghost_model.direction][ghost_model.animation_index]
67
+ .draw(x, y, 1)
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,62 @@
1
+ module Pacman
2
+ # main model class
3
+ class Level
4
+ def initialize
5
+ resize(0, 0)
6
+ @player = nil
7
+ @pellet_count = 0
8
+ @pellets_left = 0
9
+ @ghosts = {}
10
+ @ghosts_frozen = 0
11
+ end
12
+
13
+ def resize(width, height)
14
+ @width = width
15
+ @height = height
16
+
17
+ # resize array
18
+ @rows = []
19
+
20
+ 0.upto(height - 1) do
21
+ row = []
22
+ 0.upto(width - 1) do
23
+ row << nil
24
+ end
25
+ @rows << row
26
+ end
27
+ end
28
+
29
+ def [](key)
30
+ @rows[key]
31
+ end
32
+
33
+ def []=(key, value)
34
+ @rows[key] = value
35
+ end
36
+
37
+ def get(x, y)
38
+ @rows[y][x]
39
+ end
40
+
41
+ def each
42
+ return @rows.each unless block_given?
43
+ @rows.each do |row|
44
+ yield row
45
+ end
46
+ end
47
+
48
+ def register_player(_player)
49
+ end
50
+
51
+ def each_with_position
52
+ @rows.each_with_index do |row, y|
53
+ row.each_with_index do |col, x|
54
+ yield x, y, col
55
+ end
56
+ end
57
+ end
58
+
59
+ attr_accessor :width, :height, :player, :pellet_count, :pellets_left,
60
+ :cage_obj, :ghosts, :ghosts_frozen
61
+ end
62
+ end
@@ -0,0 +1,129 @@
1
+
2
+ require_relative 'level'
3
+ require_relative 'animated_object'
4
+ require_relative 'player'
5
+ require_relative 'wall'
6
+ require_relative 'pellet'
7
+ require_relative 'cage'
8
+ require_relative 'ghost'
9
+
10
+ module Pacman
11
+ # DSL builder
12
+ class LevelBuilder
13
+ class << self
14
+ def build(dsl)
15
+ builder = new(dsl)
16
+ builder.level
17
+ end
18
+
19
+ private :new
20
+ end
21
+
22
+ # builds a level according to the DSL
23
+ def initialize(dsl)
24
+ @level = Level.new
25
+ @x = 0
26
+ @y = 0
27
+
28
+ # exec DSL
29
+ instance_eval(dsl)
30
+
31
+ # place ghosts to the cage
32
+ if @level.cage_obj
33
+ cage_obj = @level.cage_obj
34
+ @level.ghosts = { blinky: BlinkyGhost.new(cage_obj.x, cage_obj.y, :left),
35
+ pinky: PinkyGhost.new(cage_obj.x + 1, cage_obj.y,
36
+ :left),
37
+ inky: InkyGhost.new(cage_obj.x + 2, cage_obj.y, :right),
38
+ clyde: ClydeGhost.new(cage_obj.x + 3, cage_obj.y,
39
+ :right) }
40
+ end
41
+
42
+ @level.pellets_left = @level.pellet_count
43
+
44
+ @level
45
+ end
46
+
47
+ def resize(width, height)
48
+ @level.resize(width, height)
49
+ end
50
+
51
+ def check_bounds(x, y)
52
+ fail OutOfBoundsError.new if x < 0 || y < 0 || @level.width < x ||
53
+ @level.height < y
54
+ end
55
+
56
+ # skip n columns if possible, otherwise skip row
57
+ def skip(n)
58
+ x = (@x + n) % @level.width
59
+ y = (@y * @level.width + @x + n) / @level.width
60
+ fail OutOfBoundsError.new if y >= @level.height || x >= @level.width
61
+
62
+ @y = y
63
+ @x = x
64
+ end
65
+
66
+ # go to specified position
67
+ def goto(x, y)
68
+ fail OutOfBoundsError.new if y < 0 || x < 0 || y >= @level.height ||
69
+ x >= @level.width
70
+ @x, @y = x, y
71
+ end
72
+
73
+ def place_object(clazz)
74
+ check_bounds(@x, @y)
75
+ @level[@y][@x] = clazz.new
76
+ begin
77
+ skip(1)
78
+ rescue
79
+ raise OutOfBoundsError.new unless @x == @level.width - 1 &&
80
+ @y == @level.height - 1
81
+ end
82
+ end
83
+
84
+ def wall
85
+ place_object(Wall)
86
+ end
87
+
88
+ def pellet
89
+ place_object(Pellet)
90
+ @level.pellet_count += 1
91
+ end
92
+
93
+ def power_pellet
94
+ place_object(PowerPellet)
95
+ end
96
+
97
+ # set player position
98
+ def player(direction)
99
+ check_bounds(@x, @y)
100
+ player = Player.new(direction, @x, @y)
101
+ level.player = player
102
+ begin
103
+ skip(1)
104
+ rescue
105
+ raise OutOfBoundsError.new unless @x == @level.width - 1 &&
106
+ @y == @level.height - 1
107
+ end
108
+ end
109
+
110
+ def cage
111
+ check_bounds(@x, @y)
112
+ cage_obj = Cage.new(@x, @y)
113
+ @level[@y][@x] = cage_obj
114
+ begin
115
+ skip(1)
116
+ rescue
117
+ raise OutOfBoundsError.new unless @x == @level.width - 1 &&
118
+ @y == @level.height - 1
119
+ end
120
+
121
+ @level.cage_obj = cage_obj
122
+ end
123
+
124
+ attr_reader :level
125
+ end
126
+
127
+ class OutOfBoundsError < StandardError
128
+ end
129
+ end
@@ -0,0 +1,100 @@
1
+ module Pacman
2
+ # main renderer class
3
+ class LevelRenderer
4
+ class << self
5
+ def field_size
6
+ 50
7
+ end
8
+
9
+ def x_min
10
+ 50
11
+ end
12
+
13
+ def y_min
14
+ 50
15
+ end
16
+ end
17
+
18
+ def initialize(window, rel_path = '')
19
+ @ghosts_renderer = GhostsRenderer.new(window, rel_path)
20
+
21
+ # initialize graphics
22
+ @font = Gosu::Font.new(window, 'Arial', 18)
23
+
24
+ @field_size = 50
25
+ @background = Gosu::Image.new(window, rel_path + 'media/bg2_2.jpg', false)
26
+ @wall = Gosu::Image.new(window, rel_path + 'media/wall.png')
27
+ @pellet = Gosu::Image.new(window, rel_path + 'media/pellet.png')
28
+ @power_pellet = Gosu::Image.new(window, rel_path + 'media/power_pellet.png')
29
+
30
+ @player_left = Gosu::Image.load_tiles(window, rel_path + 'media/pacman_left.png',
31
+ 50, 50, false)
32
+ @player_right = Gosu::Image.load_tiles(window, rel_path + 'media/pacman_right.png',
33
+ 50, 50, false)
34
+ @player_up = Gosu::Image.load_tiles(window, rel_path + 'media/pacman_up.png',
35
+ 50, 50, false)
36
+ @player_down = Gosu::Image.load_tiles(window, rel_path + 'media/pacman_down.png',
37
+ 50, 50, false)
38
+
39
+ @timer = 0
40
+ end
41
+
42
+ def render(level, state)
43
+ @timer += 1
44
+
45
+ next_frame = @timer % 5 == 0
46
+ if next_frame
47
+ level.player.animation_index = (level.player.animation_index + 1) %
48
+ @player_down.size
49
+ end
50
+
51
+ @background.draw(0, 0, 0)
52
+
53
+ render_objects(level, state)
54
+
55
+ # draw player
56
+ x_pos = LevelRenderer.x_min + level.player.x * LevelRenderer.field_size
57
+ y_pos = LevelRenderer.y_min + level.player.y * LevelRenderer.field_size
58
+
59
+ @ghosts_renderer.render(level, state, next_frame)
60
+
61
+ case level.player.direction
62
+ when :left
63
+ @player_left[level.player.animation_index].draw(x_pos, y_pos, 1)
64
+ when :right
65
+ @player_right[level.player.animation_index].draw(x_pos, y_pos, 1)
66
+ when :up
67
+ @player_up[level.player.animation_index].draw(x_pos, y_pos, 1)
68
+ when :down
69
+ @player_down[level.player.animation_index].draw(x_pos, y_pos, 1)
70
+ end
71
+
72
+ return unless (state == :win)
73
+
74
+ @font.draw('END', 100, 100, 1.0, 4.0, 4.0)
75
+ score = level.pellet_count - level.pellets_left
76
+ @font.draw("Score: #{score} / #{level.pellet_count}",
77
+ 100, 150, 1.0, 1.5, 1.5)
78
+ end
79
+
80
+ private
81
+
82
+ def render_objects(level, _state)
83
+ level.each_with_position do |x, y, obj|
84
+ x_pos = LevelRenderer.x_min + x * LevelRenderer.field_size
85
+ y_pos = LevelRenderer.y_min + y * LevelRenderer.field_size
86
+
87
+ case
88
+ when obj.class == Wall
89
+ @wall.draw(x_pos, y_pos, 1)
90
+ when obj.class == Pellet
91
+ @pellet.draw(x_pos, y_pos, 1)
92
+ when obj.class == PowerPellet
93
+ @power_pellet.draw(x_pos, y_pos, 1)
94
+ end
95
+ end
96
+
97
+ return if level.ghosts.empty?
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,98 @@
1
+ resize 20, 11
2
+
3
+ 21.times{ wall }
4
+ power_pellet
5
+ 3.times{ pellet }
6
+ wall
7
+ 8.times{ pellet }
8
+ wall
9
+ 3.times { pellet }
10
+ power_pellet
11
+ 2.times{ wall }
12
+
13
+ pellet
14
+ 2.times{ wall }
15
+ pellet
16
+ wall
17
+ pellet
18
+ 6.times{ wall }
19
+ pellet
20
+ wall
21
+ pellet
22
+ 2.times{ wall }
23
+ pellet
24
+ 2.times{ wall }
25
+
26
+ pellet
27
+ wall
28
+ 14.times{ pellet }
29
+ wall
30
+ pellet
31
+ 2.times{ wall }
32
+
33
+ pellet
34
+ wall
35
+ pellet
36
+ 2.times{wall}
37
+ pellet
38
+ # skip 6
39
+ 6.times{ wall }
40
+ pellet
41
+ 2.times{ wall }
42
+ pellet
43
+ wall
44
+ pellet
45
+ 2.times{ wall }
46
+
47
+ 6.times{ pellet }
48
+ # skip 6
49
+ skip 1
50
+ cage
51
+ skip 4
52
+ 6.times{ pellet }
53
+ 2.times{ wall }
54
+
55
+ pellet
56
+ wall
57
+ pellet
58
+ 2.times{ wall }
59
+ pellet
60
+ 6.times{ wall }
61
+ pellet
62
+ 2.times{ wall }
63
+ pellet
64
+ wall
65
+ pellet
66
+ 2.times{ wall }
67
+
68
+ pellet
69
+ wall
70
+ 14.times{ pellet }
71
+ wall
72
+ pellet
73
+ 2.times{ wall }
74
+
75
+ pellet
76
+ 2.times{ wall }
77
+ pellet
78
+ wall
79
+ pellet
80
+ 6.times{ wall }
81
+ pellet
82
+ wall
83
+ pellet
84
+ 2.times{ wall }
85
+ pellet
86
+ 2.times{ wall }
87
+
88
+ power_pellet
89
+ 3.times{ pellet }
90
+ wall
91
+ player :right
92
+ 7.times{ pellet }
93
+ wall
94
+ 3.times{ pellet }
95
+ power_pellet
96
+ wall
97
+
98
+ 20.times{ wall }