Tilemap blob functionality

This commit is contained in:
Joseph Ferano 2026-08-24 22:40:26 +07:00
parent f16ed0cfb4
commit 9796d9e38a
3 changed files with 213 additions and 66 deletions

View File

@ -34,6 +34,7 @@
(define-key m (kbd "C-c g r") #'clj-game-run-main) (define-key m (kbd "C-c g r") #'clj-game-run-main)
(define-key m (kbd "C-c g e") #'clj-game-clear-error) (define-key m (kbd "C-c g e") #'clj-game-clear-error)
(define-key m (kbd "C-c g c") #'clj-game-reload-config) (define-key m (kbd "C-c g c") #'clj-game-reload-config)
;; (define-key m (kbd "C-c g s") #'clj-game-reload-config)
(define-key m (kbd "C-c g x") #'clj-game-throw-last-error) (define-key m (kbd "C-c g x") #'clj-game-throw-last-error)
m))) m)))

View File

@ -5,15 +5,17 @@
[watch :as w] [watch :as w]
[rl :as rl])) [rl :as rl]))
;; (def ^:const screen-width 1280) (def ^:const screen-width 1280)
;; (def ^:const screen-height 630) (def ^:const screen-height 630)
(def ^:const screen-width 970) ;; (def ^:const screen-width 970)
(def ^:const screen-height 530) ;; (def ^:const screen-height 530)
(def ^:const cell-size 16) (def ^:const cell-size 16)
(def ^:const rows (quot screen-width cell-size)) (def ^:const rows (quot screen-width cell-size))
(def ^:const cols (quot screen-height cell-size)) (def ^:const cols (quot screen-height cell-size))
(def ^:const grid-len (* rows cols)) (def ^:const grid-len (* rows cols))
(def scale 4.0)
(set! *warn-on-reflection* true) (set! *warn-on-reflection* true)
;; (set! *unchecked-math* :warn-on-boxed) ;; (set! *unchecked-math* :warn-on-boxed)
@ -42,75 +44,126 @@
:grid (object-array (* rows cols)) :grid (object-array (* rows cols))
:texture (load-texture-once "source-assets/Sprout Lands - Sprites - premium pack/Sprout Lands - Sprites - premium pack/Tilesets/ground tiles/New tiles/Grass_Hill_Tiles_v2.png")}) :texture (load-texture-once "source-assets/Sprout Lands - Sprites - premium pack/Sprout Lands - Sprites - premium pack/Tilesets/ground tiles/New tiles/Grass_Hill_Tiles_v2.png")})
(def tilemap-bitmask (def edge-set
{[0 0] :NW {0 [3 3],
[0 1] :N 70 [0 0],
[0 2] :NW 7 [4 4],
[1 0] :W 59 [2 1],
[1 1] :C 175 [4 5],
[1 2] :E 27 [3 6],
[2 0] :SW 1 [2 3],
[2 1] :S 206 [0 1],
[2 2] :SE}) 239 [2 5],
4 [0 3],
95 [4 6],
141 [2 7],
15 [4 8],
159 [1 9],
31 [3 9],
223 [2 6],
13 [4 7],
191 [1 5],
143 [2 10],
41 [2 2],
43 [3 5],
6 [0 4],
111 [0 9],
3 [3 4],
12 [0 7],
2 [3 0],
142 [0 5],
23 [1 4],
47 [3 10],
127 [1 6],
19 [2 0],
11 [3 8],
255 [6 5],
9 [3 7],
5 [1 3],
14 [0 8],
45 [1 7],
78 [0 6],
140 [0 2],
79 [2 9],
173 [1 2],
87 [1 0],
207 [2 8],
10 [3 1],
71 [2 4],
63 [1 8],
8 [3 2]})
(def tilemap-bitmask (def directions
{[0 0 0 [[:N [-1 0]]
0 0 1 [:E [0 1]]
0 1 1] :NW [:S [1 0]]
[0 0 0 [:W [0 -1]]
1 0 1 [:NE [-1 1]]
1 1 1] :N [:NW [-1 -1]]
[0 0 0 [:SE [1 1]]
1 0 0 [:SW [1 -1]]])
1 1 0] :NE
[0 1 1 (defn normalize-mask [m]
0 0 1 (cond-> m
0 1 1] :W (not (and (bit-test m 0) (bit-test m 1))) (bit-clear 4) ; NE needs N+E
[1 1 0 (not (and (bit-test m 0) (bit-test m 3))) (bit-clear 5) ; NW needs N+W
1 0 0 (not (and (bit-test m 2) (bit-test m 1))) (bit-clear 6) ; SE needs S+E
1 1 0] :E (not (and (bit-test m 2) (bit-test m 3))) (bit-clear 7))) ; SW needs S+W
[0 1 1
0 0 1
0 0 0] :SW
[1 1 1
1 0 1
0 0 0] :S
[1 1 0
1 0 0
0 0 0] :SE})
(defn surrounding-tiles [game at-row at-col] (defn surrounding-tiles [game at-row at-col]
(let [idx (idx at-row at-col)] (normalize-mask
(persistent! (reduce-kv (fn [acc i [_ [dy dx]]]
(reduce (fn [acc num] (if (tile-at game (+ at-row dy) (+ at-col dx))
(let [cell-idx (+ idx num)] (bit-set acc i)
(println cell-idx) acc))
(if (or (< cell-idx 0) 0
(>= cell-idx 9 #_grid-len) directions)))
(= num 0))
(conj! acc 0)
(conj! acc (if (tile-at-idx game cell-idx)
1
0)))))
(transient [])
(range -4 5)))))
(defn auto-tile []) (defn auto-tile! [game at-row at-col]
(let [me (surrounding-tiles game at-row at-col)
north (tile-at game (dec at-row) at-col)
south (tile-at game (inc at-row) at-col)
west (tile-at game at-row (dec at-col))
east (tile-at game at-row (inc at-col))
tile (edge-set me)]
(println me tile)
(set-tile! game at-row at-col tile)
(when north
(set-tile! game (dec at-row) at-col (edge-set (surrounding-tiles game (dec at-row) at-col))))
(when south
(set-tile! game (inc at-row) at-col (edge-set (surrounding-tiles game (inc at-row) at-col))))
(when west
(set-tile! game at-row (dec at-col) (edge-set (surrounding-tiles game at-row (dec at-col)))))
(when east
(set-tile! game at-row (inc at-col) (edge-set (surrounding-tiles game at-row (inc at-col)))))))
(defn handle-game-input [config game] (defn handle-game-input [config game]
(let [game (assoc game :event-queue [])] (let [game (assoc game :event-queue [])]
(when (rl/key-pressed? rl/key-r)) (when (rl/key-pressed? rl/key-r))
(when (rl/mouse-button-pressed? rl/mouse-button-left) (when (rl/mouse-button-pressed? rl/mouse-button-right)
(let [{mx :x my :y} (rl/get-mouse-position)] (let [{mx :x my :y} (rl/get-mouse-position)
(set-tile! game (quot my cell-size) (quot mx cell-size) [3 3]))) at-row (quot my (* scale cell-size))
at-col (quot mx (* scale cell-size))]
(auto-tile! game at-row at-col)
(set-tile! game at-row at-col nil)))
(when (rl/mouse-button-pressed? rl/mouse-button-left))
(cond-> game (cond-> game
(rl/key-pressed? rl/key-space) (rl/key-pressed? rl/key-space)
(update :editor-mode not)))) (update :editor-mode not)
(rl/mouse-button-pressed? rl/mouse-button-left)
(assoc :draw-drag true)
(rl/mouse-button-released? rl/mouse-button-left)
(dissoc :draw-drag))))
(defn update-game [config game] (defn update-game [config game]
(if (:editor-mode game) (when (:draw-drag game)
() (let [{mx :x my :y} (rl/get-mouse-position)
()) row (quot my (* cell-size scale))
col (quot mx (* cell-size scale))]
(when-not (tile-at game row col)
(auto-tile! game row col))))
game) game)
(defn draw-tile! [game row-idx col-idx x y scale] (defn draw-tile! [game row-idx col-idx x y scale]
@ -120,22 +173,22 @@
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 (:texture game)) src-rect dst-rect (rl/vec2-seg 0 0) (float 0.0) rl/white))) (rl/draw-texture-pro!* (:seg (:texture game)) src-rect dst-rect (rl/vec2-seg 0 0) (float 0.0) rl/white)))
(def scale 4.0)
(defn draw-game [config game] (defn draw-game [config game]
(rl/clear-background!* color-ground) (rl/clear-background!* color-ground)
(doseq [row (range rows) (doseq [row (range rows)
col (range cols)] col (range cols)]
(when-let [[tx ty] (tile-at game row col)] (when-let [[tx ty] (tile-at game row col)]
(draw-tile! game tx ty (* col cell-size) (* row cell-size) scale))) (draw-tile! game tx ty (* col cell-size scale) (* row cell-size scale) scale)))
(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 3 3 mx my scale)))
(when (:editor-mode game) (when (:editor-mode game)
(rl/draw-rectangle!* 0 0 screen-width screen-height color-tint-gray) (rl/draw-rectangle!* 0 0 screen-width screen-height color-tint-gray)
(rl/draw-rectangle!* (/ screen-width 2) (/ screen-height 2) 100 100 rl/white) (rl/draw-rectangle!* (/ screen-width 2) (/ screen-height 2) 100 100 rl/white)
(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]
{:color-idx (:color-idx game)}) {})
(defn unload-game [game] (defn unload-game [game]
(rl/unload-texture! (:texture game)) (rl/unload-texture! (:texture game))
@ -158,4 +211,5 @@
(future (-main)) (future (-main))
(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])
:-) :-)

