Another Quil sketch
Draft of 2016.08.18
May include: visualization ↘ programming ↗ &c.
Continuing from yesterday afternoon, I spent a bit more time working in ClojureScript and Quil just now, replicating a little thing from 1994 or so. It’s still not interactive, but it’s finally sinking in that working in ClojureScript can really be a lot like writing Clojure.
(ns leaves.core (:require [quil.core :as q :include-macros true] [quil.middleware :as m])) (defn random-angle "returns a random number of radians, to initialize a circular vector" [] (rand 6.28318)) (defrecord Particle [x y vx vy speed-limit]) (defn lots-of-particles "produce a collection of randomly positioned leaves" [how-many] (repeatedly how-many #(->Particle (rand-int 500) (rand-int 500) (rand-int 10) (rand-int 10) (+ 3 (rand))))) (defn lots-of-forces "produce a collection of force vectors in random orientations" [how-many] (repeatedly how-many #(random-angle))) (defn setup "set up globals, construct initial force field and leaf pile" [] (q/frame-rate 30) (q/color-mode :hsb) {:vectors (lots-of-forces 25) :particles (lots-of-particles 1000) }) (defn grid-position "returns the force field index of a leaf's position; each force field block is 100 pixels on a side, and they're numbered sequentially from the upper left corner" [leaf] (let [lx (:x leaf) ly (:y leaf) posn (+ (* 5 (int (/ ly 100))) (int (/ lx 100)))] posn )) (defn slow-speed "apply a braking force to leaves moving faster than their speed limits" [v limit] (if (pos? (- (js/Math.abs v) limit)) (* v 0.9) v)) (defn adjust-leaf "apply the appropriate force to a leaf, given its position, changing its position and velocity" [leaf force-angle] (let [force-x (q/cos force-angle) force-y (q/sin force-angle) old-x (:x leaf) old-y (:y leaf) old-vx (:vx leaf) old-vy (:vy leaf) limit (:speed-limit leaf)] (->Particle (mod (+ old-x old-vx) 500) (mod (+ old-y old-vy) 500) (slow-speed (+ old-vx force-x) limit) (slow-speed (+ old-vy force-y) limit) limit))) (defn vary-force "rotate a force field value by a small random angle" [f] (+ f (/ (rand) 100))) (defn update-state "change all the forces randomly, and update all the leaves" [state] (let [forces (:vectors state)] {:vectors (map #(vary-force %) forces) :particles (map #(adjust-leaf % (nth forces (grid-position %))) (:particles state)) })) (defn draw-leaf "draw a little circle where a single leaf is" [leaf] (q/no-stroke) (q/ellipse (:x leaf) (:y leaf) 2 2)) (defn draw-state "clear the background, and draw all the leaves" [state] (q/background 220) (q/fill 200 100 0) (doall (map draw-leaf (:particles state)))) (q/defsketch leaves :host "leaves" :features [:no-start] :size [500 500] :setup setup :update update-state :draw draw-state :middleware [m/fun-mode])