So, in the last post I laid out my plan the manage the different GUI screens for the tic-tac-toe app, promising that, with all of the big decisions already made, today would be chock-full of implementation and smooth-sailing. For the most part it actually was! It went slower than I thought, but I made steady progress. The only unforseen issue surfaced when I had to transition to a screen with the same exact layout and widgets as the previous. Here's the first of the two screens in play:
And the second:
The only difference between these two screens is the "X" vs. "O". I observed that sometimes the second screen seemed to be skipped altogether (???). Then I realized that this had to do with the combination of fast frame rates and slow mouse clicks. It's very probable that at 30 frames per second, a simple mouse click will often straddle multiple frames. When the mouse is clicked on the first screen the update
function does the following:
- detects the mouse click using
(quil/mouse-pressed?)
- persists (on the
state
data structure) the option corresponding with the position of the mouse cursor - persists (on the
state
data structure) that the subsequent frames should transition to the next screen
This all happens VERY fast. Meanwhile, the slow human finger is still pressing the mouse button. So, when the next frame comes around and we draw and update the second screen the above steps are executed again without the user even seeing the second screen or getting a chance to move the mouse to a different option. :(
So, my current solution involves saving a bit more information on the state
data structure to keep track of whether we can trust the value returned from (quil/mouse-pressed?)
. Here's a truth table that conveys what I wanted to achieve:
:ready-to-click? (in) |
(q/mouse-pressed?) (in) |
clicked? (out) |
:ready-to-click? (out) |
---|---|---|---|
true | true | true | true |
false | true | false | false |
false | false | false | true |
true | false | false | true |
And here's the code that implements the above logic:
(defn process-click [state]
(let [ready? (:ready-for-click? state)
pressed? (q/mouse-pressed?)]
(assoc state :clicked? (and ready? pressed?)
:ready-for-click? (not pressed?))))
Maybe there's some quil feature or another approach that is better or more appropriate for this kind of problem, but this works. In any case, I should have a fully-functional game by the end of tomorrow...