Last active
April 23, 2019 20:06
-
-
Save wpcarro/791df4e656416295bfaa853330297bd5 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ;; Rewriting the example of a Finite State Machine using Clojure and | |
| ;; Haskell-inspired type annotations. Why mix the two languages? Firstly, I like | |
| ;; LISPs. Secondly, Haskell type-annotations help me organize my thoughts. | |
| ;; | |
| ;; This example was sourced from page 91 of Game Programming Patterns by Robert | |
| ;; Nystrom. | |
| ;; type State = Ducking | |
| ;; | Standing | |
| ;; | Jumping | |
| ;; | Diving | |
| ;; type Key = ReleaseDown | |
| ;; | PressDown | |
| ;; | PressB | |
| ;; type Graph a e b = Map a (Map e b) | |
| ;; release-down :: Key | |
| (def release-down "R-D") | |
| ;; press-down :: Key | |
| (def press-down "P-D") | |
| ;; press-b :: Key | |
| (def press-b "P-B") | |
| ;; fsm :: Graph State Key State | |
| (def fsm | |
| {:ducking {release-down :standing} | |
| :standing {press-down :ducking | |
| press-b :jumping} | |
| :jumping {press-down :diving} | |
| }) | |
| ;; handle-input :: State -> Key -> State | |
| (defn handle-input [state key] | |
| (get-in fsm [state key])) | |
| ;; key-pressed? :: Event -> Boolean | |
| (defn key-pressed? [event] | |
| (not (nil? event))) | |
| ;; render-state :: State -> IO () | |
| (defn render-state [state] | |
| (case state | |
| :ducking (println "___") | |
| :standing (println "-|-") | |
| :jumping (println "\\|/") | |
| :diving (println "-->"))) | |
| ;; handle-frame :: State -> Event -> State | |
| (defn handle-frame [state event] | |
| (let [new-state (if (key-pressed? event) | |
| (handle-input state event) | |
| state)] | |
| (render-state new-state) | |
| new-state)) | |
| ;; type Event = Maybe Key | |
| ;; events :: List Event | |
| (def events | |
| ;; | |
| [nil ;; standing | |
| press-down ;; ducking | |
| release-down ;; standing | |
| press-down ;; ducking | |
| release-down ;; standing | |
| press-b ;; jumping | |
| press-down ;; diving | |
| ]) | |
| ;; Intentionally throttling the loop so that it approximately goes 1FPS instead | |
| ;; of 60FPS. This is intended for educational purposes. | |
| ;; loop-game :: State -> List Events -> IO () | |
| (defn loop-game [state events] | |
| (if (empty? events) | |
| nil | |
| (let [new-state (handle-frame state (first events))] | |
| (Thread/sleep 1000) | |
| (loop-game new-state (next events))))) | |
| (loop-game :standing events) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment