oakes / play-clj

A Clojure game library
The Unlicense
939 stars 73 forks source link

Re-evaluating defscreen within a REPL session #5

Closed Misophistful closed 10 years ago

Misophistful commented 10 years ago

Is it possible to re-evaluate defscreen within a REPL session in a way that newly added functions (:on-key-down, :on-timer, etc.) are evaluated and the game doesn't need to be restarted?

To clarify a little: I'm using Light Table, and re-evaluating core.clj works perfectly when I make changes to my helper functions, or even to existing defscreen functions (like :on-show). But when I add a new function to defscreen, such as :on-timer, no amount of re-evaluating the namespace seems to enable the new function within the current REPL session. However, as soon as I stop and re-launch the game the new function is enabled as expected.

I'm guessing this might have something to do with defscreen being a macro? But I think the most likely scenario is that I'm making a mistake with my workflow. What might I be doing wrong?

oakes commented 10 years ago

Actually, this is indeed a problem with the way defscreen is written. I chose to use defonce because I didn't want the state to be wiped out when reloading the namespace. After giving it some thought, I think I found a way to do this without defonce. I just pushed the change in 0.2.3-SNAPSHOT, so if you could try it out and let me know if it works I would appreciate it.

Misophistful commented 10 years ago

Thanks for your lightning quick response.

I tried 0.2.3-SNAPSHOT, but I'm seeing the same behaviour as before: i.e. adding a new function to defscreen requires a game restart to take effect.

I'm trying to add this :on-timer function (with the associated add-timer! in :on-show) whilst in a REPL session:

  :on-timer
  (fn [screen entities]
    (case (:id screen)
      (conj entities (spawn-an-apple)))))

I thought there might be something special with timers stopping this working, so I also tried adding a plain old :on-resize function, but got the same result - a restart was required.

Here's my project.clj for you to double-check that I'm pulling the SNAPSHOT in correctly:

(defproject apples "0.0.1-SNAPSHOT"
  :description "FIXME: write description"

  :dependencies [[com.badlogicgames.gdx/gdx "0.9.9"]
                 [com.badlogicgames.gdx/gdx-backend-lwjgl "0.9.9"]
                 [com.badlogicgames.gdx/gdx-platform "0.9.9"
                  :classifier "natives-desktop"]
                 [org.clojure/clojure "1.5.1"]
                 [play-clj "0.2.3-SNAPSHOT"]]
  :repositories [["sonatype"
                  "https://oss.sonatype.org/content/repositories/snapshots/"]]

  :source-paths ["src" "src-common"]
  :javac-options ["-target" "1.6" "-source" "1.6" "-Xlint:-options"]
  :aot [apples.core.desktop-launcher]
  :main apples.core.desktop-launcher)
oakes commented 10 years ago

I think I know what may be going on. Although my recent fix allows newly-defined functions to be in the namespace, your screen still can't see them because it was created before they were defined. If I am right, you should be able to get this to work by running set-screen! again. In a REPL, you must run it like this so it runs on the render thread:

(app! :post-runnable #(set-screen! apples main-screen))

Misophistful commented 10 years ago

Thanks Zach, that works like a charm!