pacmanx 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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 }