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