我正在制作一个简单的LTK游戏,在通用Lisp,并希望让玩家的角色跳上按下空间。但是,该窗口正在不断更新,因此我不能等待用户输入。我想检查每个帧是否按下空格键。尽管谷歌搜索了很多,但我无法在Lisp中找到这样的方法。我发现的只是阻止程序流的传统I/O提示。
谢谢你的帮助。
发布于 2018-11-09 20:16:50
你用的是Tk画布吗?也许您可以将事件处理程序绑定到键按下?
(with-ltk ()
(let ((canvas (make-canvas nil)))
(grid canvas 1 1)
(bind canvas
"<Left>"
(lambda (e)
(message-box "Left" "Click" "okcancel" "info")))
(focus canvas)))当您收到按下键时,您可以设置一个变量,在处理框架时对其进行检查。
这对一个按钮很好,但是绑定,例如,向上箭头和左箭头的移动,一次只注册一个。有办法解决这个问题吗?
下面是一个更详细的例子。Tk可以绑定在KeyPress和KeyRelease事件上。您只需要管理要观察的键的按下/未按下状态,并相应地设置正确的变量。
(with-ltk ()
(let ((canvas (make-canvas nil))
(x 50)
(y 50)
(speed 5)
(w 10)
(h 10)
(dx 0)
(dy 0))
(grid canvas 1 1)
(macrolet
((on (event expr)
(check-type event string)
(let ((evar (gensym)))
`(bind canvas ,event
(lambda (,evar)
(declare (ignore ,evar))
,expr)))))
(on "<KeyPress-Left>" (decf dx))
(on "<KeyPress-Right>" (incf dx))
(on "<KeyRelease-Left>" (incf dx))
(on "<KeyRelease-Right>" (decf dx))
(on "<KeyPress-Up>" (decf dy))
(on "<KeyPress-Down>" (incf dy))
(on "<KeyRelease-Up>" (incf dy))
(on "<KeyRelease-Down>" (decf dy)))
(focus canvas)
(let ((rectangle (create-rectangle canvas x y 10 10)))
(labels ((game-loop ()
(incf x (* dx speed))
(incf y (* dy speed))
(set-coords canvas rectangle (list x y (+ x w) (+ y h)))
(after 50 #'game-loop)))
(game-loop)))))上述函数的第一部分为KeyPress/KeyRelease事件为Left、Right、Down和Up键创建一个画布并绑定事件处理程序。这是有点冗长,但足够简单的一个例子。或者,您可以仅在"<KeyPress>"和"<KeyRelease>"事件(字符串中没有附加键)上绑定,并使用由键事件的keycode索引的表。
第二部分是游戏循环,其中deltas dx和dy实际上都用于移动矩形;在游戏循环的末尾,after确保游戏循环在一段时间后再次运行。
事件处理程序不直接操作画布元素,它们只用于将UI事件转换为游戏逻辑更改。你必须小心事件发生的方式和时间。例如,上面的第一个版本用于:
(on "<KeyPress-Left>" (setf dx -1))
(on "<KeyPress-Right>" (setf dx 1))
(on "<KeyRelease-Right>" (setf dx 0))
(on "<KeyRelease-Left>" (setf dx 0))但这是错误的,因为顺序按左、按右和放右会使矩形停止。
https://stackoverflow.com/questions/53230492
复制相似问题