Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Timers in clojure?

Tags:

timer

clojure

I'm wondering if there is any widespread timer solution.

I want to write a simple game engine which would process users input on tick every 20ms (or perform some actions once after 20ms (or any other period)) and basically update "global" state via transactions, and also I plan to use futures so this solution should be able to deal with concurrency caveats.

Can you give me an advice?

like image 316
Nik Avatar asked May 05 '13 13:05

Nik


2 Answers

You have actually got two distinct issues here.

The first is the issues of timers. You have lots of choices here:

  • Start a thread that sleeps between actions, something like (future (loop [] (do-something) (Thread/sleep 20) (when (game-still-running) (recur))))
  • Use a Java TimerTask - easy to call from Clojure
  • Use a library like my little utility Task that includes a DSL for repeating tasks
  • Use the timer functionality from whatever game engine you are using - most of these provide some tools for setting up a game loop

I'd probably just use the simple thread option - it's pretty easy to set up and easy to hack more features in later if you need to.

The second issue is handling game state. This is actually the trickier problem and you will need to design it around the particular type of game you are making, so I'll just give a few points of advice:

  • If your game state is immutable, then you get a lot of advantages: your rendering code can draw the current game state independently while the game update is computing the next game state. Immutability has some performance costs, but the concurrency advantages are huge if you can make it work. Both of my mini Clojure games (Ironclad and Alchemy) use this approach
  • You should probably try and store your game state in a single top-level var. I find this works better than splitting different parts of the game state over different vars. It also means that you don't really need ref-based transactions: an atom or agent will usually do the trick.
  • You may want to implement a queue of events that need to get processed sequentially by the game state update function. This is particularly important if you have multiple concurrent event sources (e.g. player actions, timer ticks, network events etc.)
like image 134
mikera Avatar answered Oct 19 '22 07:10

mikera


This solution assumes you're writing Clojure on the JVM. Something like this could work:

(import '(java.util TimerTask Timer))

(let [task (proxy [TimerTask] []
             (run [] (println "Here we go!")))]
  (. (new Timer) (schedule task (long 20))))
like image 25
Benjamin Gruenbaum Avatar answered Oct 19 '22 07:10

Benjamin Gruenbaum