如何使用core.async防止重叠动画?

时间:2014-06-08 01:31:08

标签: animation clojure clojurescript core.async

我有这个循环处理角色的动画 - set-image!只需要一个键并显示相应的图像。

(defn main-animation-loop []
  (go (while true
        (set-image! :normal)
        (<! (timeout 8000))
        (set-image! :blink)
        (<! (timeout 150)))))

角色每隔一段时间就需要做一些特殊的动作。这应该能够中断主动画:

(defn dance! []
  (go (set-image! :look-left)
      (<! (timeout 1000))
      (set-image! :look-right)
      (<! (timeout 1000))
      (set-image! :wave)
      (<! (timeout 2000))))

什么是在舞蹈例行发生时暂停主动画的好方法?

1 个答案:

答案 0 :(得分:5)

在CSP风格编程中,将控制通道传递给事件循环很常见,因此您至少可以告诉他们何时停止。在这种情况下,如果有一个转到main-animation-loop的控制频道并且您将其复制到dance!,那么舞蹈可以告诉main-animation-loop暂停和取消暂停。或者停止它然后再次启动它(通过相同的控制通道,以防其他人使用它)。

我使用这样的模式来检查每次事件循环的消息:

(go (while (not= control-chan
                 (second (async/alts! [control-chan (async/timeout arg)])))
           (do-stuff-here))

检查是否是导致中断的超时或控制通道。

(defn main-animation-loop [control-chan]
  (go (while (not= control-chan
                 (second (async/alts! [control-chan (async/timeout 150)])))
        (set-image! :normal)
        (<! (timeout 8000))
        (set-image! :blink))))

(defn dance! [control-chan]
  (go (!> control-chan :stop)
      (set-image! :look-left)
      (<! (timeout 1000))
      (set-image! :look-right)
      (<! (timeout 1000))
      (set-image! :wave)
      (<! (timeout 2000))
      (main-animation-loop control-chan)))

通过将相同的通道传递给两个功能,您可以允许它们相互通信。只要收到的所有消息都来自超时通道,main-animation-loop将保持循环。一旦它看到其中一个来自控制通道而不是超时,它就会停止。这允许dance!通过向控制通道发送任何消息来告诉它停止。在类似的代码中,我经常让主事件循环检查消息的内容,并且不仅仅停止,但在这种情况下停止就足够了,因为dance!可以简单地再次启动事件循环。