From bf41a54aecfe4ca88a7a90b38f98ea9993cb091c Mon Sep 17 00:00:00 2001 From: Jeremy Penner Date: Mon, 18 Mar 2013 23:31:10 -0400 Subject: [PATCH] Screen stack support - rename "game-state" to "screen" (like "title screen", "options screen", etc) - rename :state to :id - provide helpers to load a screen given a "spec", deserialize a screen back to a spec, manage a screen stack - rework test repl helper to allow setting the screen directly, instead of tweaking game state - have start-game take a spec by default --- src/hottub/core.clj | 29 ++++++++++++++++++----------- src/hottub/screen.clj | 39 +++++++++++++++++++++++++++++++++++++++ src/hottub/slick.clj | 41 +++++++++++++++++++++-------------------- 3 files changed, 78 insertions(+), 31 deletions(-) create mode 100644 src/hottub/screen.clj diff --git a/src/hottub/core.clj b/src/hottub/core.clj index 4b51004..b29c5f8 100644 --- a/src/hottub/core.clj +++ b/src/hottub/core.clj @@ -2,17 +2,21 @@ (:require [hottub.slick :as slick] [hottub.gs :as gs] [hottub.resource :as res] - [hottub.timeline :as tln])) + [hottub.timeline :as tln] + [hottub.screen :as scr])) (defn -main [& args] (res/start-resource-expiry-thread) - (slick/start-game "Test game" - {:state :game - :gs (gs/update-gs gs/gs-empty - (gs/add-index :name) - (gs/add-index :type) - (gs/set-entity (gs/gen-id) {:type :sprite :x 50 :y 50 - :image "res/man.png" :name :man}))})) + (slick/start-game "Test game" {:id :game})) + +(defmethod scr/screen-from-spec :game [spec] + {:gs (gs/update-gs gs/gs-empty + (gs/add-index :name) + (gs/add-index :type) + (gs/set-entity (gs/gen-id) {:type :sprite :x 50 :y 50 + :image "res/man.png" :name :man}))}) + +(defmethod scr/spec-from-screen :game [screen] {:id :game}) (defmethod slick/update-game :game [state inputtln delta] (assoc state :gs (gs/update-gs (:gs state) @@ -26,11 +30,14 @@ (if-let [image (res/get-image (:image sprite))] (.draw image (:x sprite) (:y sprite)))))) +;;; repl helpers (def ^:dynamic g nil) (def ^:dynamic s nil) +(def ^:dynamic *newscreen* nil) + +(defn reload [] (reset! *newscreen* (scr/reload-screen s))) (defmethod slick/eval-with-bindings :default [state game f] - (binding [g game s state] + (binding [g game s state *newscreen* (atom nil)] (let [gsnew (gs/update-gs (:gs state) (f))] - (slick/game-setstate! game (assoc state :gs gsnew))))) - + (slick/game-setstate! game (or @*newscreen* (assoc state :gs gsnew)))))) diff --git a/src/hottub/screen.clj b/src/hottub/screen.clj new file mode 100644 index 0000000..47702e9 --- /dev/null +++ b/src/hottub/screen.clj @@ -0,0 +1,39 @@ +(ns hottub.screen) + +(defmulti screen-from-spec (fn [spec] (:id spec))) +(defmulti spec-from-screen (fn [screen] (:id screen))) + +(defn- -screen-from-spec [spec] (assoc (screen-from-spec spec) :id (:id spec))) +(defn- -spec-from-screen [screen] (assoc (spec-from-screen screen) :id (:id screen))) + +(defn push-screen [screenold spec] + (let [specold (-spec-from-screen screenold) + screen (-screen-from-spec spec)] + (update-in [::stack] conj specold))) + +(defn pop-screen [screenold] + (let [stackold (::stack screenold) + specnew (peek stackold) + stacknew (pop stackold) + screen (-screen-from-spec specnew)] + (assoc screen ::stack stacknew))) + +(defn push-modal-screen [screenold spec] + (let [screen (-screen-from-spec spec)] + (assoc screen ::modal screenold))) + +(defn pop-modal-screen [screenold] + (::modal screenold)) + +(defn screen-behind-modal [screen] + (pop-modal-screen screen)) + +(defn update-screen [screenold screennew] + (assoc screennew ::stack (::stack screenold))) + +(defn goto-screen [screenold spec] + (let [screen (-screen-from-spec spec)] + (assoc screen ::stack (::stack screenold)))) + +(defn reload-screen [screen] + (goto-screen screen (-spec-from-screen screen))) diff --git a/src/hottub/slick.clj b/src/hottub/slick.clj index 76cc429..d88dcf9 100644 --- a/src/hottub/slick.clj +++ b/src/hottub/slick.clj @@ -8,11 +8,12 @@ [hottub.util :as u] [hottub.repl :as repl] [hottub.resource :as res] - [hottub.timeline :as tln])) + [hottub.timeline :as tln] + [hottub.screen :as scr])) -(defmulti update-game (fn [state input delta] (:state state))) -(defmulti render-game (fn [state graphics] (:state state))) -(defmulti eval-with-bindings (fn [state game f] (:state state))) +(defmulti update-game (fn [screen input delta] (:id screen))) +(defmulti render-game (fn [screen graphics] (:id screen))) +(defmulti eval-with-bindings (fn [screen game f] (:id screen))) (def slick-key-to-key {Input/KEY_0 :0 @@ -119,14 +120,14 @@ :state state :extends org.newdawn.slick.BasicGame) -(defn game-create [title state] +(defn game-create [title screen] [[title] - {:state (atom state) + {:screen (atom screen) :repl (repl/repl-create 9999) :container (atom nil) :input (input-create)}]) -(defn game-state-atom [this] (:state (.state this))) +(defn game-screen-atom [this] (:screen (.state this))) (defn game-container [this] @(:container (.state this))) (defn game-install-input [this] @@ -147,7 +148,7 @@ (game-install-input this) (repl/repl-start (:repl (.state this)) - (fn [f] (eval-with-bindings @(game-state-atom this) this f)))) + (fn [f] (eval-with-bindings @(game-screen-atom this) this f)))) (defn game-update [this container delta] (doseq [ns-sym (modified-namespaces)] @@ -158,29 +159,29 @@ (.printStackTrace e)))) (repl/repl-update (:repl (.state this))) (try - (if-let [statenew (update-game @(game-state-atom this) (input-timeline-clear! (:input (.state this))) delta)] - (reset! (game-state-atom this) statenew)) + (if-let [screennew (update-game @(game-screen-atom this) (input-timeline-clear! (:input (.state this))) delta)] + (reset! (game-screen-atom this) screennew)) (catch Exception e - (println "Couldn't update" (:state @(game-state-atom this))) + (println "Couldn't update" (:id @(game-screen-atom this))) (.printStackTrace e)))) (defn game-render [this container graphics] (try (res/gc-expired-resources) - (render-game @(game-state-atom this) graphics) + (render-game @(game-screen-atom this) graphics) (catch Exception e - (println "Couldn't render" (:state @(game-state-atom this))) + (println "Couldn't render" (:id @(game-screen-atom this))) (.printStackTrace e)))) -(defn game-setstate! [this statenew] - (reset! (game-state-atom this) statenew)) +(defn game-setscreen! [this screennew] + (reset! (game-screen-atom this) screennew)) -(defmethod update-game :default [state input delta]) -(defmethod render-game :default [state graphics]) -(defmethod eval-with-bindings :default [state game f] (f)) +(defmethod update-game :default [screen input delta]) +(defmethod render-game :default [screen graphics]) +(defmethod eval-with-bindings :default [screen game f] (f)) -(defn start-game [title startstate] - (let [game (hottub.slick.Game. title startstate) +(defn start-game [title spec] + (let [game (hottub.slick.Game. title (scr/goto-screen nil spec)) container (AppGameContainer. game 640 480 false)] (.setAlwaysRender container true) (.start container)