Reputation: 5848
Let's say you're making a game. In the game you have some state about the world: score, number of players, enemies, etc. Let's say the game is sufficiently simple where it wouldn't be that bad to have globals in the file to update the world. Not optimal, but that's one way to do it. From an OO perspective you'd have a singleton object like a World object, with methods to query/update.
What would be best practice to detect key presses and pass the state of the presses into the engine? Would it be something like:
(let [presses {}]
(.addEventListener "keypress" #(!set presses (into presses {%1 true})))
(requestAnimationFrame js/window (fn [] (do-game presses))
Upvotes: 1
Views: 1926
Reputation: 3719
There are so many ways to go about this, but I will show mine. I do this with baconjs and jquery wrappers for clojurescript.
(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)))))
I set up a stream of keyboard input on the body. I subscribe to that stream with something like this:
(-> (puzzle.input/arrow-stream (jayq.core/$ "body"))
(yolk.bacon/on-value (fn [direction] (change-world direction))))
Now whenever the keypress is an arrow, the change-world
function gets called with the direction.
https://github.com/Cicayda/yolk
https://github.com/Cicayda/yolk-jquery
https://github.com/ibdknox/jayq
Upvotes: 2
Reputation: 58796
You could try Om for this as it works by creating the application state in an atom which is rendered in RequestAnimationFrame
Upvotes: 0
Reputation: 2744
Using core.async to capture and merge the events and translate them into game commands is a pretty cool way to go about this.
You can see an example in my snake game:
https://github.com/joakin/cnake/blob/master/src/cnake/ui.cljs#L140-L217
Once you have captured your input and transformed it into game events, you could pipe it to wherever you've got the game logic.
In my case, thats a go-loop that processes commands and contains the game state locally to that fn, and applies different functions to it and emits events for the UI to react to:
https://github.com/joakin/cnake/blob/master/src/cnake/ui.cljs#L140-L217
A more traditional approach would be to pass those commands to a function that would choose how to update an atom containing the game state.
There is a cool post about the core.async type of architecture on a game:
http://ragnard.github.io/2013/10/01/clojurecup-pong-async.html
Upvotes: 4
Reputation: 91577
Yes that would work fine, Though there is no need for a singleton object for the global state, a simple atom
will do fine. There are too many options for interactive Clojurescript programs such as this to recommend any particular one in this case.
Upvotes: 2