92
src/tilemap_blob.clj Normal file
View File

@ -0,0 +1,92 @@
(ns tilemap-blob
(:import
[javax.imageio ImageIO]
[java.io File]
[java.awt.image BufferedImage]))
(def img-path
"source-assets/Sprout Lands - Sprites - premium pack/Sprout Lands - Sprites - premium pack/Tilesets/ground tiles/New tiles/Grass_Hill_Tiles_v2.png")
(def img (ImageIO/read (File. img-path)))
(.getRGB img 100 100)
(class img)
(def buf (let [w (.getWidth img)
h (.getHeight img)]
(.getRGB img 0 0 w h nil 0 w)))
(defn tile-subimages [^BufferedImage img tile-size]
(let [rows (quot (.getHeight img) tile-size)
cols (quot (.getWidth img) tile-size)]
(vec (for [r (range rows)
c (range cols)]
(.getSubimage img (* c tile-size) (* r tile-size) tile-size tile-size)))))
(def tile-size 16)
(def tiles (tile-subimages img tile-size))
(def ref-colors #{(unchecked-int 0xFFC0D470) (unchecked-int 0xFFA4C263)})
#_(= (.getRGB (get tiles 0) 15 15) ref-color)
(def edges
(let [half (dec (quot tile-size 2))
full (dec tile-size)]
[[:N [half 0]]
[:E [full half]]
[:S [half full]]
[:W [0 half]]
[:NE [full 0]]
[:NW [0 0]]
[:SE [full full]]
[:SW [0 full]]]))
(defn tile-directions [tile]
(reduce (fn [acc [k [x y]]]
(if (contains? ref-colors (.getRGB tile x y))
(conj acc k)
acc))
[]
edges))
(tile-directions (get tiles (+ (* 3 11) 2)))
(defn scale [^BufferedImage src n]
(let [w (* n (.getWidth src)) h (* n (.getHeight src))
out (BufferedImage. w h BufferedImage/TYPE_INT_ARGB)
g (.createGraphics out)]
(.setRenderingHint g java.awt.RenderingHints/KEY_INTERPOLATION
java.awt.RenderingHints/VALUE_INTERPOLATION_NEAREST_NEIGHBOR)
(.drawImage g src 0 0 w h nil)
(.dispose g)
out))
(scale (get tiles (+ (* 3 11) 2)) 32)
(partition 11 (mapv tile-directions tiles))
(defn tile-bitmask [tile]
(reduce-kv (fn [acc i [_ [x y]]]
(if (contains? ref-colors (.getRGB tile x y))
(bit-set acc i)
acc))
0
edges))
(mapv tile-bitmask tiles)
(into {} (map-indexed (fn [i t]
[(tile-bitmask t)
((juxt quot rem) i (quot (.getWidth img) tile-size))]))
tiles)
(comment
;; #C0D470
;; #A4C263
;; #78A158
;; rgb(192, 212, 112)
:-)