ClojureScript中的游戏架构

时间:2014-04-14 21:47:57

标签: clojure clojurescript

假设您正在制作游戏。在游戏中你有一些关于世界的状态:得分,玩家数量,敌人等。让我们说游戏足够简单,在文件中使用全局变量来更新世界并不是那么糟糕。不是最佳,但这是一种方法。从OO的角度来看,您将拥有一个单独的对象,如World对象,以及查询/更新的方法。

检测按键并将按下的状态传递到引擎中的最佳做法是什么?它会是这样的:

  (let [presses {}] 
     (.addEventListener "keypress" #(!set presses (into presses {%1 true})))
     (requestAnimationFrame js/window (fn [] (do-game presses))

4 个答案:

答案 0 :(得分:4)

使用core.async来捕获和合并事件并将它们转换为游戏命令是一个非常酷的方法。

你可以在我的蛇游戏中看到一个例子:
https://github.com/joakin/cnake/blob/master/src/cnake/ui.cljs#L140-L217

一旦您捕获了输入并将其转换为游戏事件,您就可以将其传输到您拥有游戏逻辑的任何地方。

在我的情况下,这是一个go-loop,它处理命令并在本地包含游戏状态到该fn,并对其应用不同的函数并发出事件以供UI响应:
https://github.com/joakin/cnake/blob/master/src/cnake/ui.cljs#L140-L217

更传统的方法是将这些命令传递给选择如何更新包含游戏状态的原子的函数。

关于游戏中core.async类型的架构有一篇很酷的帖子:
http://ragnard.github.io/2013/10/01/clojurecup-pong-async.html

答案 1 :(得分:2)

是的,这样可以正常工作,虽然全局状态不需要单例对象,但简单的atom会很好。交互式Clojurescript程序有太多选项,例如在这种情况下推荐任何特定的程序。

答案 2 :(得分:2)

有很多方法可以解决这个问题,但我会向我展示。我用clojurescript的baconjs和jquery包装器做这个。

(ns puzzle.input
  (:require [jayq.core :as j :refer [$]]
            [yolk.bacon :as b]))

(defn- read-key-input [e]
  (let [k (.-which e)]
    (condp = k
      38 :north
      40 :south
      37 :west
      39 :east
      :sit)))

(defn arrow-stream [$elem]
  (-> (.keydownE $elem)
      (b/filter (fn [e] (not= :sit (read-key-input e))))
      (b/do-action j/prevent)
      (b/map (fn [e] (read-key-input e)))))

我在身体上设置了一个键盘输入流。我订阅了这样的流:

(-> (puzzle.input/arrow-stream (jayq.core/$ "body"))
    (yolk.bacon/on-value (fn [direction] (change-world direction))))

现在只要按键是箭头,change-world函数就会被调用方向。

https://github.com/Cicayda/yolk
https://github.com/Cicayda/yolk-jquery
https://github.com/ibdknox/jayq

答案 3 :(得分:0)

您可以尝试使用Om,因为它通过在RequestAnimationFrame中呈现的原子中创建应用程序状态来实现