我正在使用 cl-sdl2 编写一个应用程序(一个简单的游戏)。 cl-sdl2 包含一个名为
WITH-EVENT-LOOP
的宏,可用于通过一些事件处理程序启动 SDL 应用程序。
目前我使用宏如下:
(sdl2:with-event-loop (:method :poll)
(:idle () (on-idle :renderer renderer
:tick-func tick-func
:render-func render-func))
(:quit () t)
;; Input handlers below
(:keydown (:keysym keysym)
(funcall input-func :keydown :keysym keysym))
(:keyup (:keysym keysym)
(funcall input-func :keyup :keysym keysym)))
此代码清单很小,因为我省略了几个输入处理程序。至少还定义了 6 个遵循相同模式的处理程序,用于处理鼠标和游戏控制器输入事件,因此我的实际代码更长且高度重复。
我可以编写一个宏来生成这些样板形式:
(defmacro forward-evt-to (target evt &rest evt-args)
`(,evt ,evt-args
(funcall ,target ,evt ,@evt-args)))
这会生成一个可以被
WITH-EVENT-LOOP
理解的列表:
> (macroexpand-1 '(forward-evt-to input-func :keydown :keysym keysym))
(:KEYDOWN (:KEYSYM KEYSYM) (FUNCALL INPUT-FUNC :KEYDOWN :KEYSYM KEYSYM))
T
但是当我尝试使用该宏时,出现编译器错误。例如,这会失败:
(sdl2:with-event-loop (:method :poll)
(:idle () (on-idle :renderer renderer
:tick-func tick-func
:render-func render-func))
(:quit () t)
(forward-evt-to input-func :keydown :keysym keysym)
(forward-evt-to input-func :keyup :keysym keysym))
WITH-EVENT-LOOP
尝试编译代码而不扩展它并给出错误
; The value
; INPUT-FUNC
; is not of type
; LIST
有什么方法可以在
FORWARD-EVT-TO
宏内部使用我的 WITH-EVENT-LOOP
宏吗?我不能/不想直接修改WITH-EVENT-LOOP
。
一种方法是编写一个新的宏,它将扩展为您的目标形式。
示例草图:
CL-USER 8 > (defmacro with-event-loop-1 (foo &body clauses &environment env)
`(with-event-loop ,foo
,(loop for clause in clauses
when (keywordp (first clause))
collect clause
else
collect (macroexpand-1 clause env))))
WITH-EVENT-LOOP-1
CL-USER 9 > (pprint
(macroexpand
'(with-event-loop-1 (:method :poll)
(:idle () (on-idle :renderer renderer
:tick-func tick-func
:render-func render-func))
(:quit () t)
(forward-evt-to input-func :keydown :keysym keysym)
(forward-evt-to input-func :keyup :keysym keysym))))
(WITH-EVENT-LOOP
(:METHOD :POLL)
((:IDLE NIL (ON-IDLE :RENDERER RENDERER
:TICK-FUNC TICK-FUNC
:RENDER-FUNC RENDER-FUNC))
(:QUIT NIL T)
(:KEYDOWN (:KEYSYM KEYSYM) (FUNCALL INPUT-FUNC :KEYDOWN :KEYSYM KEYSYM))
(:KEYUP (:KEYSYM KEYSYM) (FUNCALL INPUT-FUNC :KEYUP :KEYSYM KEYSYM))))