commit
f234077cd7
12 changed files with 695 additions and 0 deletions
@ -0,0 +1,14 @@ |
|||||||
|
.git |
||||||
|
/resources/public/js/compiled/** |
||||||
|
figwheel_server.log |
||||||
|
pom.xml |
||||||
|
*jar |
||||||
|
/lib/ |
||||||
|
/classes/ |
||||||
|
/out/ |
||||||
|
/target/ |
||||||
|
.lein-deps-sum |
||||||
|
.lein-repl-history |
||||||
|
.lein-plugins/ |
||||||
|
.repl |
||||||
|
.nrepl-port |
@ -0,0 +1,13 @@ |
|||||||
|
/resources/public/js/compiled/** |
||||||
|
figwheel_server.log |
||||||
|
pom.xml |
||||||
|
*jar |
||||||
|
/lib/ |
||||||
|
/classes/ |
||||||
|
/out/ |
||||||
|
/target/ |
||||||
|
.lein-deps-sum |
||||||
|
.lein-repl-history |
||||||
|
.lein-plugins/ |
||||||
|
.repl |
||||||
|
.nrepl-port |
@ -0,0 +1,10 @@ |
|||||||
|
#stage 1 |
||||||
|
FROM debian as debian |
||||||
|
WORKDIR /app |
||||||
|
COPY . . |
||||||
|
RUN apt update && apt install -y leiningen |
||||||
|
RUN lein cljsbuild once |
||||||
|
|
||||||
|
#stage 2 |
||||||
|
FROM nginx |
||||||
|
COPY --from=debian /app/resources/public /usr/share/nginx/html |
@ -0,0 +1,11 @@ |
|||||||
|
pipeline { |
||||||
|
agent any |
||||||
|
options { |
||||||
|
skipStagesAfterUnstable() |
||||||
|
} |
||||||
|
stages { |
||||||
|
stage('Build') { |
||||||
|
sh 'echo "Hello!"' |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,40 @@ |
|||||||
|
# pong |
||||||
|
|
||||||
|
FIXME: Write a one-line description of your library/project. |
||||||
|
|
||||||
|
## Overview |
||||||
|
|
||||||
|
FIXME: Write a paragraph about the library/project and highlight its goals. |
||||||
|
|
||||||
|
## Setup |
||||||
|
|
||||||
|
To get an interactive development environment run: |
||||||
|
|
||||||
|
|
||||||
|
lein figwheel |
||||||
|
|
||||||
|
and open your browser at [localhost:3449](http://localhost:3449/). |
||||||
|
This will auto compile and send all changes to the browser without the |
||||||
|
need to reload. After the compilation process is complete, you will |
||||||
|
get a Browser Connected REPL. An easy way to try it is: |
||||||
|
|
||||||
|
(js/alert "Am I connected?") |
||||||
|
|
||||||
|
and you should see an alert in the browser window. |
||||||
|
|
||||||
|
To clean all compiled files: |
||||||
|
|
||||||
|
lein clean |
||||||
|
|
||||||
|
To create a production build run: |
||||||
|
|
||||||
|
lein do clean, cljsbuild once min |
||||||
|
|
||||||
|
And open your browser in `resources/public/index.html`. You will not |
||||||
|
get live reloading, nor a REPL. |
||||||
|
|
||||||
|
## License |
||||||
|
|
||||||
|
Copyright © 2014 FIXME |
||||||
|
|
||||||
|
Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version. |
@ -0,0 +1,42 @@ |
|||||||
|
(ns user |
||||||
|
(:require |
||||||
|
[figwheel-sidecar.repl-api :as f])) |
||||||
|
|
||||||
|
;; user is a namespace that the Clojure runtime looks for and |
||||||
|
;; loads if its available |
||||||
|
|
||||||
|
;; You can place helper functions in here. This is great for starting |
||||||
|
;; and stopping your webserver and other development services |
||||||
|
|
||||||
|
;; The definitions in here will be available if you run "lein repl" or launch a |
||||||
|
;; Clojure repl some other way |
||||||
|
|
||||||
|
;; You have to ensure that the libraries you :require are listed in your dependencies |
||||||
|
|
||||||
|
;; Once you start down this path |
||||||
|
;; you will probably want to look at |
||||||
|
;; tools.namespace https://github.com/clojure/tools.namespace |
||||||
|
;; and Component https://github.com/stuartsierra/component |
||||||
|
|
||||||
|
|
||||||
|
(defn fig-start |
||||||
|
"This starts the figwheel server and watch based auto-compiler." |
||||||
|
[] |
||||||
|
;; this call will only work as long as your :cljsbuild and |
||||||
|
;; :figwheel configurations are at the top level of your project.clj |
||||||
|
;; and are not spread across different lein profiles |
||||||
|
|
||||||
|
;; otherwise you can pass a configuration into start-figwheel! manually |
||||||
|
(f/start-figwheel!)) |
||||||
|
|
||||||
|
(defn fig-stop |
||||||
|
"Stop the figwheel server and watch based auto-compiler." |
||||||
|
[] |
||||||
|
(f/stop-figwheel!)) |
||||||
|
|
||||||
|
;; if you are in an nREPL environment you will need to make sure you |
||||||
|
;; have setup piggieback for this to work |
||||||
|
(defn cljs-repl |
||||||
|
"Launch a ClojureScript REPL that is connected to your build and host environment." |
||||||
|
[] |
||||||
|
(f/cljs-repl)) |
@ -0,0 +1,95 @@ |
|||||||
|
(defproject pong "0.1.0-SNAPSHOT" |
||||||
|
:description "FIXME: write this!" |
||||||
|
:url "http://example.com/FIXME" |
||||||
|
:license {:name "Eclipse Public License" |
||||||
|
:url "http://www.eclipse.org/legal/epl-v10.html"} |
||||||
|
|
||||||
|
:min-lein-version "2.9.1" |
||||||
|
|
||||||
|
:dependencies [[org.clojure/clojure "1.10.0"] |
||||||
|
[org.clojure/clojurescript "1.10.773"] |
||||||
|
[org.clojure/core.async "0.4.500"]] |
||||||
|
|
||||||
|
:plugins [[lein-figwheel "0.5.20"] |
||||||
|
[lein-cljsbuild "1.1.7" :exclusions [[org.clojure/clojure]]]] |
||||||
|
|
||||||
|
:source-paths ["src"] |
||||||
|
|
||||||
|
:cljsbuild {:builds |
||||||
|
[{:id "dev" |
||||||
|
:source-paths ["src"] |
||||||
|
|
||||||
|
;; The presence of a :figwheel configuration here |
||||||
|
;; will cause figwheel to inject the figwheel client |
||||||
|
;; into your build |
||||||
|
:figwheel {:on-jsload "pong.core/on-js-reload" |
||||||
|
;; :open-urls will pop open your application |
||||||
|
;; in the default browser once Figwheel has |
||||||
|
;; started and compiled your application. |
||||||
|
;; Comment this out once it no longer serves you. |
||||||
|
:open-urls ["http://localhost:3449/index.html"]} |
||||||
|
|
||||||
|
:compiler {:main pong.core |
||||||
|
:asset-path "js/compiled/out" |
||||||
|
:output-to "resources/public/js/compiled/pong.js" |
||||||
|
:output-dir "resources/public/js/compiled/out" |
||||||
|
:source-map-timestamp true |
||||||
|
;; To console.log CLJS data-structures make sure you enable devtools in Chrome |
||||||
|
;; https://github.com/binaryage/cljs-devtools |
||||||
|
:preloads [devtools.preload]}} |
||||||
|
;; This next build is a compressed minified build for |
||||||
|
;; production. You can build this with: |
||||||
|
;; lein cljsbuild once min |
||||||
|
{:id "min" |
||||||
|
:source-paths ["src"] |
||||||
|
:compiler {:output-to "resources/public/js/compiled/pong.js" |
||||||
|
:main pong.core |
||||||
|
:optimizations :advanced |
||||||
|
:pretty-print false}}]} |
||||||
|
|
||||||
|
:figwheel {;; :http-server-root "public" ;; default and assumes "resources" |
||||||
|
;; :server-port 3449 ;; default |
||||||
|
;; :server-ip "127.0.0.1" |
||||||
|
|
||||||
|
:css-dirs ["resources/public/css"] ;; watch and update CSS |
||||||
|
|
||||||
|
;; Start an nREPL server into the running figwheel process |
||||||
|
;; :nrepl-port 7888 |
||||||
|
|
||||||
|
;; Server Ring Handler (optional) |
||||||
|
;; if you want to embed a ring handler into the figwheel http-kit |
||||||
|
;; server, this is for simple ring servers, if this |
||||||
|
|
||||||
|
;; doesn't work for you just run your own server :) (see lein-ring) |
||||||
|
|
||||||
|
;; :ring-handler hello_world.server/handler |
||||||
|
|
||||||
|
;; To be able to open files in your editor from the heads up display |
||||||
|
;; you will need to put a script on your path. |
||||||
|
;; that script will have to take a file path and a line number |
||||||
|
;; ie. in ~/bin/myfile-opener |
||||||
|
;; #! /bin/sh |
||||||
|
;; emacsclient -n +$2 $1 |
||||||
|
;; |
||||||
|
;; :open-file-command "myfile-opener" |
||||||
|
|
||||||
|
;; if you are using emacsclient you can just use |
||||||
|
;; :open-file-command "emacsclient" |
||||||
|
|
||||||
|
;; if you want to disable the REPL |
||||||
|
;; :repl false |
||||||
|
|
||||||
|
;; to configure a different figwheel logfile path |
||||||
|
;; :server-logfile "tmp/logs/figwheel-logfile.log" |
||||||
|
|
||||||
|
;; to pipe all the output to the repl |
||||||
|
;; :server-logfile false |
||||||
|
} |
||||||
|
|
||||||
|
:profiles {:dev {:dependencies [[binaryage/devtools "1.0.0"] |
||||||
|
[figwheel-sidecar "0.5.20"]] |
||||||
|
;; need to add dev source path here to get user.clj loaded |
||||||
|
:source-paths ["src" "dev"] |
||||||
|
;; need to add the compiled assets to the :clean-targets |
||||||
|
:clean-targets ^{:protect false} ["resources/public/js/compiled" |
||||||
|
:target-path]}}) |
@ -0,0 +1,8 @@ |
|||||||
|
/* some style */ |
||||||
|
|
||||||
|
body { |
||||||
|
margin: 0; |
||||||
|
display: flex; |
||||||
|
background-color: black; |
||||||
|
} |
||||||
|
|
After Width: | Height: | Size: 2.9 KiB |
@ -0,0 +1,13 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html> |
||||||
|
<head> |
||||||
|
<meta charset="UTF-8"> |
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1"> |
||||||
|
<link href="css/style.css" rel="stylesheet" type="text/css"> |
||||||
|
<link rel="icon" href="favicon.ico"> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<canvas id="game" width="200" height="100"></canvas> |
||||||
|
<script src="js/compiled/pong.js" type="text/javascript"></script> |
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,371 @@ |
|||||||
|
(ns pong.core |
||||||
|
(:require [pong.menu :as menu])) |
||||||
|
|
||||||
|
(enable-console-print!) |
||||||
|
|
||||||
|
;; define your app data so that it doesn't get over-written on reload |
||||||
|
|
||||||
|
(declare game-draw next-frame relaunch-ball game-loop) |
||||||
|
|
||||||
|
(defonce keyboard (atom {})) |
||||||
|
|
||||||
|
(def canvas (.getElementById js/document "game")) |
||||||
|
(def context (.getContext canvas "2d")) |
||||||
|
(def paddle-height 320) |
||||||
|
(def paddle-width 40) |
||||||
|
(def paddle-speed 1) |
||||||
|
(def ball-radius 20) |
||||||
|
(def ball-speed 0.75) |
||||||
|
|
||||||
|
|
||||||
|
(defn window-height |
||||||
|
[] |
||||||
|
(.-innerHeight js/window)) |
||||||
|
|
||||||
|
(defn window-width |
||||||
|
[] |
||||||
|
(.-innerWidth js/window)) |
||||||
|
|
||||||
|
(defn unit-vector |
||||||
|
[v] |
||||||
|
(let [length (Math.sqrt (reduce + (map #(Math.pow % 2) v)))] |
||||||
|
(map #(/ % length) v))) |
||||||
|
|
||||||
|
(defn contains-point? |
||||||
|
[rect x y] |
||||||
|
(and (> x (:x rect)) |
||||||
|
(< x (+ (:x rect) (:w rect))) |
||||||
|
(> y (:y rect)) |
||||||
|
(< y (+ (:y rect) (:h rect))))) |
||||||
|
|
||||||
|
(defn collision? |
||||||
|
[ball paddle] |
||||||
|
(or (contains-point? paddle (- (:x ball) (:radius ball)) (:y ball)) |
||||||
|
(contains-point? paddle (+ (:x ball) (:radius ball)) (:y ball)))) |
||||||
|
|
||||||
|
(defn apply-ball-velocity |
||||||
|
[{:keys [ball progress] :as state}] |
||||||
|
(let [velocity (map #(* % progress) (:velocity ball))] |
||||||
|
(assoc state :ball |
||||||
|
(assoc ball |
||||||
|
:x (+ (first velocity) (:x ball)) |
||||||
|
:y (+ (second velocity) (:y ball)))))) |
||||||
|
|
||||||
|
(defn bounce-ball-off-top-wall |
||||||
|
[{{y :y radius :radius [vx vy] :velocity} :ball :as state}] |
||||||
|
(if (< (- y radius) 0) |
||||||
|
(as-> state state |
||||||
|
(assoc-in state [:ball :y] radius) |
||||||
|
(assoc-in state [:ball :velocity] [vx (- vy)])) |
||||||
|
state)) |
||||||
|
|
||||||
|
(defn bounce-ball-off-bottom-wall |
||||||
|
[{{y :y radius :radius [vx vy] :velocity} :ball :as state}] |
||||||
|
(if (> (+ y radius) (window-height)) |
||||||
|
(as-> state state |
||||||
|
(assoc-in state [:ball :y] (- (window-height) radius)) |
||||||
|
(assoc-in state [:ball :velocity] [vx (- vy)])) |
||||||
|
state)) |
||||||
|
|
||||||
|
(defn bounce-ball-off-paddle |
||||||
|
[{ball-y :y [dx] :velocity} {paddle-y :y paddle-h :h}] |
||||||
|
(unit-vector [(* (- (/ dx (Math.abs dx))) (window-width)) |
||||||
|
(* (- (/ (- ball-y paddle-y) paddle-h) 0.5) (window-height))])) |
||||||
|
|
||||||
|
(defn bounce-ball-off-left-paddle |
||||||
|
[{paddle :left-paddle ball :ball :as state}] |
||||||
|
(assoc-in state [:ball :velocity] (bounce-ball-off-paddle ball paddle))) |
||||||
|
|
||||||
|
(defn bounce-ball-off-right-paddle |
||||||
|
[{paddle :right-paddle ball :ball :as state}] |
||||||
|
(assoc-in state [:ball :velocity] (bounce-ball-off-paddle ball paddle))) |
||||||
|
|
||||||
|
(defn put-ball-infront-of-left-paddle |
||||||
|
[{{:keys [radius]} :ball {:keys [x w]} :left-paddle :as state}] |
||||||
|
(assoc-in state [:ball :x] (+ x w radius))) |
||||||
|
|
||||||
|
(defn put-ball-infront-of-right-paddle |
||||||
|
[{{:keys [radius]} :ball {:keys [x w]} :right-paddle :as state}] |
||||||
|
(assoc-in state [:ball :x] (- x radius))) |
||||||
|
|
||||||
|
(defn bounce-ball-off-left-paddle? |
||||||
|
[{:keys [ball left-paddle] :as state}] |
||||||
|
(if (collision? ball left-paddle) |
||||||
|
(-> state |
||||||
|
put-ball-infront-of-left-paddle |
||||||
|
bounce-ball-off-left-paddle) |
||||||
|
state)) |
||||||
|
|
||||||
|
(defn bounce-ball-off-right-paddle? |
||||||
|
[{:keys [ball right-paddle] :as state}] |
||||||
|
(if (collision? ball right-paddle) |
||||||
|
(-> state |
||||||
|
put-ball-infront-of-right-paddle |
||||||
|
bounce-ball-off-right-paddle) |
||||||
|
state)) |
||||||
|
|
||||||
|
(defn launch-ball-left |
||||||
|
[state] |
||||||
|
(assoc state :ball (relaunch-ball -1))) |
||||||
|
|
||||||
|
(defn launch-ball-right |
||||||
|
[state] |
||||||
|
(assoc state :ball (relaunch-ball 1))) |
||||||
|
|
||||||
|
(defn increase-right-player-score |
||||||
|
[state] |
||||||
|
(update-in state [:score :right] inc)) |
||||||
|
|
||||||
|
(defn increase-left-player-score |
||||||
|
[state] |
||||||
|
(update-in state [:score :left] inc)) |
||||||
|
|
||||||
|
(defn left-player-scored |
||||||
|
[{{:keys [x radius]} :ball :as state}] |
||||||
|
(if (> (- x radius) (window-width)) |
||||||
|
(-> state |
||||||
|
launch-ball-right |
||||||
|
increase-left-player-score) |
||||||
|
state)) |
||||||
|
|
||||||
|
(defn right-player-scored |
||||||
|
[{{:keys [x radius]} :ball :as state}] |
||||||
|
(if (< (+ x radius) 0) |
||||||
|
(-> state |
||||||
|
launch-ball-left |
||||||
|
increase-right-player-score) |
||||||
|
state)) |
||||||
|
|
||||||
|
(defn apply-paddle-speed |
||||||
|
[paddle direction progress] |
||||||
|
(direction (:y paddle) (* paddle-speed progress))) |
||||||
|
|
||||||
|
(defn handle-left-player-paddle-up-movement |
||||||
|
[{:keys [progress left-paddle] :as state}] |
||||||
|
(if (:KeyW @keyboard) |
||||||
|
(assoc-in state |
||||||
|
[:left-paddle :y] |
||||||
|
(apply-paddle-speed left-paddle - progress)) |
||||||
|
state)) |
||||||
|
|
||||||
|
(defn handle-left-player-paddle-down-movement |
||||||
|
[{:keys [progress left-paddle] :as state}] |
||||||
|
(if (:KeyS @keyboard) |
||||||
|
(assoc-in state |
||||||
|
[:left-paddle :y] |
||||||
|
(apply-paddle-speed left-paddle + progress)) |
||||||
|
state)) |
||||||
|
|
||||||
|
(defn keep-left-paddle-in-bounds |
||||||
|
[{:keys [left-paddle] :as state}] |
||||||
|
(assoc-in state |
||||||
|
[:left-paddle :y] |
||||||
|
(max 0 (min (- (window-height) (:h left-paddle)) |
||||||
|
(:y left-paddle))))) |
||||||
|
|
||||||
|
(defn update-left-paddle |
||||||
|
[{:keys [progress left-paddle] :as state}] |
||||||
|
(-> state |
||||||
|
handle-left-player-paddle-down-movement |
||||||
|
handle-left-player-paddle-up-movement |
||||||
|
keep-left-paddle-in-bounds)) |
||||||
|
|
||||||
|
(defn stick-right-paddle-to-right-of-screen |
||||||
|
[{:keys [right-paddle] :as state}] |
||||||
|
(assoc-in state [:right-paddle :x] (- (window-width) (:w right-paddle)))) |
||||||
|
|
||||||
|
(defn handle-right-player-paddle-up-movement |
||||||
|
[{:keys [progress right-paddle] :as state}] |
||||||
|
(if (:ArrowUp @keyboard) |
||||||
|
(assoc-in state |
||||||
|
[:right-paddle :y] |
||||||
|
(apply-paddle-speed right-paddle - progress)) |
||||||
|
state)) |
||||||
|
|
||||||
|
(defn handle-right-player-paddle-down-movement |
||||||
|
[{:keys [progress right-paddle] :as state}] |
||||||
|
(if (:ArrowDown @keyboard) |
||||||
|
(assoc-in state |
||||||
|
[:right-paddle :y] |
||||||
|
(apply-paddle-speed right-paddle + progress)) |
||||||
|
state)) |
||||||
|
|
||||||
|
(defn player-update-right-paddle |
||||||
|
[state] |
||||||
|
(-> state |
||||||
|
handle-right-player-paddle-up-movement |
||||||
|
handle-right-player-paddle-down-movement)) |
||||||
|
|
||||||
|
(defn computer-update-right-paddle |
||||||
|
[{:keys [progress right-paddle ball] :as state}] |
||||||
|
(let [paddle-middle (+ (:y right-paddle) (/ (:h right-paddle) 2)) |
||||||
|
speed (* paddle-speed progress)] |
||||||
|
(assoc-in state [:right-paddle :y] |
||||||
|
(cond |
||||||
|
(< (:y ball) (- paddle-middle speed)) |
||||||
|
(max (- (:y right-paddle) speed) 0) |
||||||
|
(> (:y ball) (+ paddle-middle speed)) |
||||||
|
(min (+ (:y right-paddle) speed) |
||||||
|
(- (window-height) (:h right-paddle))) |
||||||
|
:else (:y right-paddle))))) |
||||||
|
|
||||||
|
(defn draw-rect |
||||||
|
[{x :x y :y w :w h :h}] |
||||||
|
(.fillRect context x y w h)) |
||||||
|
|
||||||
|
(defn fill-circle |
||||||
|
[{x :x y :y radius :radius}] |
||||||
|
(.beginPath context) |
||||||
|
(.arc context x y radius 0 (* 2 Math.PI)) |
||||||
|
(.fill context)) |
||||||
|
|
||||||
|
(defn draw-score |
||||||
|
[{:keys [left right]}] |
||||||
|
(set! (.-font context) "30px monospace") |
||||||
|
(.fillText context (str left " | " right) (/ (window-width) 2) 30)) |
||||||
|
|
||||||
|
(defn game-draw |
||||||
|
[{:keys [left-paddle right-paddle ball score] :as state}] |
||||||
|
(.clearRect context 0 0 (window-width) (window-height)) |
||||||
|
(set! (.-fillStyle context) "#FFF") |
||||||
|
(draw-rect left-paddle) |
||||||
|
(draw-rect right-paddle) |
||||||
|
(fill-circle ball) |
||||||
|
(draw-score score) |
||||||
|
state) |
||||||
|
|
||||||
|
(defn handle-return-to-menu |
||||||
|
[{:keys [keyboard] :as state}] |
||||||
|
(if (:Escape keyboard) |
||||||
|
(assoc state :on-loop menu/scene) |
||||||
|
state)) |
||||||
|
|
||||||
|
(defn game-loop |
||||||
|
[{:keys [update-right-paddle] :as state}] |
||||||
|
(-> state |
||||||
|
update-left-paddle |
||||||
|
update-right-paddle |
||||||
|
stick-right-paddle-to-right-of-screen |
||||||
|
apply-ball-velocity |
||||||
|
bounce-ball-off-top-wall |
||||||
|
bounce-ball-off-bottom-wall |
||||||
|
bounce-ball-off-left-paddle? |
||||||
|
bounce-ball-off-right-paddle? |
||||||
|
left-player-scored |
||||||
|
right-player-scored |
||||||
|
handle-return-to-menu |
||||||
|
game-draw)) |
||||||
|
|
||||||
|
(defn next-frame |
||||||
|
[last-render state] |
||||||
|
(.requestAnimationFrame js/window |
||||||
|
#(next-frame % ((:on-loop state) |
||||||
|
(merge state |
||||||
|
{:window-width (.-innerWidth js/window) |
||||||
|
:window-height (.-innerHeight js/window) |
||||||
|
:keyboard @keyboard |
||||||
|
:progress (- % last-render)}))))) |
||||||
|
|
||||||
|
(defn vec* |
||||||
|
[v d] |
||||||
|
(map #(* % d) v)) |
||||||
|
|
||||||
|
(defn one-or-minus-one |
||||||
|
[] |
||||||
|
(let [n (- (rand 2) 1)] (/ n (Math.abs n)))) |
||||||
|
|
||||||
|
(defn launch-ball [x y dx dy] |
||||||
|
{:x x |
||||||
|
:y y |
||||||
|
:radius ball-radius |
||||||
|
:velocity (vec* (unit-vector [dx dy]) ball-speed)}) |
||||||
|
|
||||||
|
(defn relaunch-ball |
||||||
|
[direction] |
||||||
|
(launch-ball (/ (window-width) 2) |
||||||
|
(rand (window-height)) |
||||||
|
(* direction (/ (window-width) 2)) |
||||||
|
(- (rand (window-height)) (/ (window-height) 2)))) |
||||||
|
|
||||||
|
(defn start-game |
||||||
|
[state update-right-paddle] |
||||||
|
(merge state |
||||||
|
{:left-paddle {:x 0.0 |
||||||
|
:y (/ (- (window-height) paddle-height) 2) |
||||||
|
:w paddle-width |
||||||
|
:h paddle-height} |
||||||
|
:right-paddle {:x (- (window-width) paddle-width) |
||||||
|
:y (/ (- (window-height) paddle-height) 2) |
||||||
|
:w paddle-width |
||||||
|
:h paddle-height} |
||||||
|
:update-right-paddle update-right-paddle |
||||||
|
:ball (relaunch-ball (one-or-minus-one)) |
||||||
|
:score {:left 0 :right 0} |
||||||
|
:on-loop game-loop})) |
||||||
|
|
||||||
|
(defn start-one-player-game |
||||||
|
[state] |
||||||
|
(println "start one player game") |
||||||
|
(start-game state computer-update-right-paddle)) |
||||||
|
|
||||||
|
(defn start-two-players-game |
||||||
|
[state] |
||||||
|
(println "start two players game") |
||||||
|
(start-game state player-update-right-paddle)) |
||||||
|
|
||||||
|
|
||||||
|
(next-frame (.now js/performance) |
||||||
|
{:on-loop menu/scene |
||||||
|
:menu-item-selected 0 |
||||||
|
:menu-items [{:txt "1 Player" |
||||||
|
:action start-one-player-game} |
||||||
|
{:txt "2 Players" |
||||||
|
:action start-two-players-game}] |
||||||
|
:context context}) |
||||||
|
|
||||||
|
(defn set-canvas-size-to-window-size |
||||||
|
[] |
||||||
|
(set! (.-width canvas) (.-innerWidth js/window)) |
||||||
|
(set! (.-height canvas) (.-innerHeight js/window))) |
||||||
|
|
||||||
|
(set-canvas-size-to-window-size) |
||||||
|
|
||||||
|
(set! (.-onresize js/window) |
||||||
|
set-canvas-size-to-window-size) |
||||||
|
|
||||||
|
;; (def update-game-state (partial swap! game-state assoc)) |
||||||
|
;; (def update-left-paddle-movement (partial update-game-state :left-paddle-movement)) |
||||||
|
;; (def update-right-paddle-movement (partial update-game-state :right-paddle-movement)) |
||||||
|
|
||||||
|
;; (swap! game-state assoc :on-loop menu-loop) |
||||||
|
;; (fn [event] |
||||||
|
;; (let [code (.-code event)] |
||||||
|
;; (case code |
||||||
|
;; "KeyW" (update-left-paddle-movement :up) |
||||||
|
;; "KeyS" (update-left-paddle-movement :down) |
||||||
|
;; "ArrowUp" (update-right-paddle-movement :up) |
||||||
|
;; "ArrowDown" (update-right-paddle-movement :down) |
||||||
|
;; "Escape" (swap! game-state assoc :on-loop menu-loop) |
||||||
|
;; nil))) |
||||||
|
|
||||||
|
;; (fn [event] |
||||||
|
;; (let [code (.-code event)] |
||||||
|
;; (case code |
||||||
|
;; "KeyW" (and (= (:left-paddle-movement @game-state) :up) |
||||||
|
;; (update-left-paddle-movement nil)) |
||||||
|
;; "KeyS" (and (= (:left-paddle-movement @game-state) :down) |
||||||
|
;; (update-left-paddle-movement nil)) |
||||||
|
;; "ArrowUp" (and (= (:right-paddle-movement @game-state) :up) |
||||||
|
;; (update-right-paddle-movement nil)) |
||||||
|
;; "ArrowDown" (and (= (:right-paddle-movement @game-state) :down) |
||||||
|
;; (update-right-paddle-movement nil)) |
||||||
|
;; nil))) |
||||||
|
|
||||||
|
(.addEventListener js/document "keydown" #(swap! keyboard assoc (keyword (.-code %)) %)) |
||||||
|
(.addEventListener js/document "keyup" #(swap! keyboard dissoc (keyword (.-code %)))) |
||||||
|
|
||||||
|
(defn on-js-reload [] |
||||||
|
;; optionally touch your app-state to force rerendering depending on |
||||||
|
;; your application |
||||||
|
;; (swap! app-state update-in [:__figwheel_counter] inc) |
||||||
|
) |
@ -0,0 +1,78 @@ |
|||||||
|
(ns pong.menu) |
||||||
|
|
||||||
|
(def next-key-ms 200) |
||||||
|
|
||||||
|
(defn decrease-next-key |
||||||
|
[{:keys [next-key progress] :as state}] |
||||||
|
(if (> next-key 0) |
||||||
|
(assoc state :next-key (- next-key progress)) |
||||||
|
state)) |
||||||
|
|
||||||
|
(defn handle-menu-up |
||||||
|
[{:keys [menu-item-selected menu-items keyboard next-key] :as state}] |
||||||
|
(if (and (or (:KeyW keyboard) (:ArrowUp keyboard)) (<= next-key 0)) |
||||||
|
(merge state |
||||||
|
{:menu-item-selected (mod (dec (+ menu-item-selected (count menu-items))) |
||||||
|
(count menu-items)) |
||||||
|
:next-key next-key-ms}) |
||||||
|
state)) |
||||||
|
|
||||||
|
(defn handle-menu-down |
||||||
|
[{:keys [menu-item-selected menu-items keyboard next-key] :as state}] |
||||||
|
(if (and (or (:KeyS keyboard) (:ArrowDown keyboard)) (<= next-key 0)) |
||||||
|
(merge state |
||||||
|
{:menu-item-selected (mod (inc menu-item-selected) (count menu-items)) |
||||||
|
:next-key next-key-ms}) |
||||||
|
state)) |
||||||
|
|
||||||
|
(defn handle-menu-selected |
||||||
|
[{:keys [menu-item-selected menu-items keyboard] :as state}] |
||||||
|
(if (:Enter keyboard) |
||||||
|
((:action (nth menu-items menu-item-selected)) |
||||||
|
state) |
||||||
|
state)) |
||||||
|
|
||||||
|
(defn draw-text-centered |
||||||
|
[context txt x y] |
||||||
|
(let [width (.-width (.measureText context txt))] |
||||||
|
(.fillText context txt (- x (/ width 2)) y))) |
||||||
|
|
||||||
|
(defn draw-menu-item |
||||||
|
[context item selected x y] |
||||||
|
(draw-text-centered context |
||||||
|
(str (when selected ">") |
||||||
|
(:txt item) |
||||||
|
(when selected "<")) |
||||||
|
x |
||||||
|
y)) |
||||||
|
|
||||||
|
(defn draw |
||||||
|
[{:keys [context menu-item-selected window-width window-height menu-items] :as state}] |
||||||
|
(.clearRect context 0 0 |
||||||
|
window-width |
||||||
|
window-height) |
||||||
|
|
||||||
|
(set! (.-fillStyle context) "#FFF") |
||||||
|
(set! (.-font context) "30px monospace") |
||||||
|
|
||||||
|
(draw-text-centered context "Pariatech's Pong" (/ window-width 2) 60) |
||||||
|
|
||||||
|
|
||||||
|
(let [middle-horizontally (/ window-width 2) |
||||||
|
offset-vertically (/ (- window-height (* (count menu-items) 40)) 2)] |
||||||
|
(doall (map-indexed #(draw-menu-item context |
||||||
|
%2 |
||||||
|
(= %1 (Math/floor menu-item-selected)) |
||||||
|
middle-horizontally |
||||||
|
(+ offset-vertically (* %1 40))) |
||||||
|
menu-items))) |
||||||
|
state) |
||||||
|
|
||||||
|
(defn scene |
||||||
|
[state] |
||||||
|
(-> state |
||||||
|
decrease-next-key |
||||||
|
handle-menu-up |
||||||
|
handle-menu-down |
||||||
|
handle-menu-selected |
||||||
|
draw)) |
Loading…
Reference in new issue