In this article we will create a European roulette in SwiftUI. During the process we will learn about animations, structs, enums and state variables.
As Wikipedia states:
“Roulette is a casino game named after the French word meaning little wheel. In the game, players may choose to place bets on either a single number, various groupings of numbers, the colors red or black, whether the number is odd or even, or if the numbers are high (19–36) or low (1–18)”
The European roulette has 37 distinct pockets (numbered 1 to 36) and a green pocket marked 0 (zero).
So the first thing we have to do is to model each pocket / sector of the roulette.
As we said each sector of the roulette has a number (an integer value) and a color (red, black or green). So we could model the sectors with a struct as shown below:
Then, we have to declare an array that will contain all the sectors of the roulette.
Now it is time to declare some state variables. State variables are a new concept coming with SwiftUI. @State property wrapper allows us to modify values inside a struct which would normally not be allowed because structs are value types. Also, in SwiftUI, UI elements that contain a @State variable (let’s say for example a Text element that may contain and show a String state variable) are automatically updated each time the value of the state variable changes.
We declare the following state variables and a constant called “halfSector” that will help us determine the winning sector inside ContentView struct.
The first one, holds a boolean value showing if the wheel is still animating or not. spinDegrees, holds the angle by which the wheel has pinned, rand holds the random part of the angle (we will talk about it thoroughly later) and newAngle holds the value of the angle of the sector shown after a spin.
Now it is time to declare the animation that the roulette will perform each time we hit the “SPIN” button.
This variable holds an animation object that starts fast and it becomes slower as it reaches to the end (ease out), it repeats only once, it does not autoreverses after it finishes and its duration is 3 seconds.
Determining the wining sector based on the angle of spin
Now we should create a mechanism that will return the winning sector based on the angle of spin (that will be randomly generated). So, we create the following function that takes an angle as an input and it returns a sector instance.
What the function does in Layman’s terms is that it calculates the start and end angle of each sector and it checks if the given angle is within a given sector (it loops through all sectors until it finds the correct one). If the given angle is between the [start, end) set of a sector, then it returns this sector.
We also need a function to transform the angle of spin (which is the angle by which the wheel has rotated) to the angle of the sector that it is right under the arrow and that marks the wining sector. We do this with the following function:
Putting it all together
Now we have implemented the major part of the actual implementation and logic. It is time to move to the UI implementation and finalise the logic of spinning the roulette. First, we add a Stack (vertical stack) in our view. Then we add a Text item that will show either the literal “Spining …” or a literal showing the winning sector (number and colour). After this Text item, we present an arrow image horizontally aligned to the center of the screen. This arrow will indicate the winning sector. Then, of course, we show the image of the roulette wheel. We add a rotationEffect (with spinDegrees as an angle parameter) and we also assign the spinAnimation to the animation property. Finally, we add a button with the literal “SPIN” that will trigger the spinning logic. Also, we define the button to be disabled in case that isAnimating variable is set to true. This will not enable the user to spin the roulette wheel again while it already spins.
The spinning logic and trigger
The logic that triggers the wheel spin is coded between lines 16–22. On button click, we first set the isAnimating state variable to true. Then we generate a (pseudo)random number between
1 and 360. This number represents the random part of the angle that the wheel will spin right after the button is clicked. Then, we assign this random number we generated (stored in rand variable) + 720 degrees in spinDegress variable. We add 720 degrees (equal to 2 full rotations) just for user experience reasons as this addition forces the wheel to spin at least 2 full rotations before it stops to a sector. Of course, we could assign only the random number but the wheel would not animate for a full rotation and thus, it would not be aesthetically pleasing or near reality. Finally, we transform the angle of spin to the angle of the winning sector (winning sector is the sector right below the arrow indicator) using the getAngle() function we declared above and we wait (using DispatchQueue that changes isAnimating to false after 2.9 seconds, which is almost the time where spinning animation will have finished).
The code for UI and spinning logic is shown in the code below:
You can find the complete project in this GitHub repository.
Thanks for your time! I hope you enjoyed it.