MOVEMENT
This commit is contained in:
BIN
resources/public/sprite/projectile.png
Normal file
BIN
resources/public/sprite/projectile.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 302 B |
@@ -1,31 +1,111 @@
|
||||
(ns frontend.il.app
|
||||
(:require ["pixi.js" :as pixi]
|
||||
[goog.dom :as dom]))
|
||||
(:require
|
||||
[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"))
|
||||
(.addEventListener "open" #(println "Websocket opened."))
|
||||
(.addEventListener "message" #(println "Received message:" (.-data %)))
|
||||
(.addEventListener "message" #(println "Received message " (.-data %)))
|
||||
(.addEventListener "close" #(println "Websocket closed."))))
|
||||
|
||||
(defn ticker [game ticker-object]
|
||||
(let [bunny (game :bunny)]
|
||||
(set! (.-rotation bunny) (+ (.-rotation bunny) 0.01))))
|
||||
(def base-player {:meta {:type "player"
|
||||
:name "Player"
|
||||
: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 []
|
||||
(let [app (pixi/Application.)
|
||||
width (.-width js/window.screen)
|
||||
(let [width (.-width js/window.screen)
|
||||
height (.-height js/window.screen)]
|
||||
(.. app
|
||||
(init #js {:width width :height height :backgroundColor 0x1099bb})
|
||||
(init #js {:width width :height height :backgroundColor 0x222})
|
||||
(then (fn [_]
|
||||
(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"))]
|
||||
(.. texture
|
||||
(then (fn [loaded-texture]
|
||||
(let [bunny (pixi/Sprite. loaded-texture)]
|
||||
(set! (.. bunny -anchor -x) 0.5)
|
||||
(set! (.. bunny -anchor -y) 0.5)
|
||||
(set! (.. bunny -x) (/ width 2))
|
||||
(set! (.. bunny -y) (/ height 2))
|
||||
(.. app -stage (addChild bunny))
|
||||
(.. app -ticker (add (partial ticker {:bunny bunny})))))))))))))
|
||||
(init-input-handlers)
|
||||
(add-entity {:x 500 :y 500 :sprite "https://pixijs.com/assets/bunny.png"})
|
||||
(-> (.-stage app)
|
||||
(.addChild world-layer)
|
||||
(.addChild entity-layer))
|
||||
(let [e (merge {:x (-> width (/ 2) (int))
|
||||
:y (-> height (/ 2) (int))}
|
||||
base-player)
|
||||
p (entity/render {:layer entity-layer} e)
|
||||
player (assoc e :renderable p)]
|
||||
(swap! state update-in [:player] merge player)
|
||||
(.. app -ticker (add ticker))))))))
|
||||
|
||||
20
src/frontend/il/entity.cljs
Normal file
20
src/frontend/il/entity.cljs
Normal 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))
|
||||
@@ -1,10 +1,4 @@
|
||||
(ns il.constant)
|
||||
|
||||
(def world-width 4096)
|
||||
(def world-height 4096)
|
||||
|
||||
(def resources
|
||||
["zinc" "iron" "titanium" "wood" "sulfur"])
|
||||
|
||||
(def min-resources 10)
|
||||
(def max-resources 28)
|
||||
(def screen-width 800)
|
||||
(def screen-height 600)
|
||||
|
||||
@@ -5,19 +5,8 @@
|
||||
[compojure.route :as route]
|
||||
[clojure.core.async :refer [<! >! go-loop]]
|
||||
[clojure.data.json :as json]
|
||||
[il.world :as w]
|
||||
[il.constant :as consts]
|
||||
[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 [_]
|
||||
(go-websocket [in out err]
|
||||
(go-loop []
|
||||
@@ -28,7 +17,7 @@
|
||||
(if-let [msg (<! in)]
|
||||
(do
|
||||
(cond
|
||||
(= msg "world") (>! out (json/write-str world)))
|
||||
(= msg "world") (>! out "Hello World!"))
|
||||
(println msg)
|
||||
(recur))
|
||||
(println "Closed.")))))
|
||||
|
||||
@@ -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)))
|
||||
Reference in New Issue
Block a user