#!/usr/bin/env bb (ns gen-levels (:require [babashka.fs :as fs] [clojure.pprint :refer [pprint]] [clojure.data.xml :as xml] [clojure.string :as str] [clojure.java.io :as io]) (:import 'java.io.StringReader)) (defn load-tiled-xml-file [path] (-> (slurp (io/reader path)) (str/replace #">\s+" ">") (StringReader.) (xml/parse))) (defn parse-tile-set [tsx] (->> (:content tsx) (filter #(= (:tag %) :tile)) (reduce (fn [acc tile] (conj acc {(Integer/parseInt (get-in tile [:attrs :id])) (vec (->> (:content tile) (map :content) (flatten) (map :attrs) (map #(select-keys % [:x :y :height :width])) (map #(update-vals % (fn [v] (Math/round (Double/parseDouble v)))))))})) {}))) (def walls-tsx (load-tiled-xml-file "./tiled/walls.tsx")) (def objects-tsx (load-tiled-xml-file "./tiled/objects.tsx")) ;; (def colliders {:walls (parse-tile-set walls-tsx) :objects (parse-tile-set objects-tsx)}) ;; (into {} (map (fn [[k v]] ;; [(transform-key k) v]) ;; your-map)) (def colliders "collider boxes by tile GID" (let [walls (into {} (map (fn [[k v]] [(+ k 1) v]) (parse-tile-set walls-tsx))) objects (into {} (map (fn [[k v]] [(+ k 21) v]) (parse-tile-set objects-tsx)))] (merge walls objects))) (def tutorial-map-tmx (load-tiled-xml-file "./tiled/tutorial.tmx")) (def level-001-map-tmx (load-tiled-xml-file "./tiled/level_001.tmx")) (def dev-map-tmx (load-tiled-xml-file "./tiled/dev.tmx")) (defn parse-gid [gid] (let [gid-long (Long/parseLong (str gid)) h-flip (bit-test gid-long 31) ; Bit 32 (horizontal flip) v-flip (bit-test gid-long 30) ; Bit 31 (vertical flip) d-flip (bit-test gid-long 29) ; Bit 30 (diagonal flip) tile-id (bit-and gid-long 0x0FFFFFFF)] ; Clear top 4 bits to get actual tile ID {:tile-id tile-id :colliders (get colliders tile-id) :h-flip h-flip :v-flip v-flip :d-flip d-flip})) (defn parse-map [map-tmx] (let [tiles (-> (filter #(= (:tag %) :layer) (:content map-tmx)) first :content first :content first str/split-lines (->> (mapv #(str/split % #",")) (mapv (fn [row] (mapv parse-gid row)))))] {:tiles (vec (map-indexed (fn [y row] (vec (map-indexed (fn [x tile] (conj {:x (* x 25) :y (* y 25)} tile)) row))) tiles)) :objects (let [objects (:content (first (filter #(= (get-in % [:attrs :name]) "objects") (:content map-tmx))))] (vec (map (fn [obj] (let [attrs (assoc (:attrs obj) :x (Double. (get-in obj [:attrs :x])) :y (Double. (get-in obj [:attrs :y]))) tags (flatten (map :content (:content obj))) properties (map #(hash-map (keyword (get-in % [:attrs :name])) (get-in % [:attrs :value])) tags)] (into attrs properties))) objects))) :spawns (let [spawns (first (filter #(= (get-in % [:attrs :name]) "spawns") (:content map-tmx))) player-1 (first (filter #(= (get-in % [:attrs :name]) "player_1") (:content spawns))) player-2 (first (filter #(= (get-in % [:attrs :name]) "player_2") (:content spawns))) round-num-str #(Double/parseDouble (format "%.2f" (Double/parseDouble %))) extract-pos (fn [tag] {:x (round-num-str (get-in tag [:attrs :x])) :y (round-num-str (get-in tag [:attrs :y]))})] {:player-1 (extract-pos player-1) :player-2 (extract-pos player-2)})})) (def levels {:levels {:level-001 (parse-map level-001-map-tmx) :tutorial (parse-map tutorial-map-tmx) :dev (parse-map dev-map-tmx)} :colliders colliders}) (pprint (get-in levels [:levels :tutorial :objects])) ;; (pprint/pprint {:row (first (:tiles level-001))}) ;; (pprint/pprint (pr-str level-001)) (fs/write-lines "../levels.fnl" ["(local levels" (str/replace (pr-str levels) #",+" "") ")\n\n" "levels"])