diff --git a/src/play_clj/core.clj b/src/play_clj/core.clj index 69cb90a..4287414 100644 --- a/src/play_clj/core.clj +++ b/src/play_clj/core.clj @@ -1,12 +1,12 @@ (ns play-clj.core (:require [clojure.set :as set] - [play-clj.utils :as utils]) + [play-clj.ui :as ui] + [play-clj.utils :as u]) (:import [com.badlogic.gdx Application Audio Files Game Gdx Graphics Input InputMultiplexer InputProcessor Net Screen] [com.badlogic.gdx.graphics Camera Color GL20 OrthographicCamera PerspectiveCamera Texture] - [com.badlogic.gdx.graphics.g2d Animation BitmapFont SpriteBatch - TextureRegion] + [com.badlogic.gdx.graphics.g2d Animation SpriteBatch TextureRegion] [com.badlogic.gdx.input GestureDetector GestureDetector$GestureListener] [com.badlogic.gdx.maps MapLayer MapLayers] @@ -17,29 +17,12 @@ IsometricStaggeredTiledMapRenderer IsometricTiledMapRenderer OrthogonalTiledMapRenderer] - [com.badlogic.gdx.scenes.scene2d Actor Stage] - [com.badlogic.gdx.scenes.scene2d.ui ButtonGroup CheckBox Dialog - ImageButton ImageTextButton Label Skin Slider TextButton TextField] - [com.badlogic.gdx.scenes.scene2d.utils ActorGestureListener - ChangeListener ClickListener DragListener FocusListener - NinePatchDrawable SpriteDrawable TextureRegionDrawable TiledDrawable])) - -(defmulti create-entity class) - -(defmethod create-entity TextureRegion - [obj] - {:type :image :object obj}) - -(defmethod create-entity Actor - [obj] - {:type :actor :object obj}) + [com.badlogic.gdx.scenes.scene2d Actor Stage])) (load "core_2d") (load "core_deprecated") (load "core_global") -(load "core_interop") (load "core_render") -(load "core_ui") (defn defscreen* [{:keys [on-show on-render on-hide on-pause on-resize on-resume] @@ -56,11 +39,7 @@ (compare-and-set! entities entities-list))))) listeners [(input-processor options execute-fn!) (gesture-detector options execute-fn!)] - ui-listeners [(ui-gesture-listener options execute-fn!) - (ui-change-listener options execute-fn!) - (ui-click-listener options execute-fn!) - (ui-drag-listener options execute-fn!) - (ui-focus-listener options execute-fn!)] + ui-listeners (ui/listeners options execute-fn!) create-renderer-fn! #(swap! screen assoc :renderer (renderer %)) update-fn! #(swap! screen merge %)] {:screen screen @@ -121,3 +100,15 @@ (defn update! [{:keys [update-fn!]} & {:keys [] :as args}] (update-fn! args)) + +(defn listen! + [{:keys [renderer ui-listeners] :as screen} entities] + (assert (isa? (type renderer) Stage)) + (add-input! renderer) + (stage! screen :clear) + (doseq [{:keys [object]} entities] + (when (isa? (type object) Actor) + (stage! screen :add-actor object) + (doseq [listener ui-listeners] + (.addListener ^Actor object listener)))) + entities) diff --git a/src/play_clj/core_2d.clj b/src/play_clj/core_2d.clj index 47b8631..f4e3b69 100644 --- a/src/play_clj/core_2d.clj +++ b/src/play_clj/core_2d.clj @@ -26,7 +26,7 @@ nil)) (.draw object batch 1)) -(defn draw-image! +(defn draw-texture! [^SpriteBatch batch {:keys [^TextureRegion object x y width height]}] (assert (and object x y width height)) (.draw batch object (float x) (float y) (float width) (float height))) @@ -34,12 +34,12 @@ (defn draw-entity! [^SpriteBatch batch entity] (if (not (map? entity)) - (draw-entity! batch (create-entity entity)) + (draw-entity! batch (u/create-entity entity)) (case (:type entity) :actor (draw-actor! batch entity) - :image - (draw-image! batch entity) + :texture + (draw-texture! batch entity) nil))) (defn draw! [{:keys [renderer] :as screen} entities] @@ -53,7 +53,7 @@ ; textures -(defn image* +(defn texture* [img] (cond (string? img) @@ -63,19 +63,25 @@ :else img)) -(defmacro image +(defmacro texture [img & options] - `(create-entity (utils/calls! ^TextureRegion (image* ~img) ~@options))) + `(u/create-entity (u/calls! ^TextureRegion (texture* ~img) ~@options))) (defmacro animation - [duration images & args] + [duration textures & args] `(Animation. ~duration - (utils/gdx-into-array (map :object ~images)) - (utils/gdx-static-field :graphics :g2d :Animation - ~(or (first args) :normal)))) + (u/gdx-into-array (map :object ~textures)) + (u/gdx-static-field :graphics :g2d :Animation + ~(or (first args) :normal)))) -(defn animation-image - ([screen ^Animation animation] - (create-entity (.getKeyFrame animation (:total-time screen) true))) - ([screen ^Animation animation is-looping?] - (create-entity (.getKeyFrame animation (:total-time screen) is-looping?)))) +(defn animation-texture + ([{:keys [total-time]} ^Animation animation] + (u/create-entity (.getKeyFrame animation total-time true))) + ([{:keys [total-time]} ^Animation animation is-looping?] + (u/create-entity (.getKeyFrame animation total-time is-looping?)))) + +; interop + +(defmacro texture! + [entity k & options] + `(u/call! ^TextureRegion (:object ~entity) ~k ~@options)) diff --git a/src/play_clj/core_deprecated.clj b/src/play_clj/core_deprecated.clj index 1cc0429..18d4f23 100644 --- a/src/play_clj/core_deprecated.clj +++ b/src/play_clj/core_deprecated.clj @@ -10,3 +10,7 @@ (defmethod renderer :stage [_] (Stage.)) + +(defmacro label + [& args] + `(ui/label ~@args)) diff --git a/src/play_clj/core_global.clj b/src/play_clj/core_global.clj index 5682ba4..54d4c1b 100644 --- a/src/play_clj/core_global.clj +++ b/src/play_clj/core_global.clj @@ -13,37 +13,62 @@ (defmacro color [& args] `~(if (keyword? (first args)) - `(Color. ^Color (utils/gdx-static-field :graphics :Color ~(first args))) + `(Color. ^Color (u/gdx-static-field :graphics :Color ~(first args))) `(Color. ~@args))) -(defmacro bitmap-font - [& options] - `(BitmapFont. ~@options)) +; interop + +(defmacro app! + [k & options] + `(u/call! ^Application (Gdx/app) ~k ~@options)) + +(defmacro audio! + [k & options] + `(u/call! ^Audio (Gdx/audio) ~k ~@options)) + +(defmacro files! + [k & options] + `(u/call! ^Files (Gdx/files) ~k ~@options)) + +(defmacro gl! + [k & options] + `(u/call! ^GL20 (Gdx/gl20) ~k ~@options)) + +(defmacro graphics! + [k & options] + `(u/call! ^Graphics (Gdx/graphics) ~k ~@options)) + +(defmacro input! + [k & options] + `(u/call! ^Input (Gdx/input) ~k ~@options)) + +(defmacro net! + [k & options] + `(u/call! ^Net (Gdx/net) ~k ~@options)) ; input/output (defn game [key] (case key - :width (.getWidth ^Graphics (Gdx/graphics)) - :height (.getHeight ^Graphics (Gdx/graphics)) - :fps (.getFramesPerSecond ^Graphics (Gdx/graphics)) - :is-fullscreen? (.isFullscreen ^Graphics (Gdx/graphics)) - :is-touched? (.isTouched ^Input (Gdx/input)) - :x (.getX ^Input (Gdx/input)) - :y (.getY ^Input (Gdx/input)) + :width (graphics! :get-width) + :height (graphics! :get-height) + :fps (graphics! :get-frames-per-second) + :is-fullscreen? (graphics! :is-fullscreen) + :is-touched? (input! :is-touched) + :x (input! :get-x) + :y (input! :get-y) nil)) (defmacro key-code [key] - `~(symbol - (str utils/gdx-package ".Input$Keys/" (utils/key->static-field key)))) + `~(symbol (str u/gdx-package ".Input$Keys/" (u/key->static-field key)))) (defmacro is-pressed? [key] - `(.isKeyPressed ^Input (Gdx/input) (key-code ~key))) + `(input! :is-key-pressed (key-code ~key))) -(defn- input-processor +(defn ^:private input-processor [{:keys [on-key-down on-key-typed on-key-up on-mouse-moved on-scrolled on-touch-down on-touch-dragged on-touch-up]} execute-fn!] @@ -73,7 +98,7 @@ (execute-fn! on-touch-up :screen-x sx :screen-y sy :pointer p :button b) false))) -(defn- gesture-listener +(defn ^:private gesture-listener [{:keys [on-fling on-long-press on-pan on-pan-stop on-pinch on-tap on-zoom]} execute-fn!] (reify GestureDetector$GestureListener @@ -103,10 +128,10 @@ (execute-fn! on-zoom :initial-distance id :distance d) false))) -(defn- gesture-detector +(defn ^:private gesture-detector [options execute-fn!] (proxy [GestureDetector] [(gesture-listener options execute-fn!)])) -(defn- add-input! +(defn ^:private add-input! [^InputProcessor p] - (.addProcessor ^InputMultiplexer (.getInputProcessor (Gdx/input)) p)) + (.addProcessor ^InputMultiplexer (input! :get-input-processor) p)) diff --git a/src/play_clj/core_interop.clj b/src/play_clj/core_interop.clj deleted file mode 100644 index 60f3d35..0000000 --- a/src/play_clj/core_interop.clj +++ /dev/null @@ -1,102 +0,0 @@ -(in-ns 'play-clj.core) - -; 2d - -(defmacro image! - [entity k & options] - `(utils/call! ^TextureRegion (:object ~entity) ~k ~@options)) - -; render - -(defmacro orthogonal-tiled-map! - [screen k & options] - `(utils/call! ^OrthogonalTiledMapRenderer (:renderer ~screen) ~k ~@options)) - -(defmacro isometric-tiled-map! - [screen k & options] - `(utils/call! ^IsometricTiledMapRenderer (:renderer ~screen) ~k ~@options)) - -(defmacro isometric-staggered-tiled-map! - [screen k & options] - `(utils/call! ^IsometricStaggeredTiledMapRenderer (:renderer ~screen) - ~k ~@options)) - -(defmacro hexagonal-tiled-map! - [screen k & options] - `(utils/call! ^HexagonalTiledMapRenderer (:renderer ~screen) ~k ~@options)) - -(defmacro stage! - [screen k & options] - `(utils/call! ^Stage (:renderer ~screen) ~k ~@options)) - -(defmacro orthographic-camera! - [screen k & options] - `(utils/call! ^OrthographicCamera (:camera ~screen) ~k ~@options)) - -(defmacro perspective-camera! - [screen k & options] - `(utils/call! ^PerspectiveCamera (:camera ~screen) ~k ~@options)) - -; global - -(defmacro app! - [k & options] - `(utils/call! ^Application (Gdx/app) ~k ~@options)) - -(defmacro audio! - [k & options] - `(utils/call! ^Audio (Gdx/audio) ~k ~@options)) - -(defmacro files! - [k & options] - `(utils/call! ^Files (Gdx/files) ~k ~@options)) - -(defmacro gl! - [k & options] - `(utils/call! ^GL20 (Gdx/gl20) ~k ~@options)) - -(defmacro graphics! - [k & options] - `(utils/call! ^Graphics (Gdx/graphics) ~k ~@options)) - -(defmacro input! - [k & options] - `(utils/call! ^Input (Gdx/input) ~k ~@options)) - -(defmacro net! - [k & options] - `(utils/call! ^Net (Gdx/net) ~k ~@options)) - -; ui - -(defmacro check-box! - [entity k & options] - `(utils/call! ^Checkbox (:object ~entity) ~k ~@options)) - -(defmacro image-button! - [entity k & options] - `(utils/call! ^ImageButton (:object ~entity) ~k ~@options)) - -(defmacro image-text-button! - [entity k & options] - `(utils/call! ^ImageTextButton (:object ~entity) ~k ~@options)) - -(defmacro label! - [entity k & options] - `(utils/call! ^Label (:object ~entity) ~k ~@options)) - -(defmacro slider! - [entity k & options] - `(utils/call! ^Slider (:object ~entity) ~k ~@options)) - -(defmacro text-button! - [entity k & options] - `(utils/call! ^TextButton (:object ~entity) ~k ~@options)) - -(defmacro text-field! - [entity k & options] - `(utils/call! ^TextField (:object ~entity) ~k ~@options)) - -(defmacro dialog! - [entity k & options] - `(utils/call! ^Dialog (:object ~entity) ~k ~@options)) diff --git a/src/play_clj/core_render.clj b/src/play_clj/core_render.clj index e189e9f..b1f89b7 100644 --- a/src/play_clj/core_render.clj +++ b/src/play_clj/core_render.clj @@ -91,3 +91,34 @@ (when x (set! (. (. camera position) x) x)) (when y (set! (. (. camera position) y) y)) (.update camera)) + +; interop + +(defmacro orthogonal-tiled-map! + [screen k & options] + `(u/call! ^OrthogonalTiledMapRenderer (:renderer ~screen) ~k ~@options)) + +(defmacro isometric-tiled-map! + [screen k & options] + `(u/call! ^IsometricTiledMapRenderer (:renderer ~screen) ~k ~@options)) + +(defmacro isometric-staggered-tiled-map! + [screen k & options] + `(u/call! ^IsometricStaggeredTiledMapRenderer (:renderer ~screen) + ~k ~@options)) + +(defmacro hexagonal-tiled-map! + [screen k & options] + `(u/call! ^HexagonalTiledMapRenderer (:renderer ~screen) ~k ~@options)) + +(defmacro stage! + [screen k & options] + `(u/call! ^Stage (:renderer ~screen) ~k ~@options)) + +(defmacro orthographic-camera! + [screen k & options] + `(u/call! ^OrthographicCamera (:camera ~screen) ~k ~@options)) + +(defmacro perspective-camera! + [screen k & options] + `(u/call! ^PerspectiveCamera (:camera ~screen) ~k ~@options)) diff --git a/src/play_clj/core_ui.clj b/src/play_clj/ui.clj similarity index 57% rename from src/play_clj/core_ui.clj rename to src/play_clj/ui.clj index 4abfbec..545e4ec 100644 --- a/src/play_clj/core_ui.clj +++ b/src/play_clj/ui.clj @@ -1,21 +1,36 @@ -(in-ns 'play-clj.core) - -(defmacro style - [type & options] - `(~(symbol (str utils/gdx-package ".scenes.scene2d.ui." - (utils/key->class type) "$" - (utils/key->class type) "Style.")) - ~@options)) +(ns play-clj.ui + (:require [play-clj.utils :as u]) + (:import [com.badlogic.gdx Files Gdx] + [com.badlogic.gdx.graphics Color Texture] + [com.badlogic.gdx.graphics.g2d BitmapFont TextureRegion] + [com.badlogic.gdx.scenes.scene2d Actor Stage] + [com.badlogic.gdx.scenes.scene2d.ui ButtonGroup CheckBox Dialog Image + ImageButton ImageTextButton Label Skin Slider TextButton TextField] + [com.badlogic.gdx.scenes.scene2d.utils ActorGestureListener + ChangeListener ClickListener DragListener FocusListener + NinePatchDrawable SpriteDrawable TextureRegionDrawable + TiledDrawable])) (defmacro drawable [type & options] - `(~(symbol (str utils/gdx-package ".scenes.scene2d.utils." - (utils/key->class type) "Drawable.")) + `(~(symbol (str u/gdx-package ".scenes.scene2d.u." + (u/key->class type) "Drawable.")) + ~@options)) + +(defmacro bitmap-font + [& options] + `(BitmapFont. ~@options)) + +(defmacro style + [type & options] + `(~(symbol (str u/gdx-package ".scenes.scene2d.ui." + (u/key->class type) "$" + (u/key->class type) "Style.")) ~@options)) (defmacro skin [path & options] - `(utils/calls! ^Skin (Skin. (files! :internal ~path)) ~@options)) + `(u/calls! ^Skin (Skin. (.internal ^Files (Gdx/files) ~path)) ~@options)) ; widgets @@ -25,7 +40,21 @@ (defmacro check-box [text arg & options] - `(create-entity (utils/calls! ^CheckBox (check-box* ~text ~arg) ~@options))) + `(u/create-entity (u/calls! ^CheckBox (check-box* ~text ~arg) ~@options))) + +(defn image* + [arg] + (cond + (map? arg) + (Image. ^TextureRegion (:object arg)) + (string? arg) + (Image. (Texture. arg)) + :else + (Image. arg))) + +(defmacro image + [arg & options] + `(u/create-entity (u/calls! ^Image (image* ~arg) ~@options))) (defn image-button* [arg] @@ -33,7 +62,7 @@ (defmacro image-button [arg & options] - `(create-entity (utils/calls! ^ImageButton (image-button* ~arg) ~@options))) + `(u/create-entity (u/calls! ^ImageButton (image-button* ~arg) ~@options))) (defn image-text-button* [^String text arg] @@ -41,8 +70,8 @@ (defmacro image-text-button [text arg & options] - `(create-entity - (utils/calls! ^ImageTextButton (image-text-button* ~text ~arg) ~@options))) + `(u/create-entity (u/calls! ^ImageTextButton (image-text-button* ~text ~arg) + ~@options))) (defn label* [^String text arg] @@ -52,7 +81,7 @@ (defmacro label [text arg & options] - `(create-entity (utils/calls! ^Label (label* ~text ~arg) ~@options))) + `(u/create-entity (u/calls! ^Label (label* ~text ~arg) ~@options))) (defn slider* [min max step is-vert? arg] @@ -60,8 +89,8 @@ (defmacro slider [min max step is-vert? arg & options] - `(create-entity - (utils/calls! ^Slider (slider* ~min ~max ~step ~is-vert? ~arg) ~@options))) + `(u/create-entity (u/calls! ^Slider (slider* ~min ~max ~step ~is-vert? ~arg) + ~@options))) (defn text-button* [^String text arg] @@ -69,8 +98,7 @@ (defmacro text-button [text arg & options] - `(create-entity - (utils/calls! ^TextButton (text-button* ~text ~arg) ~@options))) + `(u/create-entity (u/calls! ^TextButton (text-button* ~text ~arg) ~@options))) (defn text-field* [^String text arg] @@ -78,7 +106,7 @@ (defmacro text-field [text arg & options] - `(create-entity (utils/calls! ^TextField (text-field* ~text ~arg) ~@options))) + `(u/create-entity (u/calls! ^TextField (text-field* ~text ~arg) ~@options))) (defn dialog* [text arg] @@ -86,23 +114,11 @@ (defmacro dialog [text arg & options] - `(create-entity (utils/calls! ^Dialog (dialog* ~text ~arg) ~@options))) + `(u/create-entity (u/calls! ^Dialog (dialog* ~text ~arg) ~@options))) ; listeners -(defn ui-listen! - [{:keys [renderer ui-listeners] :as screen} entities] - (assert (isa? (type renderer) Stage)) - (add-input! renderer) - (stage! screen :clear) - (doseq [{:keys [object]} entities] - (when (isa? (type object) Actor) - (stage! screen :add-actor object) - (doseq [listener ui-listeners] - (.addListener ^Actor object listener)))) - entities) - -(defn- ui-gesture-listener +(defn ^:private gesture-listener [{:keys [on-ui-fling on-ui-long-press on-ui-pan on-ui-pinch on-ui-tap on-ui-touch-down on-ui-touch-up on-ui-zoom]} execute-fn!] @@ -128,13 +144,13 @@ (zoom [e id d] (execute-fn! on-ui-zoom :event e :initial-distance id :distance d)))) -(defn- ui-change-listener +(defn ^:private change-listener [{:keys [on-ui-changed]} execute-fn!] (proxy [ChangeListener] [] (changed [e a] (execute-fn! on-ui-changed :event e :actor a)))) -(defn- ui-click-listener +(defn ^:private click-listener [{:keys [on-ui-clicked on-ui-enter on-ui-exit on-ui-touch-down on-ui-touch-dragged on-ui-touch-up]} execute-fn!] @@ -153,7 +169,7 @@ (touchUp [e x y p b] (execute-fn! on-ui-touch-up :event e :x x :y y :pointer p :button b)))) -(defn- ui-drag-listener +(defn ^:private drag-listener [{:keys [on-ui-drag on-ui-drag-start on-ui-drag-stop on-ui-touch-down on-ui-touch-dragged on-ui-touch-up]} execute-fn!] @@ -172,7 +188,7 @@ (dragStop [e x y p] (execute-fn! on-ui-drag-stop :event e :x x :y y :pointer p)))) -(defn- ui-focus-listener +(defn ^:private focus-listener [{:keys [on-ui-keyboard-focus-changed on-ui-scroll-focus-changed]} execute-fn!] (proxy [FocusListener] [] @@ -180,3 +196,45 @@ (execute-fn! on-ui-keyboard-focus-changed :event e :actor a :focused? f)) (scrollFocusChanged [e a f] (execute-fn! on-ui-scroll-focus-changed :event e :actor a :focused? f)))) + +(defn listeners + [options execute-fn!] + [(gesture-listener options execute-fn!) + (change-listener options execute-fn!) + (click-listener options execute-fn!) + (drag-listener options execute-fn!) + (focus-listener options execute-fn!)]) + +; interop + +(defmacro check-box! + [entity k & options] + `(u/call! ^Checkbox (:object ~entity) ~k ~@options)) + +(defmacro image-button! + [entity k & options] + `(u/call! ^ImageButton (:object ~entity) ~k ~@options)) + +(defmacro image-text-button! + [entity k & options] + `(u/call! ^ImageTextButton (:object ~entity) ~k ~@options)) + +(defmacro label! + [entity k & options] + `(u/call! ^Label (:object ~entity) ~k ~@options)) + +(defmacro slider! + [entity k & options] + `(u/call! ^Slider (:object ~entity) ~k ~@options)) + +(defmacro text-button! + [entity k & options] + `(u/call! ^TextButton (:object ~entity) ~k ~@options)) + +(defmacro text-field! + [entity k & options] + `(u/call! ^TextField (:object ~entity) ~k ~@options)) + +(defmacro dialog! + [entity k & options] + `(u/call! ^Dialog (:object ~entity) ~k ~@options)) diff --git a/src/play_clj/utils.clj b/src/play_clj/utils.clj index 7ae8987..7a4a12a 100644 --- a/src/play_clj/utils.clj +++ b/src/play_clj/utils.clj @@ -1,14 +1,16 @@ (ns play-clj.utils (:require [clojure.string :as s]) - (:import [com.badlogic.gdx.utils Array])) + (:import [com.badlogic.gdx.graphics.g2d TextureRegion] + [com.badlogic.gdx.utils Array] + [com.badlogic.gdx.scenes.scene2d Actor])) (def ^:const gdx-package "com.badlogic.gdx") -(defn- split-key +(defn ^:private split-key [key] (-> key name (s/split #"-"))) -(defn- join-keys +(defn ^:private join-keys [keys] (->> keys (map name) (s/join ".") (str gdx-package "."))) @@ -61,3 +63,13 @@ (defmacro calls! [obj & {:keys [] :as args}] `(doto ~obj ~@(map calls!* args))) + +(defmulti create-entity class) + +(defmethod create-entity TextureRegion + [obj] + {:type :texture :object obj}) + +(defmethod create-entity Actor + [obj] + {:type :actor :object obj})