2

在试图弄清楚 CLIM 时,我遇到了这个示例程序。这是一个简单的迷宫游戏。作者声称已在 LispWorks 中对其进行了测试(甚至#+Genera在其中进行了测试,暗示该程序可以在真正的 Lisp 机器上运行),但我正试图让它在带有 McCLIM 的 SBCL 中运行。

在 SBCL/McCLIM 下,窗口绘制,但是当您按下移动键时没有任何可见的反应。非移动键会导致文本与游戏说明一起输入到窗格中。

我发现游戏命令键正在改变游戏的内部状态,所以唯一的问题是屏幕没有更新。

然后我意识到您无法编写代码来从实现命令的代码范围内重新绘制迷宫。所有绘制的方法都接收stream来自 CLIM 的参数,该参数必须传递给图形基元。例如:

(defun draw-stone (stream x y cell-width cell-height)
  (let ((half-cell-width (/ cell-width 2))
        (half-cell-height (/ cell-height 2)))
    (draw-ellipse* stream
                   (+ (* x cell-width) half-cell-width)
                   (+ (* y cell-height) half-cell-height)
                   half-cell-width 0
                   0 half-cell-height
                   :ink +red+)))

但处理击键的代码不接受任何stream参数:

(defmacro define-stone-move-command (name keystroke dx dy)
  `(define-maze-frame-command (,name :keystroke ,keystroke) ()
     (let ((maze-array (maze-array *application-frame*)))
       (move-stone maze-array ,dx ,dy)
       (check-for-win maze-array))))

我最终要做的是将stream第一次(也是唯一一次)调用中的参数保存draw-maze-array到全局变量,以便我可以将更新代码添加到define-stone-command宏中,如下所示:

(defmacro define-stone-move-command (name keystroke dx dy)
  `(define-maze-frame-command (,name :keystroke ,keystroke) ()
     (let ((maze-array (maze-array *application-frame*)))
       (move-stone maze-array ,dx ,dy)
       (check-for-win maze-array)
       (draw-maze-array *application-frame* *maze-stream*))))

这种轻微的改变在带有 McCLIM 的 SBCL 上提供了所需的行为,但这似乎并不正确。毕竟,作者声称该代码在 LispWorks 上运行良好。我有几个问题:

  1. 有 LispWorks 的人可以确认这个程序在 LispWorks 上按原样工作吗?
  2. 我对代码的更改是否使其在 LispWorks 上失败?
  3. 在 CLIM 应用程序中处理屏幕更新的公认方法是什么?
4

1 回答 1

1

在命令中绘制迷宫不是正确的方法。将迷宫流放入全局变量中也很糟糕。;-)

显示窗格有一个:display-function. 这个想法是,在一个命令之后,整个应用程序框架会自动更新。例如对于:display-time :command-loop,显示窗格将在命令运行后自动更新。还有其他更新窗格的方法,但在这种情况下,击键运行命令,然后顶级循环将只为每个适用的窗格调用显示函数。默认的顶层循环读取一个命令(通过鼠标、命令行、击键,...),执行它并更新应用程序框架 - 在一个循环中。

整个重新显示的事情非常棘手/强大。它允许从完全自动的重新显示机制到极其精细的控制。

你可以在这里阅读:CLIM 2 Spec。注意:规范和实现提供的内容之间可能存在相当大的差异......

于 2015-06-10T18:25:59.883 回答