如何用Racket的'big-bang`感受多个按键

时间:2016-01-03 12:39:10

标签: scheme racket

我在Racket开发一个简单的小行星游戏,一切运作良好,除了我想让玩家同时移动和射击。

以下是控制键:

  • 左/右旋转
  • 上/下加速,减速
  • 射击的空间。

我的on-key处理程序:

(define (direct-ship w a-key)
  (define a-ship (world-ship w))
  (define a-direction
    (+ (ship-direction a-ship)
    (cond
      [(key=? a-key "left") -5]
      [(key=? a-key "right") 5]
      [else 0])))
  (define a-speed
    (+ (ship-speed a-ship)
       (cond
         [(key=? a-key "up") 1]
         [(key=? a-key "down") -1]
         [else 0])))
  (define bullets
    (cond
      [(key=? a-key " ") (cons (new-bullet a-ship) (world-bullets w))]
      [else (world-bullets w)]))

  (world (world-asteroids w)
         (ship (ship-pos a-ship) a-direction a-speed)
         bullets
         (world-score w)))

鉴于此proc的签名,我觉得它一次只能处理一个char。所以也许我需要使用不同的处理程序?或者不同的钥匙?

请参阅github上的完整资源: https://github.com/ericclack/racket-examples/blob/master/asteroids4.rkt

1 个答案:

答案 0 :(得分:1)

问题是on-key处理程序一次只调用一个键。即使您能够在同一时间按下右箭头和向上箭头,on-key也会被调用两次。

处理此问题的一种方法是,每个密钥都将信息存储在全局表中,以确定密钥是启用还是关闭。如果有这样的表,您可以在on-key中使用它来检查除当前正在处理的密钥之外的密钥的状态。

以下是Space Invaders克隆的片段。首先是全局键盘表。

;;; Keyboard
; The keyboard state is kept in a hash table. 
; Use key-down? to find out, whether a key is pressed or not.
(define the-keyboard (make-hasheq))
(define (key-down! k) (hash-set! the-keyboard k #t))
(define (key-up! k)   (hash-set! the-keyboard k #f))
(define (key-down? k) (hash-ref  the-keyboard k #f))

然后处理事件 - 由于上下文是在没有big-bang的情况下完成的,但是这里的意思很重要。

;;; Canvas
; Key events sent to the canvas updates the information in the-keyboard.
; Paint events calls draw-world. To prevent flicker we suspend flushing
; while drawing commences.
(define game-canvas%
  (class canvas%
    (define/override (on-event e) ; mouse events
      'ignore)
    (define/override (on-char e)  ; key event
      (define key     (send e get-key-code))
      (define release (send e get-key-release-code))
      (when (eq? release 'press)  ; key down?
        (key-down! key))
      (when (eq? key 'release)    ; key up?
        (key-up! release)
        (when (eq? release #\space)
          (play-sound "shoot.mp3" #t))))
    (define/override (on-paint)   ; repaint (exposed or resized)
      (define dc (send this get-dc))
      (send this suspend-flush)
      (send dc clear)
      (draw-world the-world dc)
      (send this resume-flush))
    (super-new)))

正如您所看到的,关键事件处理程序除了存储键是否上下之外(并且由于一些奇怪的原因,可以播放" shoot.mp3"示例)。那么玩家实际上在哪里移动(根据箭头键)?

实际移动在on-tick(或其等效物)中处理。 处理on-tick中的移动可确保玩家在按下按键时不会移动额外的距离。