Mercurial > emacs
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) |