This commit is contained in:
2026-07-03 14:41:22 -06:00
parent c15fbf7985
commit 87ddaae0b1
6 changed files with 122 additions and 112 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 B

View File

@@ -1,31 +1,111 @@
(ns frontend.il.app (ns frontend.il.app
(:require ["pixi.js" :as pixi] (:require
[goog.dom :as dom])) [clojure.string :as str]
["pixi.js" :as pixi]
[goog.dom :as dom]
[frontend.il.entity :as entity]))
(def app
(pixi/Application.))
(def stage
(.-stage app))
(def websocket (doto (js/WebSocket. (str "ws://" js/location.host "/ws")) (def websocket (doto (js/WebSocket. (str "ws://" js/location.host "/ws"))
(.addEventListener "open" #(println "Websocket opened.")) (.addEventListener "open" #(println "Websocket opened."))
(.addEventListener "message" #(println "Received message:" (.-data %))) (.addEventListener "message" #(println "Received message " (.-data %)))
(.addEventListener "close" #(println "Websocket closed.")))) (.addEventListener "close" #(println "Websocket closed."))))
(defn ticker [game ticker-object] (def base-player {:meta {:type "player"
(let [bunny (game :bunny)] :name "Player"
(set! (.-rotation bunny) (+ (.-rotation bunny) 0.01)))) :race "Human"
:class "Priest"}
:sprite "https://pixijs.com/assets/bunny.png"
:speed 10
:renderable nil})
(def world-layer
(pixi/Container.))
(def entity-layer
(pixi/Container.))
(def entity-id (atom 1))
(def state (atom {:player {:movement {:x 0 :y 0} :keymap {:w 0 :a 0 :s 0 :d 0}}
:entities {}}))
(def lerp 0.1)
(defn add-entity [entity]
(let [id (swap! entity-id inc)]
(swap! state update-in [:entities] conj {(-> id str keyword) entity})))
(defn- velocity-for-key-down [key]
(case key
"w" -1
"s" 1
"a" -1
"d" 1
{}))
(defn handle-key [func event]
(let [key (-> event .-key str/lower-case)
vel (func key)]
(swap! state update-in [:player :keymap] assoc (keyword key) vel)
(print @state)
(let [{left :d
right :a
up :w
down :s} (get-in @state [:player :keymap])]
(swap! state update-in [:player :movement] assoc :x (+ left right) :y (+ up down)))))
(defn init-input-handlers []
(js/window.addEventListener "keydown" (partial handle-key velocity-for-key-down))
(js/window.addEventListener "keyup" (partial handle-key (fn [_] 0))))
(defn ticker [t]
(let [dt (.-deltaTime t)
{entities :entities
player :player} @state]
(doseq [k (keys entities)]
(let [{:keys [x y renderable]
:as e} (entities k)]
(if-not (nil? renderable)
(do
(set! (.. renderable -x) x)
(set! (.. renderable -y) y))
(let [renderable (entity/render {:layer entity-layer} e)]
(swap! state update-in [:entities k] assoc :renderable renderable)))))
(when-not (nil? (:renderable player))
(let [{dx :x dy :y} (:movement player)
{renderable :renderable
speed :speed} player
new-x (+ (* dt speed dx) (.-x renderable))
new-y (+ (* dt speed dy) (.-y renderable))]
(set! (.. renderable -x) new-x)
(set! (.. renderable -y) new-y)
(swap! state update-in [:player] assoc :x new-x :y new-y)
(let [sx (- (/ (.. app -screen -width) 2) new-x)
sy (- (/ (.. app -screen -height) 2) new-y)]
(set! (.. world-layer -x) sx)
(set! (.. world-layer -y) sy))))))
(defn init [] (defn init []
(let [app (pixi/Application.) (let [width (.-width js/window.screen)
width (.-width js/window.screen)
height (.-height js/window.screen)] height (.-height js/window.screen)]
(.. app (.. app
(init #js {:width width :height height :backgroundColor 0x1099bb}) (init #js {:width width :height height :backgroundColor 0x222})
(then (fn [_] (then (fn [_]
(dom/appendChild (dom/getElement "app") (.-canvas app)) (dom/appendChild (dom/getElement "app") (.-canvas app))
(let [texture (.. pixi -Assets (load "https://www.sprite-ai.art/sprite-img/99fa1574-fc52-41a6-ab76-1bd75b5dc4b3/16x16-pixel-art-sprite-cookie-shaped-like-a-32x32-pixel-art-90b4.png"))] (init-input-handlers)
(.. texture (add-entity {:x 500 :y 500 :sprite "https://pixijs.com/assets/bunny.png"})
(then (fn [loaded-texture] (-> (.-stage app)
(let [bunny (pixi/Sprite. loaded-texture)] (.addChild world-layer)
(set! (.. bunny -anchor -x) 0.5) (.addChild entity-layer))
(set! (.. bunny -anchor -y) 0.5) (let [e (merge {:x (-> width (/ 2) (int))
(set! (.. bunny -x) (/ width 2)) :y (-> height (/ 2) (int))}
(set! (.. bunny -y) (/ height 2)) base-player)
(.. app -stage (addChild bunny)) p (entity/render {:layer entity-layer} e)
(.. app -ticker (add (partial ticker {:bunny bunny}))))))))))))) player (assoc e :renderable p)]
(swap! state update-in [:player] merge player)
(.. app -ticker (add ticker))))))))

View File

@@ -0,0 +1,20 @@
(ns frontend.il.entity
(:require ["pixi.js" :as pixi]))
(defn render [render-info entity]
(let [{x :x
y :y
sprite :sprite} entity
{^js layer :layer} render-info
entity-sprite (pixi/Sprite.)]
(print "Creating sprite: " sprite " for entity " entity)
(.. pixi -Assets
(load sprite)
(then (fn [loaded-texture]
(set! (.. entity-sprite -texture) loaded-texture)
(set! (.. entity-sprite -anchor -x) 0.5)
(set! (.. entity-sprite -anchor -y) 0.5)
(set! (.. entity-sprite -x) x)
(set! (.. entity-sprite -y) y)
(.. layer (addChild entity-sprite)))))
entity-sprite))

View File

@@ -1,10 +1,4 @@
(ns il.constant) (ns il.constant)
(def world-width 4096) (def screen-width 800)
(def world-height 4096) (def screen-height 600)
(def resources
["zinc" "iron" "titanium" "wood" "sulfur"])
(def min-resources 10)
(def max-resources 28)

View File

@@ -5,19 +5,8 @@
[compojure.route :as route] [compojure.route :as route]
[clojure.core.async :refer [<! >! go-loop]] [clojure.core.async :refer [<! >! go-loop]]
[clojure.data.json :as json] [clojure.data.json :as json]
[il.world :as w]
[il.constant :as consts]
[hiccup.core :as h])) [hiccup.core :as h]))
(def world (-> {}
(w/generate-water consts/world-width consts/world-height)
(w/generate-resources
consts/resources
consts/min-resources
consts/max-resources
consts/world-width
consts/world-height)))
(defn ws-handler [_] (defn ws-handler [_]
(go-websocket [in out err] (go-websocket [in out err]
(go-loop [] (go-loop []
@@ -28,7 +17,7 @@
(if-let [msg (<! in)] (if-let [msg (<! in)]
(do (do
(cond (cond
(= msg "world") (>! out (json/write-str world))) (= msg "world") (>! out "Hello World!"))
(println msg) (println msg)
(recur)) (recur))
(println "Closed."))))) (println "Closed.")))))

View File

@@ -1,73 +0,0 @@
(ns il.world
(:require
[il.util :refer [rand-int-range]]
[clojure.math :as math]))
(defn- resource-size [amt]
(cond
(>= amt 4000) "huge"
(>= amt 2750) "large"
(>= amt 1500) "medium"
:else "small"))
(defn- in-water [water point]
(let [[x y] point]))
(defn- rand-int-range-seq [min max]
(repeatedly (partial rand-int-range min max)))
(def region-division 4)
;; I thought about using Perlin noise to generate the water, but I find it over kill.
;; Instead, we split the world width, world height by a "region size", and pick
;; a random coordinate in those to generate water.
(defn generate-water [world world-width world-height]
(let [region-width (/ world-width region-division)
region-height (/ world-height region-division)
water (reduce
(fn [water [xs ys]]
(let [rw (* region-width xs)
rh (* region-height ys)]
(if (< (rand) 0.25) ; Only generate water in 25% of regions
(let [[wx wy] [(rand-int-range (- rw region-width) rw)
(rand-int-range (- rh region-height) rh)]
spokes (rand-int-range 5 17) ; "spokes" are how many points around the initial water placement
points (reduce
(fn [points [angle radius]]
(let [sx (+ wx (* radius (math/cos angle)))
sy (+ wy (* radius (math/sin angle)))]
(conj points [(int sx) (int sy)])))
[]
(mapv vector
(sort (take spokes (rand-int-range-seq 0 (* math/PI 2))))
(take spokes (rand-int-range-seq 6 12))))]
(conj water (conj points (first points)))) ; Append first point to end of vector, to complete the polygon
water)))
[]
(for [xs (range 1 (inc region-division))
ys (range 1 (inc region-division))]
[xs ys]))]
(assoc world :water water)))
(defn generate-resources [world resource-types min max world-width world-height]
(let [resources (reduce
(fn [resources [type amt]]
(reduce
(fn [resources _]
(let [x (rand-int-range 0 world-width)
y (rand-int-range 0 world-height)
amt (rand-int-range 1000 5000)
size (resource-size amt)]
(if (in-water (:water world) [x y])
resources
(conj resources [x y type amt size]))))
resources
(range amt)))
[]
(for [rt resource-types
amt (take
(count resource-types)
(repeatedly (partial rand-int-range min max)))]
[rt amt]))]
(assoc world :resources resources)))