Store the tilemap along with the tile, introduce layers, update-as-> macro
This commit is contained in:
parent
45ef9f3cda
commit
a9424226ba
174
src/game.clj
174
src/game.clj
@ -17,6 +17,7 @@
|
|||||||
(def ^:const grid-len (* rows cols))
|
(def ^:const grid-len (* rows cols))
|
||||||
|
|
||||||
(def scale 4.0)
|
(def scale 4.0)
|
||||||
|
(def num-layers 5)
|
||||||
|
|
||||||
(set! *warn-on-reflection* true)
|
(set! *warn-on-reflection* true)
|
||||||
;; (set! *unchecked-math* :warn-on-boxed)
|
;; (set! *unchecked-math* :warn-on-boxed)
|
||||||
@ -34,22 +35,33 @@
|
|||||||
t)))
|
t)))
|
||||||
|
|
||||||
(defn idx [row col] (+ (* row cols) col))
|
(defn idx [row col] (+ (* row cols) col))
|
||||||
(defn tile-at [game r c] (aget ^objects (:grid game) (idx r c)))
|
(defn tile-at [game layer r c] (aget ^objects (get (:layers game) layer) (idx r c)))
|
||||||
(defn tile-at-idx [game idx] (aget ^objects (:grid game) idx))
|
(defn tile-at-idx [game layer idx] (aget ^objects (get (:layers game) layer) idx))
|
||||||
(defn set-tile! [game r c tile] (aset ^objects (:grid game) (idx r c) tile))
|
(defn set-tile! [game layer r c tile] (aset ^objects (get (:layers game) layer) (idx r c) tile))
|
||||||
|
(defn cell-at-mouse-pos [game]
|
||||||
|
(let [{mx :x my :y} (rl/get-mouse-position)
|
||||||
|
row (quot my (* cell-size scale))
|
||||||
|
col (quot mx (* cell-size scale))]
|
||||||
|
[row col]))
|
||||||
|
|
||||||
(defn init-game [config]
|
(defn init-game [config]
|
||||||
(let [tileset-path "./source-assets/Sprout Lands Premium/Tilesets/ground tiles/New tiles/"]
|
(let [tileset-path "./source-assets/Sprout Lands Premium/Tilesets/ground tiles/New tiles/"]
|
||||||
{:editor-mode false
|
{:editor-mode false
|
||||||
:color-idx 0
|
:color-idx 0
|
||||||
;; :event-queue []
|
;; :event-queue []
|
||||||
;; TODO: Once we have a proper ID system for the cells, use int-array for performance
|
;; TODO: Once we have a proper ID system for the cells, use int-array for performance
|
||||||
:grid (object-array (* rows cols))
|
:layers (vec (repeatedly num-layers #(object-array (* rows cols))))
|
||||||
;; TODO: When we cannot find the image, no errors are being reported. Likely because raylib is failing silently
|
:current-layer 0
|
||||||
:tilemaps
|
:current-tilemap 0
|
||||||
|
;; TODO: When we cannot find the image, no errors are being reported. Likely because raylib is failing silently
|
||||||
|
;; TODO: How do we get Raylib to reload images on the fly
|
||||||
|
:tilemaps
|
||||||
{:grass-hill (load-texture-once (str tileset-path "Grass_Hill_Tiles_v2.png"))
|
{:grass-hill (load-texture-once (str tileset-path "Grass_Hill_Tiles_v2.png"))
|
||||||
:grass-stone (load-texture-once (str tileset-path "Darker_Grass_Tiles_v2.png"))
|
:grass-stone (load-texture-once (str tileset-path "Darker_Grass_Tiles_v2.png"))
|
||||||
#_#_:bush (load-texture-once "/home/joe/Downloads/Try1.png")}}))
|
;; :soil (load-texture-once (str tileset-path "Soil_Ground_HiIls_Tiles.png"))
|
||||||
|
:soil (load-texture-once (str tileset-path "Soil_Ground_Tiles.png"))
|
||||||
|
:grass-top (load-texture-once (str tileset-path "Grass_Tile_Layers.png"))
|
||||||
|
#_#_:bush (load-texture-once "/home/joe/Downloads/Try1.png")}}))
|
||||||
|
|
||||||
(def edge-set
|
(def edge-set
|
||||||
{0 [3 3],
|
{0 [3 3],
|
||||||
@ -130,112 +142,120 @@
|
|||||||
(not (and (bit-test m 2) (bit-test m 3))) (bit-clear 7)))
|
(not (and (bit-test m 2) (bit-test m 3))) (bit-clear 7)))
|
||||||
|
|
||||||
;; TODO: Is this working? Diagonals don't seem to be working
|
;; TODO: Is this working? Diagonals don't seem to be working
|
||||||
(defn surrounding-tiles [game at-row at-col]
|
(defn tile-bitset [game layer at-row at-col]
|
||||||
(normalize-mask
|
(normalize-mask
|
||||||
(reduce-kv (fn [acc i [_ [dy dx]]]
|
(reduce-kv (fn [acc i [_ [dy dx]]]
|
||||||
(let [r (+ at-row dy)
|
(let [r (+ at-row dy)
|
||||||
c (+ at-col dx)]
|
c (+ at-col dx)]
|
||||||
(if (and (>= r 0) (>= c 0)
|
(if (and (>= r 0) (>= c 0)
|
||||||
(tile-at game r c))
|
(tile-at game layer r c))
|
||||||
(bit-set acc i)
|
(bit-set acc i)
|
||||||
acc)))
|
acc)))
|
||||||
0
|
0
|
||||||
directions)))
|
directions)))
|
||||||
|
|
||||||
(defn do-neighbors! [row col do-fn]
|
(defn do-neighbors! [layer row col do-fn]
|
||||||
(doseq [[_ [dy dx]] directions
|
(doseq [[_ [dy dx]] directions
|
||||||
:let [r (+ row dy)
|
:let [r (+ row dy)
|
||||||
c (+ col dx)]]
|
c (+ col dx)]]
|
||||||
(when (and (< -1 r rows) (< -1 c cols))
|
(when (and (< -1 r rows) (< -1 c cols))
|
||||||
(do-fn r c))))
|
(do-fn layer r c))))
|
||||||
|
|
||||||
;; rows ;; => 80
|
(defn set-random-tile! [game layer row col]
|
||||||
;; cols ;; => 39
|
(let [tile (edge-set (tile-bitset game layer row col))
|
||||||
;; grid-len ;; => 3120
|
tilemap (second (get (vec (:tilemaps game)) (:current-tilemap game)))]
|
||||||
|
|
||||||
(defn set-random-tile! [game row col]
|
|
||||||
(let [tile (edge-set (surrounding-tiles game row col))]
|
|
||||||
(if (vector? tile)
|
(if (vector? tile)
|
||||||
(set-tile! game row col tile)
|
(set-tile! game layer row col [tilemap tile])
|
||||||
;; It's a map, should have the ratios
|
(set-tile! game layer row col
|
||||||
(set-tile! game row col
|
|
||||||
(reduce (fn [acc [tile weight]]
|
(reduce (fn [acc [tile weight]]
|
||||||
(if (< acc weight) (reduced tile) (- acc weight)))
|
(if (< acc weight) (reduced [tilemap tile]) (- acc weight)))
|
||||||
(rand (reduce + (vals tile)))
|
(rand (reduce + (vals tile)))
|
||||||
tile)))))
|
tile)))))
|
||||||
|
|
||||||
(defn auto-tile! [game at-row at-col]
|
(defn auto-tile! [game layer at-row at-col]
|
||||||
(set-random-tile! game at-row at-col)
|
(set-random-tile! game layer at-row at-col)
|
||||||
(do-neighbors! at-row at-col
|
(do-neighbors! layer at-row at-col
|
||||||
(fn [r c]
|
(fn [l r c]
|
||||||
(when (tile-at game r c)
|
(when (tile-at game l r c)
|
||||||
|
|
||||||
(defn delete-tile! [game at-row at-col]
|
(defn delete-tile! [game layer at-row at-col]
|
||||||
(set-tile! game at-row at-col nil)
|
(set-tile! game layer at-row at-col nil)
|
||||||
(do-neighbors! at-row at-col
|
(do-neighbors! layer at-row at-col
|
||||||
(fn [r c]
|
(fn [l r c]
|
||||||
(when (tile-at game r c)
|
(when (tile-at game l r c)
|
||||||
(set-random-tile! game r c)))))
|
(set-random-tile! game l r c)))))
|
||||||
(set-random-tile! game r c)))))
|
(set-random-tile! game l r c)))))
|
||||||
|
|
||||||
(defn handle-game-input [config game]
|
(defn handle-game-input [config game]
|
||||||
(let [game (assoc game :event-queue [])
|
(update-as-> [game game]
|
||||||
game (cond-> game
|
(assoc g :event-queue [])
|
||||||
(rl/key-pressed? rl/key-space)
|
|
||||||
(update :editor-mode not)
|
|
||||||
|
|
||||||
(rl/key-pressed? rl/key-r)
|
(cond-> g
|
||||||
(assoc :grid (object-array (* rows cols)))
|
(rl/key-pressed? rl/key-space)
|
||||||
|
(update :editor-mode not)
|
||||||
|
|
||||||
(rl/mouse-button-pressed? rl/mouse-button-left)
|
;; (rl/key-pressed? rl/key-r)
|
||||||
(assoc :drag-mode :draw)
|
;; (assoc :layers (object-array (* rows cols)))
|
||||||
|
|
||||||
(rl/mouse-button-pressed? rl/mouse-button-right)
|
(rl/mouse-button-pressed? rl/mouse-button-left)
|
||||||
(assoc :drag-mode :erase)
|
(assoc :drag-mode :draw)
|
||||||
|
|
||||||
|
(rl/mouse-button-pressed? rl/mouse-button-right)
|
||||||
|
(assoc :drag-mode :erase)
|
||||||
|
|
||||||
|
(or (rl/mouse-button-released? rl/mouse-button-left)
|
||||||
|
(rl/mouse-button-released? rl/mouse-button-right))
|
||||||
|
(dissoc :drag-mode))
|
||||||
|
|
||||||
(or (rl/mouse-button-released? rl/mouse-button-left)
|
|
||||||
(rl/mouse-button-released? rl/mouse-button-right))
|
|
||||||
(dissoc :drag-mode))
|
|
||||||
game (reduce (fn [g i]
|
|
||||||
(if (rl/key-pressed? (get rl/num-keys i))
|
|
||||||
(reduced (assoc game :active-texture-idx i))
|
|
||||||
game))
|
|
||||||
game
|
|
||||||
(range 1 (inc (count (:tilemaps game)))))]
|
|
||||||
(when (rl/mouse-button-pressed? rl/mouse-button-middle)
|
(when (rl/mouse-button-pressed? rl/mouse-button-middle)
|
||||||
(do-grid [r 10 c 20]
|
(do-grid [r 10 c 20]
|
||||||
(auto-tile! game r c)))
|
(auto-tile! g r c)))
|
||||||
game))
|
|
||||||
|
(reduce (fn [g i]
|
||||||
|
(cond
|
||||||
|
(and (rl/key-pressed? (get rl/num-keys i))
|
||||||
|
(rl/key-down? rl/key-left-shift))
|
||||||
|
(reduced (assoc g :current-tilemap (dec i)))
|
||||||
|
|
||||||
|
(rl/key-pressed? (get rl/num-keys i))
|
||||||
|
(reduced (assoc g :current-layer (dec i)))
|
||||||
|
|
||||||
|
:else
|
||||||
|
g))
|
||||||
|
g
|
||||||
|
(range 1 (inc num-layers)))))
|
||||||
|
|
||||||
(defn update-game [config game]
|
(defn update-game [config game]
|
||||||
(when-let [mode (:drag-mode game)]
|
(update-as-> [g game]
|
||||||
(let [{mx :x my :y} (rl/get-mouse-position)
|
(when-let [mode (:drag-mode game)]
|
||||||
row (quot my (* cell-size scale))
|
(let [{mx :x my :y} (rl/get-mouse-position)
|
||||||
col (quot mx (* cell-size scale))
|
row (quot my (* cell-size scale))
|
||||||
existing (tile-at game row col)]
|
col (quot mx (* cell-size scale))
|
||||||
(when (and existing (= mode :erase))
|
existing (tile-at game (:current-layer game) row col)]
|
||||||
(delete-tile! game row col))
|
(when (and existing (= mode :erase))
|
||||||
(when (and (not existing) (= mode :draw))
|
(delete-tile! game (:current-layer game) row col))
|
||||||
(auto-tile! game row col))))
|
(when (and (= mode :draw)
|
||||||
game)
|
(not= (cell-at-mouse-pos game) (:last-filled-cell game)))
|
||||||
|
(auto-tile! game (:current-layer game) row col)
|
||||||
|
(assoc game :last-filled-cell [row col]))))))
|
||||||
|
|
||||||
(defn draw-tile! [game row-idx col-idx x y scale]
|
(defn draw-tile! [game tilemap row-idx col-idx x y scale]
|
||||||
(let [src-rect (rl/rect-seg (* col-idx cell-size) (* row-idx cell-size) cell-size cell-size)
|
(let [src-rect (rl/rect-seg (* col-idx cell-size) (* row-idx cell-size) cell-size cell-size)
|
||||||
dst-x (* (quot x (* cell-size scale)) cell-size scale)
|
dst-x (* (quot x (* cell-size scale)) cell-size scale)
|
||||||
dst-y (* (quot y (* cell-size scale)) cell-size scale)
|
dst-y (* (quot y (* cell-size scale)) cell-size scale)
|
||||||
dst-rect (rl/rect-seg dst-x dst-y (* cell-size scale) (* cell-size scale))]
|
dst-rect (rl/rect-seg dst-x dst-y (* cell-size scale) (* cell-size scale))]
|
||||||
(rl/draw-texture-pro!* (:seg (get (vec (vals (:tilemaps game)))
|
(rl/draw-texture-pro!* (:seg tilemap) src-rect dst-rect (rl/vec2-seg 0 0) (float 0.0) rl/white)))
|
||||||
(dec (or (:active-texture-idx game) 1))))
|
|
||||||
src-rect dst-rect (rl/vec2-seg 0 0) (float 0.0) rl/white)))
|
|
||||||
|
|
||||||
(defn draw-game [config game]
|
(defn draw-game [config game]
|
||||||
(rl/clear-background!* color-ground)
|
(rl/clear-background!* color-ground)
|
||||||
(do-grid [row rows col cols]
|
(dotimes [layer num-layers]
|
||||||
(when-let [[tx ty] (tile-at game row col)]
|
(do-grid [row rows col cols]
|
||||||
(draw-tile! game tx ty (* col cell-size scale) (* row cell-size scale) scale)))
|
;; TODO: tile-at needs to return layer + row + col, so that's the data structure we need to save
|
||||||
|
(when-let [[tilemap [tx ty]] (tile-at game layer row col)]
|
||||||
|
(draw-tile! game tilemap tx ty (* col cell-size scale) (* row cell-size scale) scale))))
|
||||||
(when (not (contains? game :draw-drag))
|
(when (not (contains? game :draw-drag))
|
||||||
(let [{mx :x my :y :as mouse-pos} (rl/get-mouse-position)]
|
(let [{mx :x my :y :as mouse-pos} (rl/get-mouse-position)]
|
||||||
(draw-tile! game 3 3 mx my scale)))
|
(draw-tile! game (get (:tilemaps game) :grass-hill) 3 3 mx my scale)))
|
||||||
#_(rl/draw-texture-pro!* (:seg (:bush (:tilemaps game)))
|
#_(rl/draw-texture-pro!* (:seg (:bush (:tilemaps game)))
|
||||||
(rl/rect-seg 0 0 54 35)
|
(rl/rect-seg 0 0 54 35)
|
||||||
(rl/rect-seg 600 180 (* 54 2) (* 35 2))
|
(rl/rect-seg 600 180 (* 54 2) (* 35 2))
|
||||||
@ -251,7 +271,7 @@
|
|||||||
(rl/draw-text!* "EDIT MODE" (- screen-width 100) 10 16 rl/green)))
|
(rl/draw-text!* "EDIT MODE" (- screen-width 100) 10 16 rl/green)))
|
||||||
|
|
||||||
(defn watch-game [config game]
|
(defn watch-game [config game]
|
||||||
{:active-texture-idx (:active-texture-idx game)})
|
{})
|
||||||
|
|
||||||
(defn unload-game [game]
|
(defn unload-game [game]
|
||||||
(doseq [[_ tex] (:tilemaps game)]
|
(doseq [[_ tex] (:tilemaps game)]
|
||||||
@ -276,5 +296,5 @@
|
|||||||
(reset! @#'engine/game-state (init-game {}))
|
(reset! @#'engine/game-state (init-game {}))
|
||||||
(swap! @#'engine/game-state :assoc {})
|
(swap! @#'engine/game-state :assoc {})
|
||||||
|
|
||||||
(set-tile! @@#'engine/game-state 1 1 [2 2])
|
#_(set-tile! @@#'engine/game-state 1 1 [2 2])
|
||||||
:-)
|
:-)
|
||||||
|
|||||||
@ -191,6 +191,8 @@
|
|||||||
(defcfn get-fps "GetFPS" [] ::mem/int)
|
(defcfn get-fps "GetFPS" [] ::mem/int)
|
||||||
|
|
||||||
(defcfn key-pressed? "IsKeyPressed" [::mem/int] ::bool)
|
(defcfn key-pressed? "IsKeyPressed" [::mem/int] ::bool)
|
||||||
|
(defcfn key-down? "IsKeyDown" [::mem/int] ::bool)
|
||||||
|
(defcfn key-released? "IsKeyPressed" [::mem/int] ::bool)
|
||||||
(defcfn mouse-button-down? "IsMouseButtonDown" [::mem/int] ::bool)
|
(defcfn mouse-button-down? "IsMouseButtonDown" [::mem/int] ::bool)
|
||||||
(defcfn mouse-button-pressed? "IsMouseButtonPressed" [::mem/int] ::bool)
|
(defcfn mouse-button-pressed? "IsMouseButtonPressed" [::mem/int] ::bool)
|
||||||
(defcfn mouse-button-released? "IsMouseButtonReleased" [::mem/int] ::bool)
|
(defcfn mouse-button-released? "IsMouseButtonReleased" [::mem/int] ::bool)
|
||||||
|
|||||||
@ -4,3 +4,11 @@
|
|||||||
`(dotimes [~r ~rows]
|
`(dotimes [~r ~rows]
|
||||||
(dotimes [~c ~cols]
|
(dotimes [~c ~cols]
|
||||||
~@body)))
|
~@body)))
|
||||||
|
|
||||||
|
(defmacro update-as->
|
||||||
|
{:style/indent 1}
|
||||||
|
[[sym init] & body]
|
||||||
|
(let [g (gensym "game")]
|
||||||
|
`(let [~g ~init
|
||||||
|
~@(mapcat (fn [form] [g `(let [~sym ~g] (or ~form ~g))]) body)]
|
||||||
|
~g)))
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user