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
This commit is contained in:
parent
cc62dfb054
commit
bf41a54aec
|
@ -2,17 +2,21 @@
|
||||||
(:require [hottub.slick :as slick]
|
(:require [hottub.slick :as slick]
|
||||||
[hottub.gs :as gs]
|
[hottub.gs :as gs]
|
||||||
[hottub.resource :as res]
|
[hottub.resource :as res]
|
||||||
[hottub.timeline :as tln]))
|
[hottub.timeline :as tln]
|
||||||
|
[hottub.screen :as scr]))
|
||||||
|
|
||||||
(defn -main [& args]
|
(defn -main [& args]
|
||||||
(res/start-resource-expiry-thread)
|
(res/start-resource-expiry-thread)
|
||||||
(slick/start-game "Test game"
|
(slick/start-game "Test game" {:id :game}))
|
||||||
{:state :game
|
|
||||||
:gs (gs/update-gs gs/gs-empty
|
(defmethod scr/screen-from-spec :game [spec]
|
||||||
(gs/add-index :name)
|
{:gs (gs/update-gs gs/gs-empty
|
||||||
(gs/add-index :type)
|
(gs/add-index :name)
|
||||||
(gs/set-entity (gs/gen-id) {:type :sprite :x 50 :y 50
|
(gs/add-index :type)
|
||||||
:image "res/man.png" :name :man}))}))
|
(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]
|
(defmethod slick/update-game :game [state inputtln delta]
|
||||||
(assoc state :gs (gs/update-gs (:gs state)
|
(assoc state :gs (gs/update-gs (:gs state)
|
||||||
|
@ -26,11 +30,14 @@
|
||||||
(if-let [image (res/get-image (:image sprite))]
|
(if-let [image (res/get-image (:image sprite))]
|
||||||
(.draw image (:x sprite) (:y sprite))))))
|
(.draw image (:x sprite) (:y sprite))))))
|
||||||
|
|
||||||
|
;;; repl helpers
|
||||||
(def ^:dynamic g nil)
|
(def ^:dynamic g nil)
|
||||||
(def ^:dynamic s 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]
|
(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))]
|
(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))))))
|
||||||
|
|
||||||
|
|
39
src/hottub/screen.clj
Normal file
39
src/hottub/screen.clj
Normal file
|
@ -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)))
|
|
@ -8,11 +8,12 @@
|
||||||
[hottub.util :as u]
|
[hottub.util :as u]
|
||||||
[hottub.repl :as repl]
|
[hottub.repl :as repl]
|
||||||
[hottub.resource :as res]
|
[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 update-game (fn [screen input delta] (:id screen)))
|
||||||
(defmulti render-game (fn [state graphics] (:state state)))
|
(defmulti render-game (fn [screen graphics] (:id screen)))
|
||||||
(defmulti eval-with-bindings (fn [state game f] (:state state)))
|
(defmulti eval-with-bindings (fn [screen game f] (:id screen)))
|
||||||
|
|
||||||
(def slick-key-to-key
|
(def slick-key-to-key
|
||||||
{Input/KEY_0 :0
|
{Input/KEY_0 :0
|
||||||
|
@ -119,14 +120,14 @@
|
||||||
:state state
|
:state state
|
||||||
:extends org.newdawn.slick.BasicGame)
|
:extends org.newdawn.slick.BasicGame)
|
||||||
|
|
||||||
(defn game-create [title state]
|
(defn game-create [title screen]
|
||||||
[[title]
|
[[title]
|
||||||
{:state (atom state)
|
{:screen (atom screen)
|
||||||
:repl (repl/repl-create 9999)
|
:repl (repl/repl-create 9999)
|
||||||
:container (atom nil)
|
:container (atom nil)
|
||||||
:input (input-create)}])
|
: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-container [this] @(:container (.state this)))
|
||||||
|
|
||||||
(defn game-install-input [this]
|
(defn game-install-input [this]
|
||||||
|
@ -147,7 +148,7 @@
|
||||||
(game-install-input this)
|
(game-install-input this)
|
||||||
(repl/repl-start
|
(repl/repl-start
|
||||||
(:repl (.state this))
|
(: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]
|
(defn game-update [this container delta]
|
||||||
(doseq [ns-sym (modified-namespaces)]
|
(doseq [ns-sym (modified-namespaces)]
|
||||||
|
@ -158,29 +159,29 @@
|
||||||
(.printStackTrace e))))
|
(.printStackTrace e))))
|
||||||
(repl/repl-update (:repl (.state this)))
|
(repl/repl-update (:repl (.state this)))
|
||||||
(try
|
(try
|
||||||
(if-let [statenew (update-game @(game-state-atom this) (input-timeline-clear! (:input (.state this))) delta)]
|
(if-let [screennew (update-game @(game-screen-atom this) (input-timeline-clear! (:input (.state this))) delta)]
|
||||||
(reset! (game-state-atom this) statenew))
|
(reset! (game-screen-atom this) screennew))
|
||||||
(catch Exception e
|
(catch Exception e
|
||||||
(println "Couldn't update" (:state @(game-state-atom this)))
|
(println "Couldn't update" (:id @(game-screen-atom this)))
|
||||||
(.printStackTrace e))))
|
(.printStackTrace e))))
|
||||||
|
|
||||||
(defn game-render [this container graphics]
|
(defn game-render [this container graphics]
|
||||||
(try
|
(try
|
||||||
(res/gc-expired-resources)
|
(res/gc-expired-resources)
|
||||||
(render-game @(game-state-atom this) graphics)
|
(render-game @(game-screen-atom this) graphics)
|
||||||
(catch Exception e
|
(catch Exception e
|
||||||
(println "Couldn't render" (:state @(game-state-atom this)))
|
(println "Couldn't render" (:id @(game-screen-atom this)))
|
||||||
(.printStackTrace e))))
|
(.printStackTrace e))))
|
||||||
|
|
||||||
(defn game-setstate! [this statenew]
|
(defn game-setscreen! [this screennew]
|
||||||
(reset! (game-state-atom this) statenew))
|
(reset! (game-screen-atom this) screennew))
|
||||||
|
|
||||||
(defmethod update-game :default [state input delta])
|
(defmethod update-game :default [screen input delta])
|
||||||
(defmethod render-game :default [state graphics])
|
(defmethod render-game :default [screen graphics])
|
||||||
(defmethod eval-with-bindings :default [state game f] (f))
|
(defmethod eval-with-bindings :default [screen game f] (f))
|
||||||
|
|
||||||
(defn start-game [title startstate]
|
(defn start-game [title spec]
|
||||||
(let [game (hottub.slick.Game. title startstate)
|
(let [game (hottub.slick.Game. title (scr/goto-screen nil spec))
|
||||||
container (AppGameContainer. game 640 480 false)]
|
container (AppGameContainer. game 640 480 false)]
|
||||||
(.setAlwaysRender container true)
|
(.setAlwaysRender container true)
|
||||||
(.start container)
|
(.start container)
|
||||||
|
|
Loading…
Reference in a new issue