React Fruit Machine
React | Tailwind | Confetti
Hit the green SPIN buttonβ¦ You need 3 of a kindβ¦ Everyoneβs a winnerβ¦
Fruit Loops
Here is all the fruity code for this machine.
The lowest-level component is Fruit.jsx, representing one of the
fruits/icons on a wheel.
Each icon on a wheel is given a rotation, clamped to between 0 and 360 degrees.
This rotation is implemented as a 3D CSS transform, which you can see on line
9 below:
Spin the Wheels / Reels
The wheels are implemented by Reel.jsx. A reel is a collection of 12 different Fruit components, each given a rotation offset of 30 degrees from each other. It also adds some semi-transparent gradients and highlights over the top of the reel to give the impression of 3D shading (because CSS can do 3D transforms, but it doesnβt do 3D lighting / shading, so we have to fake it). Hereβs a few of them:
Gimme a Nudge
The Nudge and Hold buttons are implemented by the NudgeHoldBlock.jsx component.
This component is passed a WheelState object which holds state relevant
to each wheel of the machine. It also has methods that can be used as
callbacks from this component to update its parent state when button
clicks happen. (This is OK for a small toy app, in a larger app it might
use Pinea/Redux to manage these kinds of state updates).
Wheelspin
The main job of the WheelState class is to manage the movement
of each wheel. The position of the wheel corresponds to the rotation
that each Reel component shows. The wheels can be told to operate in
either speed-seek mode, or position-seek mode. Speed-seek is used
for normal spin-ups and spin-downs. Position-seek is used for Nudges. At
the end of a spin-down, the wheel switches from speed-seek mode to
position-seek, so that it alway ends up in an βexactβ position rather than
ending up halfway between two fruit positions.
Coordination
The top-level FruitMachine.jsx
component just needs to be concerned with things that affect all wheels
at once. Mainly this is setting them all off spinning, and checking to
see if a win has occurred. A win happens when all the reels stop with
the same position. Focussing on the spin() function, it works by
randomising the speed of each wheel, and then by setting a spinDown
countdown amount.
The driving force of the machine is a useInterval() hook that
effectively functions as the main loop of the simulation and manages
the core tasks of keeping track of time, spinning the wheels down when
their spin time is up, and checking for win states:
Acknowledgements
This fruit machine would not have been possible without the UseInterval
hook from Overreacted
A large debt is also owed to the Canvas Confetti NPM Package for its brilliant and amazingly configurable confetti implementation.