This commit is contained in:
2026-07-25 22:53:26 -06:00
parent ba10d04fa2
commit a179e453b1
4 changed files with 55 additions and 58 deletions

View File

@@ -36,12 +36,12 @@
(when (count outbox) (when (count outbox)
(go (go
(doseq [msg outbox] (doseq [msg outbox]
(println state) (js/console.log (clj->js state))
(println "Writing event: " msg) (js/console.log "Writing event: " (clj->js msg))
(>! tx-chan (js/JSON.stringify (clj->js msg)))))) (>! tx-chan (js/JSON.stringify (clj->js msg))))))
(assoc state :outbox [])) (assoc state :outbox []))
(defn ticker [app state layers rx-chan tx-chan t] (defn ticker [app state layers sb rx-chan tx-chan t]
(let [dt (.-deltaTime t) (let [dt (.-deltaTime t)
{world-layer :world-layer {world-layer :world-layer
entity-layer :entity-layer} layers entity-layer :entity-layer} layers
@@ -50,9 +50,9 @@
send-interval 25 ; Send every 25ms (10 tps) send-interval 25 ; Send every 25ms (10 tps)
elapsed (.-elapsedMS t) elapsed (.-elapsedMS t)
{:keys [player entities]} (-> (update @state :elapsed + elapsed) {:keys [player entities]} (-> (update @state :elapsed + elapsed)
(update/update-entities dt layers) (update/update-state :entities dt layers)
(update/update-players dt layers) (update/update-state :players dt layers)
(update/update-player dt send-interval layers entity-relative-mouse-pos) (update/update-player dt send-interval layers entity-relative-mouse-pos sb)
(update/update-from-server rx-chan) (update/update-from-server rx-chan)
(drain-outbox! tx-chan) (drain-outbox! tx-chan)
(->> (swap! state merge))) (->> (swap! state merge)))
@@ -69,8 +69,9 @@
(let [{renderable :renderable (let [{renderable :renderable
x :x x :x
y :y} thing] y :y} thing]
(set! (.. renderable -x) x) (when renderable
(set! (.. renderable -y) y))))) (set! (.. renderable -x) x)
(set! (.. renderable -y) y))))))
(defn init [] (defn init []
(let [app (doto (pixi/Application.) (let [app (doto (pixi/Application.)
@@ -93,6 +94,11 @@
layers {:entity-layer entity-layer layers {:entity-layer entity-layer
:world-layer world-layer :world-layer world-layer
:ui-layer ui-layer} :ui-layer ui-layer}
sb-callback (fn [v _] (swap! state update-in [:player :keymap] assoc :lmb v))
sb (entity/player-shoot-box
entity-layer
(partial sb-callback true)
(partial sb-callback false))
websocket (doto (js/WebSocket. (str "ws://" js/location.host "/ws")) websocket (doto (js/WebSocket. (str "ws://" js/location.host "/ws"))
(.addEventListener "open" #(go-loop [] (.addEventListener "open" #(go-loop []
(when-let [msg (<! tx-chan)] (when-let [msg (<! tx-chan)]
@@ -112,15 +118,4 @@
(.addChild world-layer) ; Bottom of the layer stack (.addChild world-layer) ; Bottom of the layer stack
(.addChild entity-layer) ; Middle of the layer stack (.addChild entity-layer) ; Middle of the layer stack
(.addChild ui-layer)) ; Top of the layer stack (.addChild ui-layer)) ; Top of the layer stack
(let [e (merge {:x (-> width (/ 2) (int)) (.. app -ticker (add (partial ticker app state layers sb rx-chan tx-chan))))))))
:y (-> height (/ 2) (int))}
(@state :player))
p (entity/render entity-layer e)
sb-callback (fn [v _] (swap! state update-in [:player :keymap] assoc :lmb v))
sb (entity/player-shoot-box
entity-layer
(partial sb-callback true)
(partial sb-callback false))
player (assoc e :renderable p :shootbox sb)]
(swap! state update-in [:player] merge player)
(.. app -ticker (add (partial ticker app state layers rx-chan tx-chan)))))))))

View File

@@ -14,9 +14,10 @@
e)) e))
(defn apply-renderable [e layers] (defn apply-renderable [e layers]
(if-not (contains? e :renderable) (if (and (nil? (e :renderable)) (e :sprite))
(let [{entity-layer :entity-layer} layers (let [{entity-layer :entity-layer} layers
renderable (entity/render entity-layer e)] renderable (entity/render entity-layer e)]
(js/console.log (clj->js e))
(assoc e :renderable renderable)) (assoc e :renderable renderable))
e)) e))
@@ -56,30 +57,25 @@
state))) state)))
;; TODO: Cleanup entities somehow ;; TODO: Cleanup entities somehow
(defn update-entities [state dt layers] (defn update-state [state key dt layers]
(let [{entities :entities} state (let [{v key} state
new-entities (update-vals entities #(-> % new-entities (update-vals v #(-> %
(apply-server-position) (apply-server-position)
(apply-renderable layers) (apply-renderable layers)
(apply-velocity dt)))] (apply-velocity dt)))]
(assoc state :entities new-entities))) (assoc state key new-entities)))
(defn update-players [state dt layers] (defn update-player [state dt send-interval layers mouse-pos sb]
(let [{players :players} state
new-players (update-vals players #(-> %
(apply-server-position)
(apply-renderable layers)
(apply-velocity dt)))]
(assoc state :players new-players)))
(defn update-player [state dt send-interval layers mouse-pos]
(let [{player :player} state (let [{player :player} state
updated-player (-> player updated-player (-> player
(apply-renderable layers) (apply-renderable layers)
(assoc :shootbox sb)
(apply-velocity dt))] (apply-velocity dt))]
(-> (assoc state :player updated-player) (if-not (nil? player)
(apply-player-position send-interval) (-> (assoc state :player updated-player)
(apply-player-shoot mouse-pos)))) (apply-player-position send-interval)
(apply-player-shoot mouse-pos))
(update state :outbox conj {:type "request-init"}))))
(defn- deep-merge [& maps] (defn- deep-merge [& maps]
(apply merge-with (apply merge-with
@@ -94,7 +90,7 @@
{:keys [type] :as msg} (async/poll! rx-chan)] {:keys [type] :as msg} (async/poll! rx-chan)]
(if-not (nil? msg) (if-not (nil? msg)
(cond (cond
(= type "init") (update state-acc :player merge msg) (= type "init") (update state-acc :player merge (dissoc msg :type))
(= type "sync") (let [entities (msg :entities) (= type "sync") (let [entities (msg :entities)
players (if-not (nil? (get-in state-acc [:player :id])) players (if-not (nil? (get-in state-acc [:player :id]))
(dissoc (msg :players) (get-in state-acc [:player :id])) (dissoc (msg :players) (get-in state-acc [:player :id]))

View File

@@ -13,24 +13,27 @@
(defn ws-handler [state state-chan player-id] (defn ws-handler [state state-chan player-id]
(go-websocket [in out err] (go-websocket [in out err]
(s/change state-chan update :players assoc player-id {:out out :in in :err err :x 0 :y 0
:data (merge p/default-player {:id player-id})})
(go-loop [] (go-loop []
(when-let [e (<! err)] (when-let [e (<! err)]
(println (.getMessage e)) (println (.getMessage e))
(recur))) (recur)))
(go-loop [] (go-loop []
(if-let [raw (<! in)] (if-let [raw (<! in)]
(when (contains? (@state :players) player-id) ; Only if player has been initialized do we accept messages (if (contains? (@state :players) player-id)
(let [msg (j/from-json raw) (let [msg (j/from-json raw)
type (get msg :type "invalid")] type (get msg :type "invalid")
state @state]
(cond (cond
(= type "position") (handler/handle-position @state state-chan player-id msg) (= type "position") (handler/handle-position state state-chan player-id msg)
(= type "shoot") (handler/handle-shoot @state state-chan player-id msg) (= type "shoot") (handler/handle-shoot state state-chan player-id msg)
(= type "invalid") (>! out "Hello World!")) (= type "request-init") (handler/handle-request-init state state-chan player-id msg)
(= type "invalid") (>! out "Invalid command!"))
(println msg) (println msg)
(println @state)) (println state)
(recur)) (recur))
(do (s/change state-chan update :players assoc player-id {:out out :in in :err err :x 0 :y 0
:data (merge p/default-player {:id player-id})})
(recur)))
(do (do
(s/change state-chan update :players dissoc player-id) (s/change state-chan update :players dissoc player-id)
(println "Closed: " player-id)))))) (println "Closed: " player-id))))))
@@ -71,17 +74,16 @@
event-state event-state
(event-state :systems)) (event-state :systems))
updated-state (swap! state conj system-state) updated-state (swap! state conj system-state)
_ (println updated-state)
entities (updated-state :entities) entities (updated-state :entities)
players (updated-state :players)] players (updated-state :players)]
(doseq [{out :out init? :initialized data :data} (vals players)] (doseq [{:keys [initialized data out] :as player} (vals players)]
(when (nil? init?)
(>! out (j/to-json (assoc data :type "init")))
(s/change state-chan update-in [:players (data :id)] assoc :init true))
(when-not (nil? out) (when-not (nil? out)
(when (nil? initialized)
(>! out (j/to-json (assoc (merge data (select-keys player [:x :y])) :type "init")))
(s/change state-chan update-in [:players (data :id)] assoc :initialized true))
(>! out (j/to-json {:type "sync" (>! out (j/to-json {:type "sync"
:entities entities :entities entities
:players players}))))) :players (update-vals players #(select-keys % [:x :y :data :sprite]))})))))
(let [elapsed (- (System/currentTimeMillis) start-time) (let [elapsed (- (System/currentTimeMillis) start-time)
sleep-time (max 0 (- 50 elapsed))] sleep-time (max 0 (- 50 elapsed))]
(<! (async/timeout sleep-time))) (<! (async/timeout sleep-time)))

View File

@@ -3,14 +3,18 @@
[il.common.velocity :as v])) [il.common.velocity :as v]))
(defn handle-position [_ state-chan player-id {x :x y :y}] (defn handle-position [_ state-chan player-id {x :x y :y}]
(println "Setting player movement: " player-id x y)
(s/change state-chan update-in [:players player-id] assoc :x x :y y)) (s/change state-chan update-in [:players player-id] assoc :x x :y y))
(defn handle-shoot [state state-chan player-id msg] (defn handle-request-init [_ state-chan player-id _]
(s/change state-chan update-in [:players player-id] dissoc :initialized))
(defn handle-shoot [_ state-chan player-id msg]
(let [bullet-id (random-uuid) (let [bullet-id (random-uuid)
; player (get-in state [:players player-id]) ; player (get-in state [:players player-id])
{tx :x ty :y player :player} msg {tx :x ty :y player :player} msg
{x :x y :y} player {x :x y :y} player
speed 25 ; TODO: Get projectile speed from player weapon speed 50 ; TODO: Get projectile speed from player weapon
velocity (v/velocity-for x y tx ty speed) velocity (v/velocity-for x y tx ty speed)
bullet {:sprite "/sprite/projectile.png" ; TODO: Render sprite based on player weapon bullet {:sprite "/sprite/projectile.png" ; TODO: Render sprite based on player weapon
:x x :x x