Search code examples
clojureprocessingquil

Update state with if on Quil


I am trying to make 10 PRINT code with Quil. I try to transform this code from the twitter post https://twitter.com/ACharLuk/status/913094845505445890 which is using luna

enter image description here

This is my code for it

(ns tenprint.core
  (:require [quil.core :as q]
            [quil.middleware :as m]))

(defn setup []
  (q/frame-rate 30)
  (q/color-mode :hsb)
  {:x 0
   :y 0
   :scale 20
   }
  )

(defn update-state [state]

  (let [x (:x state) y (:y state) s (:scale state)]
    {
     :x (do (+ x s) ((if (>= x q/width) 0)))
     :y (do (if (>= x q/width) (+ y s)) (if (>= x q/height) (+ y s)))
     :scale (+ s 0)
     }
    )
  )

(defn draw-state [state]
  (q/background 0)

  (q/stroke 255)

  ;(q/line 0 10 10 0)

  (let [x (:x state) y (:y state) s (:scale state)]
    (if (> (rand) 0.5)
      (q/line x y (+ x s) (+ y s))
      (q/line x (+ y s) (+ x s) y)
      )
    )
  )

(q/defsketch tenprint
             :title "10PRINT"
             :size [500 500]
             :setup setup
             :update update-state
             :draw draw-state
             :settings #(q/smooth 2)
             :features [:keep-on-top]
             :middleware [m/fun-mode]
             )

And it just appears like this. I was trying to split the update of states, but it says that you must not have duplicated variables to be updated

enter image description here

Thank you.


Solution

  • Your code is in the right direction and you managed to draw the first line. It crashed when update-state was called. To fix the code I did the following things:

    • Clojure works with pure functions where you cannot "set" values as you seem to wanted to do in update-state (with do only the last expression is returned, not two values). To update-state you need to return a whole new state.
    • q/height and q/widths are functions that return the height and width, so call them (surround them by parentheses) to get the number out.
    • When you redraw the background in update-state the older lines are gone, so put (q/background 0) in setup.
      • Move (q/no-loop) from update-state to the draw-state entry-point of the program.

    And stylistically I changed this:

    Below the working version:

    (ns tenprint.core
      (:require [quil.core :as q]
                [quil.middleware :as m]))
    
    (defn setup []
      (q/background 0) ; move setting background to setup, otherwise the state is overwritten
      (q/frame-rate 30)
      (q/stroke 255)
      (q/color-mode :hsb)
      {:x 0
       :y 0
       :scale 20})
    
    (defn update-state [{:keys [x y scale] :as state}] ; destructure
      ;; height and width are functions you need to `(call)` to get the value
      {:x (if (>= x (q/width)) 0 (+ x scale)) ; fix if-statements
       :y (if (>= x (q/width)) (+ y scale) y) ; 'do' does something different than you think
       :scale scale}) ; no need to add 0
    
    (defn draw-state [{:keys [x y scale] :as state}] ; destructure
      (if (>= y (q/height))
        (q/no-loop)
        (if (> (rand) 0.5)
          (q/line x y (+ x scale) (+ y scale))
          (q/line x (+ y scale) (+ x scale) y))))      
    
    (q/defsketch tenprint
      :title "10 PRINT"
      :size [500 500]
      :setup setup
      :draw draw-state
      :update update-state
      :features [:keep-on-top]
      :middleware [m/fun-mode])
    

    10PRINT