1
votes

I'm working on a game in Clojure using Swing. I have a KeyListener to take care of controls, but it's not updating a ref.

(def move (ref :drop))

(defn get-move 
  [block state x y moves]
  (do (println @move)
      (if (check-move @move x y block state) @move
        :nothing)))



(defn listener
  [keyevent]
  (let [c (.getKeyChar keyevent)]
   (do (println c)
      (cond (= c "j") (dosync (ref-set move :left))
            (= c "l") (dosync (ref-set move :right))
            (= c "i") (dosync (ref-set move :rotate))
            (= c "k") (dosync (ref-set move :drop))))))



(defn make-keylistener
  []
 (proxy [KeyAdapter] []
  (keyPressed [event]
            (listener event))))

Now, the idea is that the main function that updates the gui calls get-move. It checks if the move ref is valid in the game, and if so returns it. The listener is attached to a JPanel and changes the ref based on a keypress. The listener works fine - whenever a button is pressed, it prints out the key char. I can only assume it's changing the ref. However, get-move always returns the same value - it never sees @move change. I feel like I'm misunderstanding something fundamental about concurrency and state in Clojure. What am I doing wrong, and is there a more functional way of handling this?

Thanks!

EDIT: Same problem occurs if I use atoms.

1

1 Answers

1
votes

It's not a concurrency problem. .getKeyChar returns a char, which I was comparing to a string. Rewriting the conditions to (= (str c) "j") makes it work.