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.