我在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
答案 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
中的移动可确保玩家在按下按键时不会移动额外的距离。