comparison lisp/play/snake.el @ 43464:dc17128932c4

(snake-velocity-queue, snake-update-velocity) (snake-final-x-velocity, snake-final-y-velocity): New variable and functions. Store user's keypresses into a queue and pop from the queue each subsequent turn. (snake-update-game, snake-move-left) (snake-move-right, snake-move-up, snake-move-down, snake-active-p) (snake-start-game): Use that queue. (snake-use-glyphs-flag): Renamed from snake-use-glyphs. (snake-use-color-flag): Likewise. (snake-mode): Rename uses of those variables.
author Richard M. Stallman <rms@gnu.org>
date Fri, 22 Feb 2002 15:19:06 +0000
parents 28a987555ba1
children 93a9551db080
comparison
equal deleted inserted replaced
43463:9fbf31526ff4 43464:dc17128932c4
32 32
33 (require 'gamegrid) 33 (require 'gamegrid)
34 34
35 ;; ;;;;;;;;;;;;; customization variables ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 35 ;; ;;;;;;;;;;;;; customization variables ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
36 36
37 (defvar snake-use-glyphs t 37 (defvar snake-use-glyphs-flag t
38 "Non-nil means use glyphs when available.") 38 "Non-nil means use glyphs when available.")
39 39
40 (defvar snake-use-color t 40 (defvar snake-use-color-flag t
41 "Non-nil means use color when available.") 41 "Non-nil means use color when available.")
42 42
43 (defvar snake-buffer-name "*Snake*" 43 (defvar snake-buffer-name "*Snake*"
44 "Name used for Snake buffer.") 44 "Name used for Snake buffer.")
45 45
144 (defvar snake-velocity-y 0) 144 (defvar snake-velocity-y 0)
145 (defvar snake-positions nil) 145 (defvar snake-positions nil)
146 (defvar snake-cycle 0) 146 (defvar snake-cycle 0)
147 (defvar snake-score 0) 147 (defvar snake-score 0)
148 (defvar snake-paused nil) 148 (defvar snake-paused nil)
149 (defvar snake-moved-p nil)
150 (defvar snake-velocity-queue nil
151 "This queue stores the velocities requested too quickly by user.
152 They will take effect one at a time at each clock-interval.
153 This is necessary for proper behavior.
154
155 For instance, if you are moving right, you press up and then left, you
156 want the snake to move up just once before starting to move left. If
157 we implemented all your keystrokes immediately, the snake would
158 effectively never move up. Thus, we need to move it up for one turn
159 and then start moving it leftwards.")
160
149 161
150 (make-variable-buffer-local 'snake-length) 162 (make-variable-buffer-local 'snake-length)
151 (make-variable-buffer-local 'snake-velocity-x) 163 (make-variable-buffer-local 'snake-velocity-x)
152 (make-variable-buffer-local 'snake-velocity-y) 164 (make-variable-buffer-local 'snake-velocity-y)
153 (make-variable-buffer-local 'snake-positions) 165 (make-variable-buffer-local 'snake-positions)
154 (make-variable-buffer-local 'snake-cycle) 166 (make-variable-buffer-local 'snake-cycle)
155 (make-variable-buffer-local 'snake-score) 167 (make-variable-buffer-local 'snake-score)
156 (make-variable-buffer-local 'snake-paused) 168 (make-variable-buffer-local 'snake-paused)
169 (make-variable-buffer-local 'snake-moved-p)
170 (make-variable-buffer-local 'snake-velocity-queue)
157 171
158 ;; ;;;;;;;;;;;;; keymaps ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 172 ;; ;;;;;;;;;;;;; keymaps ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
159 173
160 (defvar snake-mode-map 174 (defvar snake-mode-map
161 (make-sparse-keymap 'snake-mode-map)) 175 (make-sparse-keymap 'snake-mode-map))
221 snake-velocity-x snake-initial-velocity-x 235 snake-velocity-x snake-initial-velocity-x
222 snake-velocity-y snake-initial-velocity-y 236 snake-velocity-y snake-initial-velocity-y
223 snake-positions nil 237 snake-positions nil
224 snake-cycle 1 238 snake-cycle 1
225 snake-score 0 239 snake-score 0
226 snake-paused nil) 240 snake-paused nil
241 snake-moved-p nil
242 snake-velocity-queue nil)
227 (let ((x snake-initial-x) 243 (let ((x snake-initial-x)
228 (y snake-initial-y)) 244 (y snake-initial-y))
229 (dotimes (i snake-length) 245 (dotimes (i snake-length)
230 (gamegrid-set-cell x y snake-snake) 246 (gamegrid-set-cell x y snake-snake)
231 (setq snake-positions (cons (vector x y) snake-positions)) 247 (setq snake-positions (cons (vector x y) snake-positions))
233 (incf y snake-velocity-y))) 249 (incf y snake-velocity-y)))
234 (snake-update-score)) 250 (snake-update-score))
235 251
236 (defun snake-update-game (snake-buffer) 252 (defun snake-update-game (snake-buffer)
237 "Called on each clock tick. 253 "Called on each clock tick.
238 Advances the snake one square, testing for collision." 254 Advances the snake one square, testing for collision.
239 (if (and (not snake-paused) 255 Argument SNAKE-BUFFER is the name of the buffer."
240 (eq (current-buffer) snake-buffer)) 256 (when (and (not snake-paused)
241 (let* ((pos (car snake-positions)) 257 (eq (current-buffer) snake-buffer))
242 (x (+ (aref pos 0) snake-velocity-x)) 258 (snake-update-velocity)
243 (y (+ (aref pos 1) snake-velocity-y)) 259 (let* ((pos (car snake-positions))
244 (c (gamegrid-get-cell x y))) 260 (x (+ (aref pos 0) snake-velocity-x))
245 (if (or (= c snake-border) 261 (y (+ (aref pos 1) snake-velocity-y))
246 (= c snake-snake)) 262 (c (gamegrid-get-cell x y)))
247 (snake-end-game) 263 (if (or (= c snake-border)
248 (cond ((= c snake-dot) 264 (= c snake-snake))
249 (incf snake-length) 265 (snake-end-game)
250 (incf snake-score) 266 (cond ((= c snake-dot)
251 (snake-update-score)) 267 (incf snake-length)
252 (t 268 (incf snake-score)
253 (let* ((last-cons (nthcdr (- snake-length 2) 269 (snake-update-score))
254 snake-positions)) 270 (t
255 (tail-pos (cadr last-cons)) 271 (let* ((last-cons (nthcdr (- snake-length 2)
256 (x0 (aref tail-pos 0)) 272 snake-positions))
257 (y0 (aref tail-pos 1))) 273 (tail-pos (cadr last-cons))
258 (gamegrid-set-cell x0 y0 274 (x0 (aref tail-pos 0))
259 (if (= (% snake-cycle 5) 0) 275 (y0 (aref tail-pos 1)))
260 snake-dot 276 (gamegrid-set-cell x0 y0
261 snake-blank)) 277 (if (= (% snake-cycle 5) 0)
262 (incf snake-cycle) 278 snake-dot
263 (setcdr last-cons nil)))) 279 snake-blank))
264 (gamegrid-set-cell x y snake-snake) 280 (incf snake-cycle)
265 (setq snake-positions 281 (setcdr last-cons nil))))
266 (cons (vector x y) snake-positions)))))) 282 (gamegrid-set-cell x y snake-snake)
283 (setq snake-positions
284 (cons (vector x y) snake-positions))
285 (setq snake-moved-p nil)))))
286
287 (defun snake-update-velocity ()
288 (unless snake-moved-p
289 (if snake-velocity-queue
290 (let ((new-vel (car (last snake-velocity-queue))))
291 (setq snake-velocity-x (car new-vel)
292 snake-velocity-y (cadr new-vel))
293 (setq snake-velocity-queue
294 (nreverse (cdr (nreverse snake-velocity-queue))))))
295 (setq snake-moved-p t)))
296
297 (defun snake-final-x-velocity ()
298 (or (caar snake-velocity-queue)
299 snake-velocity-x))
300
301 (defun snake-final-y-velocity ()
302 (or (cadr (car snake-velocity-queue))
303 snake-velocity-y))
267 304
268 (defun snake-move-left () 305 (defun snake-move-left ()
269 "Makes the snake move left" 306 "Make the snake move left."
270 (interactive) 307 (interactive)
271 (unless (= snake-velocity-x 1) 308 (when (zerop (snake-final-x-velocity))
272 (setq snake-velocity-x -1 309 (push '(-1 0) snake-velocity-queue)))
273 snake-velocity-y 0)))
274 310
275 (defun snake-move-right () 311 (defun snake-move-right ()
276 "Makes the snake move right" 312 "Make the snake move right."
277 (interactive) 313 (interactive)
278 (unless (= snake-velocity-x -1) 314 (when (zerop (snake-final-x-velocity))
279 (setq snake-velocity-x 1 315 (push '(1 0) snake-velocity-queue)))
280 snake-velocity-y 0)))
281 316
282 (defun snake-move-up () 317 (defun snake-move-up ()
283 "Makes the snake move up" 318 "Make the snake move up."
284 (interactive) 319 (interactive)
285 (unless (= snake-velocity-y 1) 320 (when (zerop (snake-final-y-velocity))
286 (setq snake-velocity-x 0 321 (push '(0 -1) snake-velocity-queue)))
287 snake-velocity-y -1)))
288 322
289 (defun snake-move-down () 323 (defun snake-move-down ()
290 "Makes the snake move down" 324 "Make the snake move down."
291 (interactive) 325 (interactive)
292 (unless (= snake-velocity-y -1) 326 (when (zerop (snake-final-y-velocity))
293 (setq snake-velocity-x 0 327 (push '(0 1) snake-velocity-queue)))
294 snake-velocity-y 1)))
295 328
296 (defun snake-end-game () 329 (defun snake-end-game ()
297 "Terminates the current game" 330 "Terminate the current game."
298 (interactive) 331 (interactive)
299 (gamegrid-kill-timer) 332 (gamegrid-kill-timer)
300 (use-local-map snake-null-map) 333 (use-local-map snake-null-map)
301 (gamegrid-add-score snake-score-file snake-score)) 334 (gamegrid-add-score snake-score-file snake-score))
302 335
303 (defun snake-start-game () 336 (defun snake-start-game ()
304 "Starts a new game of Snake" 337 "Start a new game of Snake."
305 (interactive) 338 (interactive)
306 (snake-reset-game) 339 (snake-reset-game)
307 (use-local-map snake-mode-map) 340 (use-local-map snake-mode-map)
308 (gamegrid-start-timer snake-tick-period 'snake-update-game)) 341 (gamegrid-start-timer snake-tick-period 'snake-update-game))
309 342
310 (defun snake-pause-game () 343 (defun snake-pause-game ()
311 "Pauses (or resumes) the current game" 344 "Pause (or resume) the current game."
312 (interactive) 345 (interactive)
313 (setq snake-paused (not snake-paused)) 346 (setq snake-paused (not snake-paused))
314 (message (and snake-paused "Game paused (press p to resume)"))) 347 (message (and snake-paused "Game paused (press p to resume)")))
315 348
316 (defun snake-active-p () 349 (defun snake-active-p ()
319 (put 'snake-mode 'mode-class 'special) 352 (put 'snake-mode 'mode-class 'special)
320 353
321 (defun snake-mode () 354 (defun snake-mode ()
322 "A mode for playing Snake. 355 "A mode for playing Snake.
323 356
324 snake-mode keybindings: 357 Snake mode keybindings:
325 \\{snake-mode-map} 358 \\{snake-mode-map}
326 " 359 "
327 (kill-all-local-variables) 360 (kill-all-local-variables)
328 361
329 (add-hook 'kill-buffer-hook 'gamegrid-kill-timer nil t) 362 (add-hook 'kill-buffer-hook 'gamegrid-kill-timer nil t)
341 ["Pause" snake-pause-game 374 ["Pause" snake-pause-game
342 (and (snake-active-p) (not snake-paused))] 375 (and (snake-active-p) (not snake-paused))]
343 ["Resume" snake-pause-game 376 ["Resume" snake-pause-game
344 (and (snake-active-p) snake-paused)])) 377 (and (snake-active-p) snake-paused)]))
345 378
346 (setq gamegrid-use-glyphs snake-use-glyphs) 379 (setq gamegrid-use-glyphs snake-use-glyphs-flag)
347 (setq gamegrid-use-color snake-use-color) 380 (setq gamegrid-use-color snake-use-color-flag)
348 381
349 (gamegrid-init (snake-display-options)) 382 (gamegrid-init (snake-display-options))
350 383
351 (run-hooks 'snake-mode-hook)) 384 (run-hooks 'snake-mode-hook))
352 385
355 "Play the Snake game. 388 "Play the Snake game.
356 Move the snake around without colliding with its tail or with the border. 389 Move the snake around without colliding with its tail or with the border.
357 390
358 Eating dots causes the snake to get longer. 391 Eating dots causes the snake to get longer.
359 392
360 snake-mode keybindings: 393 Snake mode keybindings:
361 \\<snake-mode-map> 394 \\<snake-mode-map>
362 \\[snake-start-game] Starts a new game of Snake 395 \\[snake-start-game] Starts a new game of Snake
363 \\[snake-end-game] Terminates the current game 396 \\[snake-end-game] Terminates the current game
364 \\[snake-pause-game] Pauses (or resumes) the current game 397 \\[snake-pause-game] Pauses (or resumes) the current game
365 \\[snake-move-left] Makes the snake move left 398 \\[snake-move-left] Makes the snake move left
366 \\[snake-move-right] Makes the snake move right 399 \\[snake-move-right] Makes the snake move right
367 \\[snake-move-up] Makes the snake move up 400 \\[snake-move-up] Makes the snake move up
368 \\[snake-move-down] Makes the snake move down 401 \\[snake-move-down] Makes the snake move down"
369
370 "
371 (interactive) 402 (interactive)
372 403
373 (switch-to-buffer snake-buffer-name) 404 (switch-to-buffer snake-buffer-name)
374 (gamegrid-kill-timer) 405 (gamegrid-kill-timer)
375 (snake-mode) 406 (snake-mode)