Color Picker Game
Wednesday, May 3, 2023
In the SwiftUI by Tutorials book by Ray Wenderlich, there is a tutorial on building RGBullsEye, which is a game for adjusting RGB Colors using sliders to match a provided random color and providing a “color score” to the user showing how well they matched it. Some users have even posted their solutions on GitHub.
I thought it would be fun to build a version of this example using Factor.
We could generate a
color by
using
random-unit
to make three random values for the red
, green
, and blue
slots. Instead, we can pick randomly from the standard color database.
: random-color ( -- color )
named-colors random named-color ;
Comparing two colors can use the rgba-distance word from the colors.distances vocabulary, returning an integer score out of 100 points:
: color-score ( color1 color2 -- n )
rgba-distance 1.0 swap - 100.0 * round >integer ;
We can define a gadget type that can be used to find our object in a gadget hierarchy.
TUPLE: color-picker-game < track ;
Given a child of the color-picker-game
instance, we can pull out the
color-preview
gadgets in a slightly fragile way by knowing where they
are in the layout:
: find-color-previews ( gadget -- preview1 preview2 )
[ color-picker-game? ] find-parent
children>> first children>> first2 ;
Using that, we can make a button that, when clicked:
- finds the two
color-preview
objects - grabs the latest color value from their models
- calculates the “color score”
- displays it by modifying the button text
: <match-button> ( -- button )
"Match Color" [
dup find-color-previews
[ model>> compute-model ] bi@
color-score "Your score: %d" sprintf
over children>> first text<< relayout
] <border-button> ;
Another button can be used to reset the color we are trying to match against
to a new random color, setting it on the model used by the left
color-preview
:
: <reset-button> ( -- button )
"Random" [
find-color-previews drop model>>
random-color swap set-model
] <border-button> ;
Using these two buttons, and some gadgets from the color picker vocabulary, we can build up our interface, choosing a random color to start, and then laying out the other components we need:
:: <color-picker-game> ( -- gadget )
vertical color-picker-game new-track { 5 5 } >>gap
random-color <model> :> left-model
\ <rgba> <color-sliders> :> ( sliders right-model )
horizontal <track>
left-model <color-preview> 1/2 track-add
right-model <color-preview> 1/2 track-add
1 track-add
sliders f track-add
right-model <color-status> f track-add
<match-button> f track-add
<reset-button> f track-add ;
We can make a main entry point, constructing the game and providing it as the main gadget:
MAIN-WINDOW: color-picker-game-window
{ { title "Color Picker Game" } }
<color-picker-game> >>gadgets ;
This is available in the development version and includes some additional features such as support for additional color spaces along with some improvements to our tabbed gadgets. Give it a try!