master
Abhinav Sarkar 2013-10-13 12:19:55 +05:30
parent f2ed5e513d
commit 92a0e45c67
2 changed files with 66 additions and 72 deletions

View File

@ -48,39 +48,45 @@
(close! c)))) (close! c))))
c)) c))
(defn next-pos [[x y] [vel-x vel-y] tick] (def *width* (- (.-scrollWidth (.-body js/document)) 20))
[(+ x (* vel-x tick)) (+ y (* vel-y tick))]) (def *height* (- (.-scrollHeight (.-body js/document)) 125))
(def *padding* 5)
(def width (- (.-scrollWidth (.-body js/document)) 20)) (def *paddle-size* 100)
(def height (- (.-scrollHeight (.-body js/document)) 125)) (def *paddle-width* 10)
(def padding 5) (def *ball-radius* 8)
(def paddle-size 100) (def *ball-speed* 0.33)
(def paddle-width 10) (def *init-pos* [(/ *width* 2) (/ *height* 2)])
(def ball-radius 8) (def *paddle-step* 20)
(def ball-speed 0.33) (def *max-paddle-y* (- *height* *paddle-size*))
(def init-pos [(/ width 2) (/ height 2)]) (def *ef-paddle-width* (+ *paddle-width* *padding*))
(def paddle-step 20) (def *init-paddle-pos* (/ (- *height* *paddle-size*) 2))
(def max-paddle-y (- height paddle-size)) (def *init-vel-deg-lim* [35 55])
(def ef-paddle-width (+ paddle-width padding))
(def init-paddle-pos (/ (- height paddle-size) 2))
(defn layout-game (defn layout-game
"Lays out the game screen." "Lays out the game screen."
[] []
(doto (dom/by-id "canvas") (doto (dom/by-id "canvas")
(dom/set-style! "width" (str width "px")) (dom/set-style! "width" (str *width* "px"))
(dom/set-style! "height" (str height "px"))) (dom/set-style! "height" (str *height* "px")))
(doto (dom/by-id "ball") (doto (dom/by-id "ball")
(dom/set-attr! "r" ball-radius) (dom/set-attr! "r" *ball-radius*)
(dom/set-attr! "cx" (first init-pos)) (dom/set-attr! "cx" (first *init-pos*))
(dom/set-attr! "cy" (second init-pos))) (dom/set-attr! "cy" (second *init-pos*)))
(doseq [id ["lpaddle" "rpaddle"]] (doseq [id ["lpaddle" "rpaddle"]]
(doto (dom/by-id id) (doto (dom/by-id id)
(dom/set-attr! "width" paddle-width) (dom/set-attr! "width" *paddle-width*)
(dom/set-attr! "height" paddle-size) (dom/set-attr! "height" *paddle-size*)
(dom/set-attr! "y" (/ (- height paddle-size) 2)))) (dom/set-attr! "y" (/ (- *height* *paddle-size*) 2))))
(dom/set-attr! (dom/by-id "lpaddle") "x" 0) (dom/set-attr! (dom/by-id "lpaddle") "x" 0)
(dom/set-attr! (dom/by-id "rpaddle") "x" (- width paddle-width))) (dom/set-attr! (dom/by-id "rpaddle") "x" (- *width* *paddle-width*)))
(defn initial-velocity []
(let [[l h] *init-vel-deg-lim*
sgn #(if (< % 0.5) -1 1)
deg (+ l (* (- h l) (rand)))
rad (deg->rad deg)]
(map #(* *ball-speed* %)
[(* (sgn (rand)) (sin rad)) (* (sgn (rand)) (cos rad))])))
(defn start-game (defn start-game
"Sets up the game by creating the signals and setting up the components and starts the game." "Sets up the game by creating the signals and setting up the components and starts the game."
@ -91,27 +97,23 @@
pl-pos (chan 1) ;; paddle left position signal pl-pos (chan 1) ;; paddle left position signal
pr-pos (chan 1) ;; paddle right position signal pr-pos (chan 1) ;; paddle right position signal
game-state (chan 1) ;; game state signal, the state of the game and the current score game-state (chan 1) ;; game state signal, the state of the game and the current score
init-vel (let [sgn #(if (< % 0.5) -1 1) init-vel (initial-velocity)]
deg (+ 35 (* 20 (rand)))
rad (deg->rad deg)]
(map #(* ball-speed %)
[(* (sgn (rand)) (sin rad)) (* (sgn (rand)) (cos rad))]))]
(setup-components frames game-state pos vel pl-pos pr-pos) (setup-components frames game-state pos vel pl-pos pr-pos)
;; start the game by setting the initial values of the signals ;; start the game by setting the initial values of the signals
(put! pos init-pos) (put! pos *init-pos*)
(put! vel init-vel) (put! vel init-vel)
(put! pl-pos init-paddle-pos) (put! pl-pos *init-paddle-pos*)
(put! pr-pos init-paddle-pos) (put! pr-pos *init-paddle-pos*)
(put! game-state [:moving 0]))) (put! game-state [:moving 0])))
(defn setup-components (defn setup-components
"Multiplexes the signals and sets up the components by connecting them using the signals "Creates mult(iple)s of the signals and sets up the components by connecting them using
tapped from the multiplexers. the signals tapped from the mults.
The signals are taken as parameters." The signals are taken as parameters."
[frames game-state pos vel pl-pos pr-pos] [frames game-state pos vel pl-pos pr-pos]
(let [ticks (chan) ;; ticks signal (let [ticks (chan) ;; ticks signal
ticks-m (mult ticks) ;; multiplexers for all signals ticks-m (mult ticks) ;; mult(iple)s for all signals
pos-m (mult pos) pos-m (mult pos)
vel-m (mult vel) vel-m (mult vel)
pl-pos-m (mult pl-pos) pl-pos-m (mult pl-pos)
@ -122,7 +124,7 @@
;; sustained at the ticks rate ;; sustained at the ticks rate
pl-pos-sust (sustain (tap pl-pos-m) (tap ticks-m (chan (sliding-buffer 1000)))) pl-pos-sust (sustain (tap pl-pos-m) (tap ticks-m (chan (sliding-buffer 1000))))
pr-pos-sust (sustain (tap pr-pos-m) (tap ticks-m (chan (sliding-buffer 1000))))] pr-pos-sust (sustain (tap pr-pos-m) (tap ticks-m (chan (sliding-buffer 1000))))]
;; set up the components ;; set up the components by tapping into mults
(ticker frames (tap game-state-m) ticks) (ticker frames (tap game-state-m) ticks)
(ball-positioner (tap ticks-m) (tap vel-m) (tap pos-m) pos) (ball-positioner (tap ticks-m) (tap vel-m) (tap pos-m) pos)
@ -145,9 +147,12 @@
(go (loop [] (go (loop []
(let [[state _] (<! game-state)] (let [[state _] (<! game-state)]
(do (>! ticks (<! ticks-in)) (do (>! ticks (<! ticks-in))
(if (= :gameover state) (if-not (= :gameover state)
(stop-frames) (recur)
(recur)))))))) (stop-frames))))))))
(defn next-pos [[x y] [vel-x vel-y] tick]
[(+ x (* vel-x tick)) (+ y (* vel-y tick))])
(defn ball-positioner (defn ball-positioner
"Ball Positioner component. "Ball Positioner component.
@ -170,34 +175,34 @@
(let [pos (<! pos-in)] (let [pos (<! pos-in)]
(>! pos-out (>! pos-out
(condp = (<! keys) (condp = (<! keys)
:up (max (- pos paddle-step) 0) :up (max (- pos *paddle-step*) 0)
:down (min (+ pos paddle-step) max-paddle-y))))))) :down (min (+ pos *paddle-step*) *max-paddle-y*)))))))
(defn in-y-range? [y paddle-y] (defn in-y-range? [y paddle-y]
(and (> y (- paddle-y padding)) (< y (+ paddle-y paddle-size padding)))) (and (> y (- paddle-y *padding*)) (< y (+ paddle-y *paddle-size* *padding*))))
(defn detect-x-collision [x y lpaddle-y rpaddle-y] (defn detect-x-collision [x y lpaddle-y rpaddle-y]
(cond (cond
(< x ef-paddle-width) (< x *ef-paddle-width*)
(if (in-y-range? y lpaddle-y) :collision-left :gameover) (if (in-y-range? y lpaddle-y) :collision-left :gameover)
(> x (- width ef-paddle-width)) (> x (- *width* *ef-paddle-width*))
(if (in-y-range? y rpaddle-y) :collision-right :gameover) (if (in-y-range? y rpaddle-y) :collision-right :gameover)
:else :moving)) :else :moving))
(defn detect-y-collision [y] (defn detect-y-collision [y]
(cond (cond
(< y padding) :collision-left (< y *padding*) :collision-left
(> y (- height padding)) :collision-right (> y (- *height* *padding*)) :collision-right
:else :moving)) :else :moving))
(defn collision-state? [state] (defn collision? [state]
(or (= state :collision-left) (= state :collision-right))) (or (= state :collision-left) (= state :collision-right)))
(defn adjust-vel [state v] (defn adjust-vel [state vel]
(condp = state (condp = state
:collision-left (abs v) :collision-left (abs vel)
:collision-right (- (abs v)) :collision-right (- (abs vel))
:moving v :moving vel
:gameover 0)) :gameover 0))
(defn perturb [v] (* v (+ 1 (/ (- (rand) 0.5) 25)))) (defn perturb [v] (* v (+ 1 (/ (- (rand) 0.5) 25))))
@ -217,18 +222,18 @@
[x y] (<! pos) [x y] (<! pos)
lpaddle-y (<! pl-pos) lpaddle-y (<! pl-pos)
rpaddle-y (<! pr-pos) rpaddle-y (<! pr-pos)
[xn yn] (next-pos [x y] [vel-x vel-y] tick)
[_ score] (<! game-state-in) [_ score] (<! game-state-in)
;; calculate next position and detect collision ;; calculate next position and detect collision
[xn yn] (next-pos [x y] [vel-x vel-y] tick)
x-state (detect-x-collision xn yn lpaddle-y rpaddle-y) x-state (detect-x-collision xn yn lpaddle-y rpaddle-y)
vel-xn (adjust-vel x-state vel-x)
y-state (detect-y-collision yn) y-state (detect-y-collision yn)
x-collision (collision? x-state)
y-collision (collision? y-state)
;; calculate next velocity and game state
vel-xn (adjust-vel x-state vel-x)
vel-yn (adjust-vel y-state vel-y) vel-yn (adjust-vel y-state vel-y)
x-collision (collision-state? x-state)
y-collision (collision-state? y-state)
;; calculate next game state
state-n (cond state-n (cond
(= x-state :gameover) :gameover (= x-state :gameover) :gameover
(or x-collision y-collision) :collision (or x-collision y-collision) :collision
@ -261,6 +266,9 @@
:moving "Playing" :moving "Playing"
:collision "Playing" :collision "Playing"
:gameover "Game Over")] :gameover "Game Over")]
(doto ball-el
(dom/set-attr! "cx" x)
(dom/set-attr! "cy" y))
(when-not (= fps fps-p) (when-not (= fps fps-p)
(dom/set-text! fps-el fps)) (dom/set-text! fps-el fps))
(when-not (= state state-p) (when-not (= state state-p)
@ -270,9 +278,6 @@
(when (= state :gameover) (when (= state :gameover)
(do (dom/set-text! state-el "press <space> to restart") (do (dom/set-text! state-el "press <space> to restart")
(ev/listen-once! :keypress #(when (= (:keyCode %) 32) (start-game))))) (ev/listen-once! :keypress #(when (= (:keyCode %) 32) (start-game)))))
(doto ball-el
(dom/set-attr! "cx" x)
(dom/set-attr! "cy" y))
(recur fps state-text score)))) (recur fps state-text score))))
(go-loop (go-loop
(dom/set-attr! lpaddle-el "y" (<! pl-pos))) (dom/set-attr! lpaddle-el "y" (<! pl-pos)))

View File

@ -23,17 +23,6 @@
(close! c)))) (close! c))))
c)) c))
(defn multiplex [in cs-or-n]
(let [cs (if (number? cs-or-n)
(repeatedly cs-or-n chan)
cs-or-n)]
(go (loop []
(let [x (<! in)]
(if-not (nil? x)
(do (put-all! cs x) (recur))
:done))))
cs))
(defn map-chan [f source] (defn map-chan [f source]
(let [c (chan)] (let [c (chan)]
(go (loop [] (go (loop []