move objects out of bg tiles

"
Press any key to quit" 10 10))
This commit is contained in:
Travis Shears 2026-04-18 14:12:07 +02:00
parent 32ea10495e
commit bbbe7bfe8a
Signed by: travisshears
GPG key ID: CB9BF1910F3F7469
14 changed files with 400 additions and 89 deletions

Binary file not shown.

View file

@ -2,70 +2,109 @@
(ns gen-levels (ns gen-levels
(:require (:require
[babashka.fs :as fs] [babashka.fs :as fs]
[clojure.pprint :as pprint] [clojure.pprint :refer [pprint]]
[clojure.data.xml :as xml] [clojure.data.xml :as xml]
[clojure.string :as str] [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"))) (defn load-tiled-xml-file [path]
(def wall-colliders (-> (slurp (io/reader path))
(str/replace #">\s+" ">")
(StringReader.)
(xml/parse)))
(defn parse-tile-set [tsx]
(->> (->>
(:content walls-tsx) (:content tsx)
(remove string?)
(filter #(= (:tag %) :tile)) (filter #(= (:tag %) :tile))
(reduce (fn [acc tile] (reduce (fn [acc tile]
(conj acc (conj acc
{(Integer/parseInt (get-in tile [:attrs :id])) {(Integer/parseInt (get-in tile [:attrs :id]))
(vec (vec
(->> (:content tile) (->> (:content tile)
(remove string?)
(map :content) (map :content)
(flatten) (flatten)
(remove string?)
(map :attrs) (map :attrs)
(map #(select-keys % [:x :y :height :width])) (map #(select-keys % [:x :y :height :width]))
(map #(update-vals % (fn [v] (Math/round (Double/parseDouble v)))))))})) (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 walls-tsx (load-tiled-xml-file "./tiled/walls.tsx"))
(def level-001 (def objects-tsx (load-tiled-xml-file "./tiled/objects.tsx"))
(let [tags (remove string? (:content level-001-tmx)) ;; (def colliders {:walls (parse-tile-set walls-tsx) :objects (parse-tile-set objects-tsx)})
tile-nums (-> (filter #(= (:tag %) :layer) tags) ;; (into {} (map (fn [[k v]]
first ;; [(transform-key k) v])
:content ;; your-map))
second (def colliders
:content "collider boxes by tile GID"
first (let [walls (into {} (map (fn [[k v]] [(+ k 1) v]) (parse-tile-set walls-tsx)))
str/split-lines 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"))
(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
(->> (->>
(remove empty?) (mapv #(str/split % #","))
(map #(str/split % #",")) (mapv (fn [row] (mapv parse-gid row)))))]
(map (fn [row] (map Integer/parseInt row))))) {:tiles
(vec (map-indexed
tiles (vec (map-indexed
(fn [y row] (fn [y row]
(vec (map-indexed (vec (map-indexed
(fn [x tile-id] {:x (* x 25) :y (* y 25) :tile-id tile-id}) (fn [x tile] (conj {:x (* x 25) :y (* y 25)} tile))
row))) tile-nums))] row))) tiles))
(hash-map :spawns
:tiles tiles (let [spawns (first (filter #(= (get-in % [:attrs :name]) "spawns") (:content map-tmx)))
:wall-colliders wall-colliders player-1 (first (filter #(= (get-in % [:attrs :name]) "player_1") (:content spawns)))
:spawns (vec (reduce (fn [acc tag] player-2 (first (filter #(= (get-in % [:attrs :name]) "player_2") (:content spawns)))
(if (= (:tag tag) :object) round-num-str #(Double/parseDouble (format "%.2f" (Double/parseDouble %)))
(conj acc extract-pos (fn [tag] {:x (round-num-str (get-in tag [:attrs :x]))
(hash-map :y (round-num-str (get-in tag [:attrs :y]))})]
:name (get-in tag [:attrs :name]) {:player-1 (extract-pos player-1)
:x (Math/round (Double/parseDouble (get-in tag [:attrs :x]))) :player-2 (extract-pos player-2)})
:y (Math/round (Double/parseDouble (get-in tag [:attrs :y])))))
acc)) '() (:content (first (filter #(= (get-in % [:attrs :name]) "spawns") tags))))))))
;; {: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 {:row (first (:tiles level-001))})
;; (pprint/pprint (pr-str level-001)) ;; (pprint/pprint (pr-str level-001))
(fs/write-lines "../levels.fnl" ["(local levels" (fs/write-lines "../levels.fnl" ["(local levels"
(str/replace (pr-str {:level01 level-001}) #",+" "") (str/replace (pr-str levels) #",+" "")
")\n\n" ")\n\n"
"{ :levels levels }"]) "{ :levels levels }"])

Binary file not shown.

Before

Width:  |  Height:  |  Size: 549 B

After

Width:  |  Height:  |  Size: 649 B

Before After
Before After

View file

@ -31,7 +31,7 @@
10,11,11,11,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,11,10,11,11,11,10,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11,10, 10,11,11,11,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,11,10,11,11,11,10,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11,10,
10,11,11,11,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,11,10,11,11,11,10,11,11,11,11,11,11,11,11,8,11,11,11,11,11,11,10, 10,11,11,11,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,11,10,11,11,11,10,11,11,11,11,11,11,11,11,8,11,11,11,11,11,11,10,
10,11,11,11,11,11,11,11,11,11,11,11,8,11,11,11,11,11,11,11,8,11,11,11,11,11,11,11,11,8,11,11,11,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10, 10,11,11,11,11,11,11,11,11,11,11,11,8,11,11,11,11,11,11,11,8,11,11,11,11,11,11,11,11,8,11,11,11,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,
10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10, 10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,2147483650,11,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,
10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,9,11,11,11,11,11,11,11,11,9,11,11,11,14,18,11,11,17,1,1,1,1,12,1,1,1,18,11,11,20, 10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,9,11,11,11,11,11,11,11,11,9,11,11,11,14,18,11,11,17,1,1,1,1,12,1,1,1,18,11,11,20,
10,11,11,11,11,11,11,11,11,11,11,11,9,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,11,10,11,11,11,10,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11,10, 10,11,11,11,11,11,11,11,11,11,11,11,9,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,11,10,11,11,11,10,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11,10,
10,11,11,11,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,11,10,11,11,11,10,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11,10, 10,11,11,11,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,11,10,11,11,11,10,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11,10,
@ -60,10 +60,10 @@
</data> </data>
</layer> </layer>
<objectgroup id="2" name="spawns"> <objectgroup id="2" name="spawns">
<object id="1" name="spawn1" x="569.372" y="697.644"> <object id="1" name="player_1" x="569.372" y="697.644">
<point/> <point/>
</object> </object>
<object id="3" name="spawn2" x="679.319" y="590.314"> <object id="3" name="player_2" x="679.319" y="590.314">
<point/> <point/>
</object> </object>
</objectgroup> </objectgroup>

View file

@ -17,4 +17,14 @@
<object id="1" x="1.12811" y="2.08266" width="22.8225" height="20.6531"/> <object id="1" x="1.12811" y="2.08266" width="22.8225" height="20.6531"/>
</objectgroup> </objectgroup>
</tile> </tile>
<tile id="3">
<objectgroup draworder="index" id="2">
<object id="1" x="2.0113" y="1.87259" width="20.9453" height="21.084"/>
</objectgroup>
</tile>
<tile id="5">
<objectgroup draworder="index" id="2">
<object id="1" x="0.0892797" y="4.0196" width="24.8292" height="17.8243"/>
</objectgroup>
</tile>
</tileset> </tileset>

View file

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.12.1" orientation="orthogonal" renderorder="right-down" width="50" height="50" tilewidth="25" tileheight="25" infinite="0" nextlayerid="4" nextobjectid="18">
<tileset firstgid="1" source="walls.tsx"/>
<tileset firstgid="21" source="objects.tsx"/>
<layer id="1" name="bg" width="50" height="50">
<data encoding="csv">
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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
</data>
</layer>
<objectgroup id="2" name="spawns">
<object id="1" name="player_1" x="562.031" y="1164.44">
<point/>
</object>
<object id="2" name="player_2" x="687.512" y="1162.99">
<point/>
</object>
</objectgroup>
<objectgroup id="3" name="objects">
<object id="3" type="charging_station" x="550" y="1025" width="75" height="50">
<properties>
<property name="dir" value="n"/>
</properties>
</object>
<object id="4" name="wait_for_2_players" type="h_door" x="650" y="1000" width="50" height="25"/>
<object id="6" name="waiting_for_player2" type="info_pad" x="650" y="1025" width="25" height="25"/>
<object id="7" name="waiting_for_player2" type="info_pad" x="675" y="1025" width="25" height="25"/>
<object id="15" name="controls" type="info_pad" x="550" y="1150" width="25" height="25"/>
<object id="16" name="controls" type="info_pad" x="675" y="1150" width="25" height="25"/>
</objectgroup>
</map>

View file

@ -1,5 +1,5 @@
{ {
"activeFile": "level_001.tmx", "activeFile": "tutorial.tmx",
"expandedProjectPaths": [ "expandedProjectPaths": [
"/Users/she0001t/personal_projects/fennel_love2d_experiments/two_player_cleaning_game", "/Users/she0001t/personal_projects/fennel_love2d_experiments/two_player_cleaning_game",
".", ".",
@ -7,11 +7,14 @@
], ],
"fileStates": { "fileStates": {
"level_001.tmx": { "level_001.tmx": {
"scale": 2.4998, "expandedObjectLayers": [
"selectedLayer": 0, 2
],
"scale": 0.5497,
"selectedLayer": 1,
"viewCenter": { "viewCenter": {
"x": 149.0119209536763, "x": 624.886301619065,
"y": 73.8059044723578 "y": 614.8808440967802
} }
}, },
"map_tileset.tsx": { "map_tileset.tsx": {
@ -21,11 +24,22 @@
}, },
"objects.tsx": { "objects.tsx": {
"scaleInDock": 1, "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": { "walls.tsx": {
"scaleInDock": 1.4397, "scaleInDock": 1.4397,
"scaleInEditor": 8.2977 "scaleInEditor": 5.9643
} }
}, },
"last.exportedFilePath": "/Users/she0001t/personal_projects/fennel_love2d_experiments/two_player_cleaning_game/assets/tiled", "last.exportedFilePath": "/Users/she0001t/personal_projects/fennel_love2d_experiments/two_player_cleaning_game/assets/tiled",
@ -39,13 +53,15 @@
"openFiles": [ "openFiles": [
"level_001.tmx", "level_001.tmx",
"walls.tsx", "walls.tsx",
"objects.tsx" "objects.tsx",
"tutorial.tmx"
], ],
"project": "untitled.tiled-project", "project": "untitled.tiled-project",
"recentFiles": [ "recentFiles": [
"objects.tsx",
"walls.tsx",
"level_001.tmx", "level_001.tmx",
"walls.tsx",
"objects.tsx",
"tutorial.tmx",
"map_tileset.tsx" "map_tileset.tsx"
], ],
"tileset.lastUsedFormat": "tsx", "tileset.lastUsedFormat": "tsx",

View file

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<tileset version="1.10" tiledversion="1.12.1" name="walls" tilewidth="25" tileheight="25" tilecount="20" columns="20"> <tileset version="1.10" tiledversion="1.12.1" name="walls" tilewidth="25" tileheight="25" tilecount="20" columns="13">
<image source="../walls.png" width="500" height="25"/> <image source="../walls.png" width="325" height="25"/>
<tile id="0"> <tile id="0">
<objectgroup draworder="index" id="2"> <objectgroup draworder="index" id="2">
<object id="1" x="0.141111" y="4.23334" width="24.9767" height="17.4978"/> <object id="1" x="0.141111" y="4.02527" width="24.9767" height="17.7059"/>
</objectgroup> </objectgroup>
</tile> </tile>
<tile id="1"> <tile id="1">
@ -14,57 +14,63 @@
</tile> </tile>
<tile id="2"> <tile id="2">
<objectgroup draworder="index" id="2"> <objectgroup draworder="index" id="2">
<object id="1" x="-0.264752" y="4.10365" width="15.0247" height="17.8045"/> <object id="1" x="10.0692" y="4.10365" width="15.0247" height="17.8045"/>
<object id="2" x="10.0606" y="-0.0661879" width="4.83172" height="4.30221"/> <object id="2" x="10.13" y="20.5323" width="4.83172" height="4.30221"/>
</objectgroup> </objectgroup>
</tile> </tile>
<tile id="3"> <tile id="3">
<objectgroup draworder="index" id="2"> <objectgroup draworder="index" id="2">
<object id="1" x="-0.264752" y="4.03746" width="15.157" height="17.8707"/> <object id="1" x="9.99984" y="3.9681" width="15.157" height="17.8707"/>
<object id="2" x="10.0606" y="20.1873" width="4.76553" height="4.96409"/>
</objectgroup> </objectgroup>
</tile> </tile>
<tile id="4"> <tile id="4">
<objectgroup draworder="index" id="2"> <objectgroup draworder="index" id="2">
<object id="1" x="10.1267" y="4.16984" width="14.7599" height="17.6722"/> <object id="2" x="10.13" y="0.0242897" width="4.83172" height="21.8801"/>
<object id="2" x="10.0606" y="18.3341" width="4.83172" height="6.5526"/>
</objectgroup> </objectgroup>
</tile> </tile>
<tile id="5"> <tile id="5">
<objectgroup draworder="index" id="2"> <objectgroup draworder="index" id="2">
<object id="1" x="9.99437" y="4.10365" width="15.0247" height="17.8707"/> <object id="1" x="9.99437" y="4.10365" width="4.89882" height="20.853"/>
</objectgroup> </objectgroup>
</tile> </tile>
<tile id="6"> <tile id="6">
<objectgroup draworder="index" id="2"> <objectgroup draworder="index" id="2">
<object id="1" x="1.77636e-15" y="4.10365" width="14.8261" height="18.0031"/> <object id="1" x="10.1259" y="0.0116848" width="4.70022" height="24.9386"/>
</objectgroup> </objectgroup>
</tile> </tile>
<tile id="7"> <tile id="7">
<objectgroup draworder="index" id="2"> <objectgroup draworder="index" id="2">
<object id="1" x="10.1267" y="0.0661879" width="4.89791" height="21.7758"/> <object id="1" x="0.0701754" y="4.0888" width="24.8722" height="17.7532"/>
<object id="2" x="10.0565" y="16.9227" width="4.85487" height="7.90651"/>
</objectgroup> </objectgroup>
</tile> </tile>
<tile id="8"> <tile id="8">
<objectgroup draworder="index" id="2"> <objectgroup draworder="index" id="2">
<object id="1" x="10.0606" y="4.10365" width="4.89791" height="20.8492"/> <object id="1" x="0.0734307" y="4.10365" width="24.7335" height="17.9363"/>
<object id="2" x="10.1952" y="0" width="4.71616" height="7.21296"/>
</objectgroup> </objectgroup>
</tile> </tile>
<tile id="9"> <tile id="9">
<objectgroup draworder="index" id="2"> <objectgroup draworder="index" id="2">
<object id="1" x="9.99437" y="-0.0661879" width="4.96409" height="24.8867"/> <object id="1" x="9.99437" y="-0.0661879" width="4.96409" height="24.8867"/>
<object id="2" x="14.0098" y="4.09197" width="10.9581" height="17.963"/>
</objectgroup>
</tile>
<tile id="10">
<objectgroup draworder="index" id="2">
<object id="1" x="10.0565" y="1.77636e-15" width="4.85487" height="24.9679"/>
<object id="2" x="0.0693553" y="4.02261" width="24.9679" height="17.963"/>
</objectgroup> </objectgroup>
</tile> </tile>
<tile id="11"> <tile id="11">
<objectgroup draworder="index" id="2"> <objectgroup draworder="index" id="2">
<object id="1" x="-0.132376" y="4.03746" width="25.019" height="17.7384"/> <object id="1" x="2.98861" y="4.03746" width="21.898" height="17.7384"/>
<object id="2" x="10.1929" y="13.9656" width="4.76553" height="11.1858"/>
</objectgroup> </objectgroup>
</tile> </tile>
<tile id="12"> <tile id="12">
<objectgroup draworder="index" id="2"> <objectgroup draworder="index" id="2">
<object id="1" x="0.0661879" y="4.23603" width="24.9528" height="17.3412"/> <object id="1" x="9.984" y="3.88925" width="11.9834" height="18.1041"/>
<object id="2" x="9.99437" y="0.0661879" width="4.89791" height="10.1267"/> <object id="2" x="9.99437" y="0.0661879" width="4.89791" height="24.83"/>
</objectgroup> </objectgroup>
</tile> </tile>
<tile id="13"> <tile id="13">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 559 B

After

Width:  |  Height:  |  Size: 419 B

Before After
Before After

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,7 @@
;; deps ;; deps
(local levels (. (require "levels.fnl") :levels)) (local levels (. (require "levels.fnl") :levels))
(local bump (require "bump")) (local bump (require "bump"))
(local network (require "network.fnl"))
;; colors ;; colors
(lambda color [full-r full-g full-b] (lambda color [full-r full-g full-b]
@ -28,6 +29,7 @@
(love.graphics.setColor (unpack (. color-pallet color)))) (love.graphics.setColor (unpack (. color-pallet color))))
;; global vars ;; global vars
(var level-key "tutorial")
(var player-art nil) ; 25x50 pixels each player is 25x25 (var player-art nil) ; 25x50 pixels each player is 25x25
(var dust-sprite nil) ; 35x35 pixels (var dust-sprite nil) ; 35x35 pixels
(var battery-bar-sprite nil) (var battery-bar-sprite nil)
@ -59,24 +61,24 @@
(lambda add-collider-debug-box [x y w h] (lambda add-collider-debug-box [x y w h]
(table.insert collider-debug-boxes {: x : y :width w :height h})) (table.insert collider-debug-boxes {: x : y :width w :height h}))
(local bump-world (bump.newWorld 25)) (var bump-world nil)
(local player { :x 50 :y 50 :w 25 :h 25 :speed 80 :battery 100 :rot 0 }) (local player { :x 50 :y 50 :w 25 :h 25 :speed 80 :battery 100 :rot 0 })
(fn load-walls [] (fn load-walls []
(set walls.sprite (love.graphics.newImage "assets/walls.png"))
(set walls.batch (love.graphics.newSpriteBatch walls.sprite 2500)) (set walls.batch (love.graphics.newSpriteBatch walls.sprite 2500))
;; load quads ;; load quads
(let [(w h) (walls.sprite:getDimensions)] (let [(w h) (walls.sprite:getDimensions)]
(for [i 0 19 1] (for [i 0 19 1]
(table.insert walls.quads (love.graphics.newQuad (* i 25) 0 25 25 w h)))) (table.insert walls.quads (love.graphics.newQuad (* i 25) 0 25 25 w h))))
;; fill batch ;; fill batch
(each [_ row (pairs (. levels :level01 :tiles))] ;;
(each [_ row (pairs (. levels :levels level-key :tiles))]
(each [_ tile (pairs row)] (each [_ tile (pairs row)]
(let [ (let [
x tile.x x tile.x
y tile.y y tile.y
id tile.tile-id id tile.tile-id
colliders (or (. levels.level01.wall-colliders (- id 1)) [])] colliders tile.colliders]
(if (and (> id 0) (< id 21)) ;; 1-20 are wall tiles (if (and (> id 0) (< id 21)) ;; 1-20 are wall tiles
(do (do
; (print (fennel.view {:quad (. walls.quads id) : x : y : id})) ; (print (fennel.view {:quad (. walls.quads id) : x : y : id}))
@ -122,13 +124,12 @@
(table.insert objects.list station))) (table.insert objects.list station)))
(fn load-objects [] (fn load-objects []
(set objects.sprite (love.graphics.newImage "assets/objects.png"))
(let [(w h) (objects.sprite:getDimensions)] (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 (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-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))) (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)] (each [_ tile (pairs row)]
(let [ (let [
x tile.x x tile.x
@ -137,18 +138,24 @@
(when (> id 20) ;; 21+ are object tiles (when (> id 20) ;; 21+ are object tiles
(when (= id 22) (create-charging-station x y))))))) (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 [] (lambda load-level [lvl-name]
(love.window.setMode screen.screen-w screen.screen-h) (set bump-world (bump.newWorld 25))
(tset screen :canvas (love.graphics.newCanvas screen.canvas-w screen.canvas-h)) (set level-key :tutorial)
(bump-world:add player player.x player.y player.w player.h) ;; set player 1 location
(load-player)
(load-walls) (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 battery-bar-sprite (love.graphics.newImage "assets/battery_bar.png"))
(set player-art (set player-art
(let [ (let [
player-sprite (love.graphics.newImage "assets/player.png") 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 ;; start a thread listening on stdin
(: (love.thread.newThread "require('love.event') (: (love.thread.newThread "require('love.event')
while 1 do love.event.push('stdin', io.read('*line')) end") :start)) 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)))) (print (if ok (fennel.view val) val))))
;; drawing ;; drawing
(fn draw-world [] (fn draw-world []
(reset-color) (reset-color)
(love.graphics.draw walls.batch) (love.graphics.draw walls.batch)
@ -228,7 +243,15 @@ while 1 do love.event.push('stdin', io.read('*line')) end") :start))
(let (let
[(items len) (bump-world:queryRect player.x player.y 25 25 #(= $1.behavior "hover"))] [(items len) (bump-world:queryRect player.x player.y 25 25 #(= $1.behavior "hover"))]
(each [_ item (pairs items)] (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 [] (fn draw-ui []
(love.graphics.push) (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)) ; (love.graphics.print "Hello from Fennel!\nPress any key to quit" 10 10))
(fn love.keypressed [key] nil ) (fn love.keypressed [key] nil )
(fn love.quit []
"Clean up before game closes"
(network.close)
false)

View file

@ -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
}