From bbbe7bfe8ac84258c34a7474e23c96c794cc8628 Mon Sep 17 00:00:00 2001 From: Travis Shears Date: Sat, 18 Apr 2026 14:12:07 +0200 Subject: [PATCH] move objects out of bg tiles " Press any key to quit" 10 10)) --- .../assets/doors.aseprite | Bin 0 -> 454 bytes two_player_cleaning_game/assets/gen_levels.bb | 119 ++++++++++------ .../assets/objects.aseprite | Bin 690 -> 828 bytes two_player_cleaning_game/assets/objects.png | Bin 549 -> 649 bytes .../assets/tiled/level_001.tmx | 6 +- .../assets/tiled/objects.tsx | 10 ++ .../assets/tiled/tutorial.tmx | 79 +++++++++++ .../assets/tiled/untitled.tiled-session | 36 +++-- .../assets/tiled/walls.tsx | 40 +++--- .../assets/walls.aseprite | Bin 2265 -> 1351 bytes two_player_cleaning_game/assets/walls.png | Bin 559 -> 419 bytes two_player_cleaning_game/levels.fnl | 2 +- two_player_cleaning_game/main.fnl | 64 ++++++--- two_player_cleaning_game/network.fnl | 133 ++++++++++++++++++ 14 files changed, 400 insertions(+), 89 deletions(-) create mode 100644 two_player_cleaning_game/assets/doors.aseprite create mode 100644 two_player_cleaning_game/assets/tiled/tutorial.tmx create mode 100644 two_player_cleaning_game/network.fnl diff --git a/two_player_cleaning_game/assets/doors.aseprite b/two_player_cleaning_game/assets/doors.aseprite new file mode 100644 index 0000000000000000000000000000000000000000..055712a9be940f6078e38e31e9f68712533e29c1 GIT binary patch literal 454 zcmX@c$iVPmDI-G)gCv6j1CRq`Ap>>>Mvx#-RuWm5YHT;4>Aya*fNf;~nkojw>5%%{_TrxtjVP_vYVkwut@r#%kwzOaCvF1pq@jY{dWo literal 0 HcmV?d00001 diff --git a/two_player_cleaning_game/assets/gen_levels.bb b/two_player_cleaning_game/assets/gen_levels.bb index 82f698d..611331d 100755 --- a/two_player_cleaning_game/assets/gen_levels.bb +++ b/two_player_cleaning_game/assets/gen_levels.bb @@ -2,70 +2,109 @@ (ns gen-levels (:require [babashka.fs :as fs] - [clojure.pprint :as pprint] + [clojure.pprint :refer [pprint]] [clojure.data.xml :as xml] [clojure.string :as str] - [clojure.java.io :as io])) + [clojure.java.io :as io]) + (:import + 'java.io.StringReader)) -(def walls-tsx (xml/parse (io/reader "./tiled/walls.tsx"))) -(def wall-colliders +(defn load-tiled-xml-file [path] + (-> (slurp (io/reader path)) + (str/replace #">\s+" ">") + (StringReader.) + (xml/parse))) + +(defn parse-tile-set [tsx] (->> - (:content walls-tsx) - (remove string?) + (:content tsx) (filter #(= (:tag %) :tile)) (reduce (fn [acc tile] (conj acc {(Integer/parseInt (get-in tile [:attrs :id])) (vec (->> (:content tile) - (remove string?) (map :content) (flatten) - (remove string?) (map :attrs) (map #(select-keys % [:x :y :height :width])) (map #(update-vals % (fn [v] (Math/round (Double/parseDouble v)))))))})) {}))) -(pprint/pprint wall-colliders) -(def level-001-tmx (xml/parse (io/reader "./tiled/level_001.tmx"))) -(def level-001 - (let [tags (remove string? (:content level-001-tmx)) - tile-nums (-> (filter #(= (:tag %) :layer) tags) - first - :content - second - :content - first - str/split-lines - (->> - (remove empty?) - (map #(str/split % #",")) - (map (fn [row] (map Integer/parseInt row))))) +(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))) - tiles (vec (map-indexed - (fn [y row] - (vec (map-indexed - (fn [x tile-id] {:x (* x 25) :y (* y 25) :tile-id tile-id}) - row))) tile-nums))] +(def tutorial-map-tmx (load-tiled-xml-file "./tiled/tutorial.tmx")) +(def level-001-map-tmx (load-tiled-xml-file "./tiled/level_001.tmx")) - (hash-map - :tiles tiles - :wall-colliders wall-colliders - :spawns (vec (reduce (fn [acc tag] - (if (= (:tag tag) :object) - (conj acc - (hash-map - :name (get-in tag [:attrs :name]) - :x (Math/round (Double/parseDouble (get-in tag [:attrs :x]))) - :y (Math/round (Double/parseDouble (get-in tag [:attrs :y]))))) - acc)) '() (:content (first (filter #(= (get-in % [:attrs :name]) "spawns") tags)))))))) +(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)) + + :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)}) + +;; {:tag :objectgroup, + ;; :attrs {:id "2", :name "spawns"}, + ;; {:player-1 nil + ;; :player-2 nil} + ;; (vec (reduce (fn [acc tag] + ;; (if (= (:tag tag) :object) + ;; (conj acc + ;; (hash-map + ;; :name (get-in tag [:attrs :name]) + ;; :x (Math/round (Double/parseDouble (get-in tag [:attrs :x]))) + ;; :y (Math/round (Double/parseDouble (get-in tag [:attrs :y]))))) + ;; acc)) '() (:content (first (filter #(= (get-in % [:attrs :name]) "spawns") tags)))))))) + })) +(def levels {:levels {:level-001 (parse-map level-001-map-tmx) + :tutorial (parse-map tutorial-map-tmx)} + :colliders colliders}) + +;; (pprint (get-in levels [:levels :level-001 :spawns])) ;; (pprint/pprint {:row (first (:tiles level-001))}) ;; (pprint/pprint (pr-str level-001)) (fs/write-lines "../levels.fnl" ["(local levels" - (str/replace (pr-str {:level01 level-001}) #",+" "") + (str/replace (pr-str levels) #",+" "") ")\n\n" "{ :levels levels }"]) diff --git a/two_player_cleaning_game/assets/objects.aseprite b/two_player_cleaning_game/assets/objects.aseprite index 8bbbbb82cd13ffd749ee320148b0e365f10350b6..ae79a0ef6b9b70400db6abbff1262829f8501559 100644 GIT binary patch delta 504 zcmVv2mk;8000002az!ok;ozi00960|B>mI0k@NY0Tq8>04)G`ob8(1ZNo4O zMZH89%16fN933JH^{1;b55$Ea=s{Yf$+GtV0;1Svq9dA?4HFS<59rPIrqv&9qaw~$ z@bPsctG1mC8N0IJ<>~uJy?OYzKzj~a`JctVg{!Fkub0nP%kEz@UW+6CclXi!bD#q6 z|MFzje{UWl`lo*eoMR+$rSWF|Tdt$#|7iTRBaSnPQw#q+$5HdYH~yZVnKy2YTB&I> z|JmyQ&gylbRm*BPagO+py8hv^QZHIDB>p+|XXcjEBGsRIpH=sD9Buy^Eo%O2`PYj1 z-~3CEIOXnJlkxf6Y#)iMGyG@Ce`{A7%<9i??lyc%zxRI_-wccTFa7G?nU&N=+c u82Oi+7w{y13@iV*{_?Q&zt4g97$aj<|KXnp?!SD2e_!zYZO$DBYZyFE^8cCu delta 381 zcmdnPwux176B7f&gQbiNDL|;ez{tP=q>%ypM8$YUqlt~G{4PLYNd@r&3#{Iy>;sv|`~yZc4n;N`1a*doOO7=@lf+vT4J{FPfbF6MZEsHVHlv z5#N4fiDhc)VI%IO$B7r8t1Y?rriZt;JafL%sekKF9$mfaC})n*IbROxd_&8xcR%}? zuDSJlVq(jO*&9AeE#GMPq|+@j$LQP5+woz3e@~ltt&m$M_Qv?F^WL91yuTf-K7D`0 JpS>yA8~~sppCkYP diff --git a/two_player_cleaning_game/assets/objects.png b/two_player_cleaning_game/assets/objects.png index 0d85d3f4faeed3bebd7edc7f4dc1148f2af643ad..9f82178e26a5485246724e7ca240aae2060546d1 100644 GIT binary patch delta 588 zcmV-S0<-<41c?QZFn$5_lm$*QGBe^wKbb8PXqKGlA-WLdYSkuof4B_-}YLWZlN z)EnirEg2=LVE=u6wIp3<4tQ;1DokKHL$w@ta z^EpFstLDZ>tz?b$)#AF7hT0`7etywqZ!Z@YHQiTPIitfxQf*VKuifQ38qCuDEz~a8 zajcr08163D`)GOPv1N0Urgr(g=Sg2PR%#>U*~E7{?0@g&C;qmV?(fAS=OL;7rUF~K zzXi=$JuG{*ep8o@Rzyq03IG5AH7&B#(!7l{So(HSEsI^t(mb*2<@`q0bYIq1kPu@Q zD_K326-~?`#!#}1F?B0xP;z@vPoqODB;c3`kUL6x z)4XI&1t@(jf6l3G)g{Z)@9ed#Iw8_wQks{nt(K-KO%t-kNjqirC95}FTm+Nx0Ua0s aw&ow0M3cejAl&}|0000|GASAX5Q_wHC9w&c(wA=i>m9JqBM5i+uG5wMr_rdINSVR zXXe~~?4oj8zI09fq96aX_PfWQi&|^$1teWu)|#J+SwGLbHm&~L+d@s1--~kUuNLAr#o1!Q_MB5zhx@myk7CG^^$e9Up?dHcfH+q@ReKa?^l!e1- - + - + diff --git a/two_player_cleaning_game/assets/tiled/objects.tsx b/two_player_cleaning_game/assets/tiled/objects.tsx index 4ddb1db..b6b02bf 100644 --- a/two_player_cleaning_game/assets/tiled/objects.tsx +++ b/two_player_cleaning_game/assets/tiled/objects.tsx @@ -17,4 +17,14 @@ + + + + + + + + + + diff --git a/two_player_cleaning_game/assets/tiled/tutorial.tmx b/two_player_cleaning_game/assets/tiled/tutorial.tmx new file mode 100644 index 0000000..561fbe2 --- /dev/null +++ b/two_player_cleaning_game/assets/tiled/tutorial.tmx @@ -0,0 +1,79 @@ + + + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2147483651,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,2,1,1,1,1,1,1,1,1,1,8,1,1,1,0,0,1,1,1,8,1,1,1,1,1,1,1,1,1,2147483650,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,1,1,1,1,1,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,1,1,1,1,1,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,1,1,1,1,1,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,1,1,1,1,1,0,0,1,2147483658,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,1,1,1,1,1,1,1,2147483650,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + + + + + + + + + + + + + + + + + + + + diff --git a/two_player_cleaning_game/assets/tiled/untitled.tiled-session b/two_player_cleaning_game/assets/tiled/untitled.tiled-session index 786f8d8..2a5c318 100644 --- a/two_player_cleaning_game/assets/tiled/untitled.tiled-session +++ b/two_player_cleaning_game/assets/tiled/untitled.tiled-session @@ -1,5 +1,5 @@ { - "activeFile": "level_001.tmx", + "activeFile": "tutorial.tmx", "expandedProjectPaths": [ "/Users/she0001t/personal_projects/fennel_love2d_experiments/two_player_cleaning_game", ".", @@ -7,11 +7,14 @@ ], "fileStates": { "level_001.tmx": { - "scale": 2.4998, - "selectedLayer": 0, + "expandedObjectLayers": [ + 2 + ], + "scale": 0.5497, + "selectedLayer": 1, "viewCenter": { - "x": 149.0119209536763, - "y": 73.8059044723578 + "x": 624.886301619065, + "y": 614.8808440967802 } }, "map_tileset.tsx": { @@ -21,11 +24,22 @@ }, "objects.tsx": { "scaleInDock": 1, - "scaleInEditor": 6.3771 + "scaleInEditor": 2.8063 + }, + "tutorial.tmx": { + "expandedObjectLayers": [ + 2 + ], + "scale": 2.2046, + "selectedLayer": 1, + "viewCenter": { + "x": 636.1698267259367, + "y": 1051.8914995917626 + } }, "walls.tsx": { "scaleInDock": 1.4397, - "scaleInEditor": 8.2977 + "scaleInEditor": 5.9643 } }, "last.exportedFilePath": "/Users/she0001t/personal_projects/fennel_love2d_experiments/two_player_cleaning_game/assets/tiled", @@ -39,13 +53,15 @@ "openFiles": [ "level_001.tmx", "walls.tsx", - "objects.tsx" + "objects.tsx", + "tutorial.tmx" ], "project": "untitled.tiled-project", "recentFiles": [ - "objects.tsx", - "walls.tsx", "level_001.tmx", + "walls.tsx", + "objects.tsx", + "tutorial.tmx", "map_tileset.tsx" ], "tileset.lastUsedFormat": "tsx", diff --git a/two_player_cleaning_game/assets/tiled/walls.tsx b/two_player_cleaning_game/assets/tiled/walls.tsx index 9c57228..90baec0 100644 --- a/two_player_cleaning_game/assets/tiled/walls.tsx +++ b/two_player_cleaning_game/assets/tiled/walls.tsx @@ -1,9 +1,9 @@ - - + + - + @@ -14,57 +14,63 @@ - - + + - - + - - + - + - + - + + - + + + + + + + + + - - + - - + + diff --git a/two_player_cleaning_game/assets/walls.aseprite b/two_player_cleaning_game/assets/walls.aseprite index 6ef51d14e5cd5aa538d01a4a32f53431696468a2..58eed86528fa566f2c5f2b0e7f799c21d0f6be7e 100644 GIT binary patch literal 1351 zcmZ=~Wng%)l$Svg2o)F@85kH+fEWST85lu=3<5w%3vdEx=&z3~U|U&$Y%w5aR{&dy zWSt9;Evdi`6=6e?fic~j;{G!*{Ld@~lA;woK$2nSK9ISlUSKrq+n+zvMc!+MB%PvOuMnO zU&m%b)yk*wL3a#Sm500!xZoWary#^LC62*q^1{zPXlB~rFcaZ(xS8&=>fOKgy*j#d zdJGSPTFnRZ*cl%E50;Ms znuZ*ypa_B3f$U64aG)h8DDZWJefg7qV<&&#!5XdRKx>7n%-)H2&AL85zW77p=;8{I z{v?)V?lU)A?_ZBXgzG#oZiPKgLsn0H0 z=c1V&i^Jt0)A73epoo0LWl`Qg)>+3_$SyAHxz*^eZ<#9X`Rhf%bv|)xhNJTv)BVvb zgXK_W2IM3mhLl5c;?+a+4bOv$Ce;S7NGWdvo(JM4E5-0dgyHsQW_Qjv6w+ xWQ~$IntoI?yif@7*K#wHmtQu$%Ii-5`F(+37r*KZ^e?KCKJbT+VXnWYG62m%SIqzb literal 2265 zcmcb~!NBlfsR)B45GpV*GB7Zt05JlvGcbY#83cfk7T_|_&|e=}z_zjg*+c5*JN$d> zfL+%n8MzCw0!*@g8!GDp+@F*7Le_dUx-vnZMziv;#Q zNlJR_P$sQep>oSmN`7$})G`jAexpJW;eN*R)BB!fpjj0`&?;zXZ8F?gX7J{YyO>;O z8PBpG3^P4nZ;;xWe5EhY+U@Ouc27;_lUtibw)d1+GswA2nwNrRPY4nAoJa)5$|gfi zxIGuF?L0nS2L%_{D-O3E`;8_>>^*#xk729sq7mg?ni{-;ADjyP{@WeU0w`~@*~L%Mf+C$qf*jp>}y|T-_|X=_#-q~_1tRQ z(0ncRk%rx8d4}>WW%r}dyg^Lv0LKH554W{M*}LY)!1#R(jb;f@d>>3^XHfi7_dg!Z zWPgGIge7;t6Dgc=;5*Y+cMGlajx6q3R zgQM)bqN0vGg{4Dw#l26a!}aS~|^m)I6!g6jBoQ+;Zf#_CP8=s%6XCiqY&$CeKb- zP$qQo=e+C^`zH%8u$E7sv#D34_V7}>NuYWpp#+pu7F)@!D?`rk zpwgsAo|$34Kg$_%42M)w2`N|&uRVPv(8q?2;oLNqGx=zN1fTc36ls~2B>LqQd-xeCyb8qwfo~^SV#=hz;?KxF?CF1CN+heSjXLkNwd-vxXn`1S5zaG^V zSR8)p*4YUg*BR-&l9=?mVPn*~?Az%L4#6xOeUj0OesjNnd)B?ja8>Ti#iw@eU36>C z_o!=zO4oZf-ugT9QO(}1$93Y4bG$EDwqwrY>CbGOkKM}MlC_3wzNX#k!!wl*2+vY- zSfI(of{)t0M_`e8+E%Mof5k0t&-$g^8++_l?Beg=H-2pu@Lu~kdo**#P89ZJ6T-G@yGywol(YoFM literal 559 zcmeAS@N?(olHy`uVBq!ia0y~yVEh7POLDLQ$>Y^`l7JLrage(c!@6@aFM;fro-U3d z6?5L+J)JA<$iom|8NeN+$XMe)t4J`*OG_a@(d>cPoahAZqAj0eyQuz^`$J4m9 zvG!NR|IZsalj<#U@74YP^S!#8p#+DqgRO+ZS9t-R4p4Rps!Duj;+u{?s{nwLJUIsnFcB+vm5x7d+FqT%~a9#@;M7 z<08?Wa;kd&Pdn zQi;mB`cY-2d#B{@6O&d)WqzCgq-IUwcK37c`g^}wD21oJU``9#{kU@K%(oqPT-UjC z8h`m1b0H<8 z&9ArM?SDG!-p}s1{-vAVDDRr~dE!#Hz27euO+T~FeVWv?S94cSn^pakkAXAe1;c~` Z@of$=PpdB id 0) (< id 21)) ;; 1-20 are wall tiles (do ; (print (fennel.view {:quad (. walls.quads id) : x : y : id})) @@ -122,13 +124,12 @@ (table.insert objects.list station))) (fn load-objects [] - (set objects.sprite (love.graphics.newImage "assets/objects.png")) (let [(w h) (objects.sprite:getDimensions)] (set objects.quads.charging-pad (love.graphics.newQuad 0 0 25 25 w h)) (set objects.quads.charging-pad-active (love.graphics.newQuad 50 0 25 25 w h)) (set objects.quads.charging-station (love.graphics.newQuad 25 0 25 25 w h))) - (each [_ row (pairs (. levels :level01 :tiles))] + (each [_ row (pairs (. levels :levels level-key :tiles))] (each [_ tile (pairs row)] (let [ x tile.x @@ -137,18 +138,24 @@ (when (> id 20) ;; 21+ are object tiles (when (= id 22) (create-charging-station x y))))))) +(fn load-player [] + (set player.battery 100) + (set player.x (. levels :levels level-key :spawns :player-1 :x)) + (set player.y (. levels :levels level-key :spawns :player-1 :y)) + (bump-world:add player player.x player.y player.w player.h)) -(fn love.load [] - (love.window.setMode screen.screen-w screen.screen-h) - (tset screen :canvas (love.graphics.newCanvas screen.canvas-w screen.canvas-h)) - (bump-world:add player player.x player.y player.w player.h) - +(lambda load-level [lvl-name] + (set bump-world (bump.newWorld 25)) + (set level-key :tutorial) + ;; set player 1 location + (load-player) (load-walls) - (load-objects) + (load-objects)) - ;; load world images +(fn load-assets [] + (set objects.sprite (love.graphics.newImage "assets/objects.png")) + (set walls.sprite (love.graphics.newImage "assets/walls.png")) (set battery-bar-sprite (love.graphics.newImage "assets/battery_bar.png")) - (set player-art (let [ player-sprite (love.graphics.newImage "assets/player.png") @@ -169,9 +176,18 @@ } } )) + ) + + +(fn love.load [] + (love.window.setMode screen.screen-w screen.screen-h) + (tset screen :canvas (love.graphics.newCanvas screen.canvas-w screen.canvas-h)) + (load-assets) + (load-level :tutorial) + ;; Initialize network + (network.init) + (network.send-msg "REGISTER") - (set dust-sprite (love.graphics.newImage "assets/dust_001.png")) - ; (print (fennel.view game-state)) ;; start a thread listening on stdin (: (love.thread.newThread "require('love.event') while 1 do love.event.push('stdin', io.read('*line')) end") :start)) @@ -182,7 +198,6 @@ while 1 do love.event.push('stdin', io.read('*line')) end") :start)) (print (if ok (fennel.view val) val)))) ;; drawing - (fn draw-world [] (reset-color) (love.graphics.draw walls.batch) @@ -228,7 +243,15 @@ while 1 do love.event.push('stdin', io.read('*line')) end") :start)) (let [(items len) (bump-world:queryRect player.x player.y 25 25 #(= $1.behavior "hover"))] (each [_ item (pairs items)] - (item:hover-cb dt)))) + (item:hover-cb dt))) + + ;; Network updates + (network.update dt)) + ; (set net-state.net-update-timer (+ net-state.net-update-timer dt)) + ; (when (>= net-state.net-update-timer net-state.net-update-interval) + ; (when net-state.connected + ; (network.send-update player.x player.y player.rot player.battery)) + ; (set net-state.net-update-timer 0))) (fn draw-ui [] (love.graphics.push) @@ -313,3 +336,8 @@ while 1 do love.event.push('stdin', io.read('*line')) end") :start)) ; (love.graphics.print "Hello from Fennel!\nPress any key to quit" 10 10)) (fn love.keypressed [key] nil ) + +(fn love.quit [] + "Clean up before game closes" + (network.close) + false) diff --git a/two_player_cleaning_game/network.fnl b/two_player_cleaning_game/network.fnl new file mode 100644 index 0000000..21d5ddc --- /dev/null +++ b/two_player_cleaning_game/network.fnl @@ -0,0 +1,133 @@ +(local socket (require "socket")) + +;; Guide: https://www.love2d.org/wiki/Tutorial:Networking_with_UDP + +;; Configuration +(local config { + :host "localhost" + :port 9999 +}) + +;; Network state +(local state { + :socket nil + :connected false + ; :player-id nil + ; :last-error nil +}) + +;; Callback functions for network events +; (local callbacks { +; :on-ready (fn []) +; :on-wait (fn []) +; :on-opponent-update (fn [data]) +; :on-error (fn [error]) +; }) + +(fn init [] + "Initialize UDP connection to server + Returns true on success, false on error" + (let [udp (socket.udp)] + (udp:setpeername config.host config.port) + (udp:settimeout 0) ; non-blocking + + (set state.socket udp) + (set state.connected true))) + +(fn send-msg [dg] + (state.socket:send dg)) + +(fn update [dt] + (let [(data msg) (state.socket:receive)] + (when data + (print (fennel.view {: data : msg}))))) + +; (fn register [] +; "Send REGISTER message to server" +; (when state.socket +; (try +; (state.socket:send "REGISTER") +; (catch err +; (set state.last-error err) +; (when callbacks.on-error (callbacks.on-error err)))))) + +; (fn split-string [str delimiter] +; "Split string by delimiter into table" +; (local result []) +; (local current "") +; (each [i 1 (length str) 1] +; (let [char (string.sub str i i)] +; (if (= char delimiter) +; (do +; (table.insert result current) +; (set current "")) +; (set current (.. current char))))) +; (table.insert result current) +; result) + +; (fn parse-message [msg] +; "Parse message in format: COMMAND#arg1#arg2#..." +; (split-string msg "#")) + +; (fn send-update [x y rotation battery] +; "Send player state to server in format: UPDATE#x#y#rotation#battery" +; (when state.socket +; (try +; (let [msg (.. "UPDATE#" x "#" y "#" rotation "#" battery)] +; (state.socket:send msg)) +; (catch err +; (set state.last-error err))))) + +; (fn update [dt] +; "Call from love.update to process incoming messages" +; (when state.socket +; (let [(msg _src-ip _src-port) (state.socket:receivefrom)] +; (when msg +; (let [parts (parse-message msg) +; command (. parts 1)] +; (match command +; "READY_TO_PLAY" (callbacks.on-ready) +; "WAIT" (callbacks.on-wait) +; "UPDATE" (callbacks.on-opponent-update { +; :x (tonumber (. parts 2)) +; :y (tonumber (. parts 3)) +; :rotation (tonumber (. parts 4)) +; :battery (tonumber (. parts 5)) +; }) +; _ (print (.. "← Message: " msg)))))))) + +; (fn set-callback [event cb] +; "Register callback for network events +; Available events: :on-ready :on-wait :on-opponent-update :on-error" +; (tset callbacks event cb)) + +(fn close [] + "Close network connection" + (when state.socket + (state.socket:close) + (set state.socket nil) + (set state.connected false))) + +; (fn is-connected [] +; "Check if currently connected to server" +; state.connected) + +; (fn get-last-error [] +; "Get the last error that occurred" +; state.last-error) + +;; Export public API +{ + : init + : update + : state + : send-msg + : close + ; :register register + ; :send-update send-update + ; :update update + ; :set-callback set-callback + ; :close close + ; :is-connected is-connected + ; :get-last-error get-last-error +}