【问题标题】:Analogy of Python is_pressed in Common Lisp?在 Common Lisp 中类比 Python is_pressed?
【发布时间】:2018-11-12 19:24:16
【问题描述】:

我正在用 Common Lisp 制作一个简单的 LTK 游戏,并且想让玩家角色在按下空格键时跳跃。但是,窗口在不断更新,所以我不能等待用户输入。我想检查每一帧是否按下了空格键。尽管进行了很多谷歌搜索,但我还是找不到在 Lisp 中执行此操作的方法。我发现的只是阻止程序流程的传统 I/O 提示。

感谢您的帮助。

【问题讨论】:

    标签: io common-lisp


    【解决方案1】:

    您使用的是 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)))))
    

    上述函数的第一部分为Left、Right、Down 和Up 键创建一个画布并为KeyPress/KeyRelease 事件绑定事件处理程序。这有点冗长,但对于示例来说足够简单。或者,您可以只绑定"&lt;KeyPress&gt;" 和"&lt;KeyRelease&gt;" 事件(字符串中没有其他键),并使用由您的键事件的keycode 索引的表。

    第二部分是游戏循环,其中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))
    

    但这是错误的,因为顺序 press-left、press-right 和 release-right 会使矩形停止。

    【讨论】:

    • 这适用于一个按钮,但绑定例如用于移动的向上箭头和向左箭头都一次只注册一个。有没有办法解决这个问题?
    • @Kotlopou 编辑了答案
    猜你喜欢
    • 2012-12-05
    • 1970-01-01
    • 2016-07-30
    • 2011-08-26
    • 1970-01-01
    • 2019-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多