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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a38cf4a118a4ee9e1c27b8f19b603896aa5a6546
4
+ data.tar.gz: a7aa399345721a67320a4d9fa47f61f63c61e728
5
+ SHA512:
6
+ metadata.gz: 58b90c93229efe35f6963625e7a14f774577d0a7d762c2dceabe55a7276a71af476dcc03aed0cf40d17da74ea04b3ffa62161d97e7258a56784f74cd8f5bd5fd
7
+ data.tar.gz: bcf9890d7d891dda69133ae5bf7a1bff2e04bf4f233af179a21fc7cfef751bd06b71505156b8137a6a117aa76e423e48ecfe6caf915a9f982b16aea86790e827
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in pacman.gemspec
4
+ gem "gosu", ">= 0.8.6"
5
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 fajmanjir
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.
@@ -0,0 +1,19 @@
1
+ # Pacman
2
+
3
+ Classic Pacman game remake
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'pacman'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install pacman
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pacman/controller'
4
+ # require 'controller'
5
+
6
+ game = Pacman::Game.new("lib/pacman/")
7
+ game.show
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pacman/pacman'
4
+ # require 'controller'
5
+
6
+ # game = Pacman::Game.new
7
+ # game.show
@@ -0,0 +1,10 @@
1
+ module Pacman
2
+ # Objext using animation
3
+ class AnimatedObject
4
+ def initialize
5
+ @animation_index = 0
6
+ end
7
+
8
+ attr_accessor :animation_index
9
+ end
10
+ end
@@ -0,0 +1,14 @@
1
+ module Pacman
2
+ # base point for ghosts
3
+ class Cage
4
+ def initialize(x, y)
5
+ @x, @y = x, y
6
+ end
7
+
8
+ def passable?
9
+ true
10
+ end
11
+
12
+ attr_accessor :x, :y
13
+ end
14
+ end
@@ -0,0 +1,127 @@
1
+ require 'rubygems'
2
+ require 'gosu'
3
+ require_relative 'level_builder'
4
+ require_relative 'level_renderer'
5
+ require_relative 'ghosts_controller'
6
+ require_relative 'ghosts_renderer'
7
+
8
+ module Pacman
9
+ # controller
10
+ class Game < Gosu::Window
11
+ def initialize(rel_path = '')
12
+ super(1280, 800, false)
13
+ @last_milliseconds = 0
14
+
15
+ self.caption = 'PacMan'
16
+ @level = 1
17
+
18
+ @renderer = LevelRenderer.new(self, rel_path)
19
+
20
+ # affects pacman and creatures speed
21
+ @timer_default = 20
22
+ @rel_path = rel_path
23
+
24
+ load_level
25
+
26
+ @ghosts_controller = GhostsController.new(@level)
27
+
28
+ @state = :running
29
+ end
30
+
31
+ def load_level
32
+ file = File.open(@rel_path + "levels/level#{@level}.lvl", 'r')
33
+ dsl = file.read
34
+ file.close
35
+
36
+ @level = LevelBuilder.build(dsl)
37
+
38
+ @timer = @timer_default
39
+ end
40
+
41
+ # this is a callback for key up events or equivalent (there are
42
+ # constants for gamepad buttons and mouse clicks)
43
+ def button_up(key)
44
+ close if key == Gosu::KbEscape
45
+ end
46
+
47
+ def button_down(key)
48
+ case @state
49
+ when :running
50
+ @level.player.direction = :left if (key == Gosu::KbLeft)
51
+ @level.player.direction = :right if (key == Gosu::KbRight)
52
+ @level.player.direction = :up if (key == Gosu::KbUp)
53
+ @level.player.direction = :down if (key == Gosu::KbDown)
54
+ end
55
+ end
56
+
57
+ def draw
58
+ @renderer.render(@level, @state)
59
+ end
60
+
61
+ def update
62
+ update_delta
63
+ # with a delta we need to express the speed of our entities in
64
+ # terms of pixels/second
65
+
66
+ case @state
67
+ when :running
68
+ @timer -= 1
69
+
70
+ if (@timer % 10 == 0)
71
+ # update animation
72
+ @level.player.animation_index = (@level.player.animation_index + 1)
73
+ end
74
+
75
+ if (@timer == 0)
76
+ update_player
77
+ @ghosts_controller.update
78
+ @state = :win if @ghosts_controller.colission
79
+ @timer = @timer_default
80
+ end
81
+ end
82
+ end
83
+
84
+ def update_player
85
+ player = @level.player
86
+ case @level.player.direction
87
+ when :left
88
+ next_obj = @level.get(player.x - 1, player.y)
89
+ player.x -= 1 if player.x > 0 && (next_obj.nil? || next_obj.passable?)
90
+ when :right
91
+ next_obj = @level.get(player.x + 1, player.y)
92
+ player.x += 1 if player.x < @level.width - 1 && (next_obj.nil? ||
93
+ next_obj.passable?)
94
+ when :up
95
+ next_obj = @level.get(player.x, player.y - 1)
96
+ player.y -= 1 if player.y > 0 && (next_obj.nil? || next_obj.passable?)
97
+ when :down
98
+ if player.y + 1 < @level.height - 1
99
+ next_obj = @level.get(player.x, player.y + 1)
100
+ player.y += 1 if next_obj.nil? || next_obj.passable?
101
+ end
102
+ end
103
+
104
+ return unless next_obj != 0 && next_obj.class.ancestors.include?(Item)
105
+
106
+ @level.pellets_left -= 1 if next_obj.instance_of?(Pellet)
107
+ @state = :win if @level.pellets_left == 0
108
+
109
+ eat_power_pellet if next_obj.instance_of?(PowerPellet)
110
+
111
+ @level[player.y][player.x] = nil
112
+ end
113
+
114
+ def eat_power_pellet
115
+ @level.ghosts_frozen = 10 # frozen for x steps
116
+ end
117
+
118
+ def update_delta
119
+ # Gosu::millisecodns returns the time since the game_window was created
120
+ # Divide by 1000 since we want to work in seconds
121
+ current_time = Gosu.milliseconds / 1000.0
122
+ # clamping here is important to avoid strange behaviors
123
+ @delta = [current_time - @last_milliseconds, 0.25].min
124
+ @last_milliseconds = current_time
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,41 @@
1
+ module Pacman
2
+ # model of ghost
3
+ class Ghost < AnimatedObject
4
+ def initialize(x, y, direction)
5
+ super()
6
+ @x, @y = x, y
7
+ @direction = direction
8
+ @stopped = false # used for slow ghost
9
+ end
10
+
11
+ attr_accessor :x, :y, :direction, :stopped
12
+ end
13
+
14
+ # red ghost
15
+ class BlinkyGhost < Ghost
16
+ def initialize(x, y, direction)
17
+ super(x, y, direction)
18
+ end
19
+ end
20
+
21
+ # pink ghost
22
+ class PinkyGhost < Ghost
23
+ def initialize(x, y, direction)
24
+ super(x, y, direction)
25
+ end
26
+ end
27
+
28
+ # cyan ghost
29
+ class InkyGhost < Ghost
30
+ def initialize(x, y, direction)
31
+ super(x, y, direction)
32
+ end
33
+ end
34
+
35
+ # orange ghost
36
+ class ClydeGhost < Ghost
37
+ def initialize(x, y, direction)
38
+ super(x, y, direction)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,253 @@
1
+ module Pacman
2
+ # handles behaviour of ghosts
3
+ class GhostsController
4
+ def initialize(level)
5
+ @level = level
6
+ @colission = false
7
+ end
8
+
9
+ def update
10
+ @level.ghosts_frozen -= 1 unless (@level.ghosts_frozen == 0)
11
+ return unless (@level.ghosts_frozen == 0)
12
+
13
+ update_blinky ||
14
+ update_pinky ||
15
+ update_inky ||
16
+ update_clyde
17
+ end
18
+
19
+ attr_accessor :colission
20
+
21
+ private
22
+
23
+ def update_blinky
24
+ ghost = @level.ghosts[:blinky]
25
+ dirs = update_ghost(ghost)
26
+
27
+ behave_smart(ghost, dirs)
28
+ end
29
+
30
+ def update_pinky
31
+ ghost = @level.ghosts[:pinky]
32
+ dirs = update_ghost(ghost)
33
+
34
+ behave_random(ghost, dirs)
35
+ end
36
+
37
+ def update_inky
38
+ ghost = @level.ghosts[:inky]
39
+ dirs = update_ghost(ghost)
40
+
41
+ behave_random(ghost, dirs)
42
+ end
43
+
44
+ def update_clyde
45
+ ghost = @level.ghosts[:clyde]
46
+ dirs = update_ghost(ghost)
47
+
48
+ behave_slow_random(ghost, dirs)
49
+ end
50
+
51
+ def behave_smart(ghost, dirs)
52
+ return if dirs.nil?
53
+
54
+ if continue_forward?(ghost, dirs)
55
+ move(ghost, ghost.direction)
56
+ return
57
+ end
58
+
59
+ return if try_simply_continue(ghost, dirs)
60
+
61
+ dir = nil
62
+ if (ghost.x - @level.player.x).abs > (ghost.y - @level.player.y).abs
63
+ # prefer horizontal direction
64
+ if ghost.x - @level.player.x > 1
65
+ dir = :left if can_move_left?(ghost)
66
+ else
67
+ dir = :right if can_move_right?(ghost)
68
+ end
69
+
70
+ if dir.nil?
71
+ if ghost.y - @level.player.y > 1
72
+ dir = :up if can_move_up?(ghost)
73
+ else
74
+ dir = :down if can_move_down?(ghost)
75
+ end
76
+ end
77
+ else
78
+ # prefer vertical direction
79
+ if ghost.y - @level.player.y > 1
80
+ dir = :up if can_move_up?(ghost)
81
+ else
82
+ dir = :down if can_move_down?(ghost)
83
+ end
84
+
85
+ if dir.nil?
86
+ if ghost.y - @level.player.y > 1
87
+ dir = :left if can_move_left?(ghost)
88
+ else
89
+ dir = :right if can_move_right?(ghost)
90
+ end
91
+ end
92
+ end
93
+ dir = random_direction(dirs) if dir.nil?
94
+ move(ghost, dir)
95
+ end
96
+
97
+ def behave_slow_random(ghost, dirs)
98
+ if ghost.stopped
99
+ ghost.stopped = false
100
+ return
101
+ end
102
+
103
+ ghost.stopped = true
104
+
105
+ behave_random(ghost, dirs)
106
+ end
107
+
108
+ def behave_random(ghost, dirs)
109
+ return if dirs.nil?
110
+
111
+ if continue_forward?(ghost, dirs)
112
+ move(ghost, ghost.direction)
113
+ else
114
+ if (dirs.size == 2)
115
+ if (dirs.first == inverse_direction(ghost.direction))
116
+ move(ghost, dirs.last)
117
+ else
118
+ move(ghost, dirs.first)
119
+ end
120
+ return
121
+ end
122
+
123
+ dir = random_direction(dirs)
124
+
125
+ move(ghost, dir)
126
+ end
127
+ end
128
+
129
+ # return possible directions if decision needed, nil otherwise
130
+ def update_ghost(ghost)
131
+ dirs = possible_directions(ghost)
132
+ case
133
+ when dirs.size > 1
134
+ return dirs
135
+ when dirs.size == 1
136
+ move(ghost, dirs.first)
137
+ end
138
+ nil
139
+ end
140
+
141
+ def possible_directions(ghost)
142
+ res = []
143
+ res << :left if can_move_left?(ghost)
144
+ res << :right if can_move_right?(ghost)
145
+ res << :up if can_move_up?(ghost)
146
+ res << :down if can_move_down?(ghost)
147
+
148
+ res
149
+ end
150
+
151
+ def random_direction(dirs)
152
+ dir = nil
153
+ loop do
154
+ d = rand(4)
155
+ case d
156
+ when 0
157
+ dir = :left
158
+ when 1
159
+ dir = :right
160
+ when 2
161
+ dir = :up
162
+ when 3
163
+ dir = :down
164
+ end
165
+ break if dirs.include?(dir)
166
+ end
167
+ dir
168
+ end
169
+
170
+ def can_move_left?(ghost)
171
+ return false unless ghost.x > 0
172
+ obj = @level.get(ghost.x - 1, ghost.y)
173
+ obj.nil? || obj.passable?
174
+ end
175
+
176
+ def can_move_right?(ghost)
177
+ return false unless ghost.y < @level.width - 1
178
+ obj = @level.get(ghost.x + 1, ghost.y)
179
+ obj.nil? || obj.passable?
180
+ end
181
+
182
+ def can_move_up?(ghost)
183
+ return false unless ghost.y > 0
184
+ obj = @level.get(ghost.x, ghost.y - 1)
185
+ obj.nil? || obj.passable?
186
+ end
187
+
188
+ def can_move_down?(ghost)
189
+ return false unless ghost.y < @level.height
190
+ obj = @level.get(ghost.x, ghost.y + 1)
191
+ obj.nil? || obj.passable?
192
+ end
193
+
194
+ def continue_forward?(ghost, dirs)
195
+ return false if dirs.size > 2
196
+ return true if dirs.size == 1 && ghost.direction == dirs.first
197
+ (dirs.include?(:left) && dirs.include?(:right) &&
198
+ (ghost.direction == :left || ghost.direction == :right)) ||
199
+ (dirs.include?(:up) && dirs.include?(:down) &&
200
+ (ghost.direction == :up || ghost.direction == :down))
201
+ end
202
+
203
+ def inverse_direction(direction)
204
+ case direction
205
+ when :left
206
+ :right
207
+ when :right
208
+ :left
209
+ when :up
210
+ :down
211
+ when :down
212
+ :up
213
+ end
214
+ end
215
+
216
+ def move(ghost, direction)
217
+ if colission_with_player?(ghost)
218
+ @colission = true
219
+ return
220
+ end
221
+
222
+ ghost.direction = direction
223
+ case direction
224
+ when :left
225
+ ghost.x -= 1
226
+ when :right
227
+ ghost.x += 1
228
+ when :up
229
+ ghost.y -= 1
230
+ when :down
231
+ ghost.y += 1
232
+ end
233
+ @colission = true if colission_with_player?(ghost)
234
+ end
235
+
236
+ def colission_with_player?(ghost)
237
+ ghost.x == @level.player.x && ghost.y == @level.player.y
238
+ end
239
+
240
+ def try_simply_continue(ghost, dirs)
241
+ if (dirs.size == 2)
242
+ # neotoci se uprostred cesty
243
+ if (dirs.first == inverse_direction(ghost.direction))
244
+ move(ghost, dirs.last)
245
+ else
246
+ move(ghost, dirs.first)
247
+ end
248
+ return true
249
+ end
250
+ false
251
+ end
252
+ end
253
+ end