In part 2 we covered creating the wheel and getting it spinning. In this part we're going to make it into a game. In part 1 we already set the click events for each betting point on the table, now we're going to work on the setBet and spin functions. First we need to set some variables outside of any functions at the top of the script
let wager = 5;
let bet = [];
let numbersBet = [];
Here we have a set wager, the bet is for an array of objects containing the numbers bet, the bet type, wager and payout odds. The numbersBet variable is for the array of numbers that have been betted on, each number will only be placed in once and this is checked against the winning number before the search for the bets begin.
Now we go back to the setBet function. Currently it looks like this
function setBet(n, t, o){
console.log(n);
console.log(t);
console.log(o);
}
we're going to change it to this
function setBet(n, t, o){
var obj = {
amt: wager,
type: t,
odds: o,
numbers: n
};
bet.push(obj);
let numArray = n.split(',').map(Number);
for(i = 0; i < numArray.length; i++){
if(!numbersBet.includes(numArray[i])){
numbersBet.push(numArray[i]);
}
}
}
Broken down. Earlier we set the bet variable as an array ready for objects. Here, we're setting the object to be pushed into the array containing: the wager, bet type, odds and numbers bet on.
var obj = {
amt: wager,
type: t,
odds: o,
numbers: n
};
bet.push(obj);
All of this was set for each betting point in part 1. We then split the numbers into an array
let numArray = n.split(',').map(Number);
iterated through them and, if each iteration's number isn't already in the numbersBet array, add it to the array.
for(i = 0; i < numArray.length; i++){
if(!numbersBet.includes(numArray[i])){
numbersBet.push(numArray[i]);
}
}
Next we start the build on the spin function.
function spin(){}
Inside that function, we'll begin by adding a log in the console for the numbers that have been bet on to see if the numbersBet push is working correctly
console.log(numbersBet);
Then we'll set a randomly generated number between 0 & 36
var winningSpin = Math.floor(Math.random() * 36);
Next we check to see if the numbersBet array contains the winning number
if(numbersBet.includes(winningSpin)){
for(i = 0; i < bet.length; i++){
var numArray = bet[i].numbers.split(',').map(Number);
if(numArray.includes(winningSpin)){
console.log(winningSpin);
console.log('odds ' + bet[i].odds);
console.log('payout ' + ((bet[i].odds * bet[i].amt) + bet[i].amt));
}
}
}
Broken down. First, if the numbersBet array contains the random number chosen, we iterate through the bet array containing the betting information
for(i = 0; i < bet.length; i++){}
In that loop, we then take the numbers property value and split it into an array
var numArray = bet[i].numbers.split(',').map(Number);
if the array contains the winning number we get a log in the console of the winning number, the odds for the bet and the payout for the win.
if(numArray.includes(winningSpin)){
console.log(winningSpin);
console.log('odds ' + bet[i].odds);
console.log('payout ' + ((bet[i].odds * bet[i].amt) + bet[i].amt));
}
This will loop over until all the objects/bets have been checked in the bet array. Next, if the numbersBet array doesn't contain the random number we'll get a log in the console of the winning number and a no win message
else{
console.log(winningSpin);
console.log('no win');
}
Finally, we wrap up by resetting the numbersBet and bet arrays
bet = [];
numbersBet = [];
The full function so far should look like this
function spin(){
console.log(numbersBet);
var winningSpin = Math.floor(Math.random() * 36);
if(numbersBet.includes(winningSpin)){
for(i = 0; i < bet.length; i++){
var numArray = bet[i].numbers.split(',').map(Number);
if(numArray.includes(winningSpin)){
console.log(winningSpin);
console.log('odds ' + bet[i].odds);
console.log('payout ' + ((bet[i].odds * bet[i].amt) + bet[i].amt));
}
}
}else{
console.log(winningSpin);
console.log('no win');
}
bet = [];
numbersBet = [];
}
All that's left is to add in the spin button. Now we go back to the end of the buildBettingBoard function and we add the following
let spinBtn = document.createElement('div');
spinBtn.setAttribute('class', 'spinBtn');
spinBtn.innerText = 'spin';
spinBtn.onclick = function(){
spin();
};
container.append(spinBtn);
And give it some basic styling
.spinBtn{
position: relative;
top: 253px;
font-size:28px;
cursor:pointer
}
Now, after you've refreshed the page, you'll be able to place bets and get an instant win/loss message in the console. Now the basic game logic is functioning, we can get to work designing the user interface. I thought the best place to start was building the chips which will just be elements with the class "chip" with a choice of colours depending on the size of the bet. So in the CSS we add in the following
.chip{
width: 21px;
height: 21px;
background-color:#fff;
border: 3px solid;
border-radius: 100%;
position:absolute;
}
.gold{
border-color:gold;
}
.red{
border-color:red;
}
.green{
border-color:green;
}
.blue{
border-color:blue;
}
Next we want the chip to be placed on the table where the bet has been made so, within every call for setBet in the buildBettingBoard function we're going to add "this". So, for instance
setBet(num, 'outside_oerb', 1);
will become
setBet(this, num, 'outside_oerb', 1);
and the actual function
function setBet(n, t, o){}
will become
function setBet(e, n, t, o){}
then we're going to continue building on the setBet function. At the bottom of the setBet function we add the following
let chip = document.createElement('div');
chip.setAttribute('class', 'chip');
e.append(chip);
We put this at the bottom of the function because we're going to have a number on the chip representing the bet and the colour of the chip to change depending on the bet amount. All that will come a little later. For now, the chips are being placed but they're not aligned correctly. Now we have to do some aligning. It should be relatively easy given the chips are being added to elements already in place. All we have to do on our stylsheet is call upon the parent element and chip and change its positioning, like such
.tt1_block .chip{
margin-left: 19px;
margin-top: -24px;
}
.number_block .chip{
margin-left: 7px;
margin-top: -24px;
}
.wlrtl .chip{
margin-left: -9px;
margin-top: 9px;
}
.cbbb .chip{
margin-left: -4px;
margin-top: -5px;
}
.ttbbetblock .chip{
margin-left: -7px;
margin-top: -8px;
}
#wlttb_top .chip{
margin-left: -5px;
margin-top: -8px;
}
.bbtoptwo .chip{
margin-left: 108px;
margin-top: -25px;
}
.number_0 .chip{
margin-left: -8px;
margin-top: -22px;
}
.bo3_block .chip{
margin-left: 65px;
margin-top: -26px;
}
.oto_block .chip{
margin-left: 45px;
margin-top: -25px;
}
Now, when you click on a betting spot, the chip should be neatly aligned with the bet. Next, let's tidy up the board a bit and get rid of the betting spot borders. In the stylesheet go to .ttbbetblock and change it to
.ttbbetblock{
width: 19.1px;
height: 10px;
position: relative;
display: inline-block;
margin-left: 22.52px;
top: -2px;
cursor:pointer;
z-index:3;
}
Just remove the border from ..rtlbb1, .rtlbb2, .rtlbb3 and with the corner bets, remove the border from .cbbb, change its margin-left to 22.52px and change the following elements
#cbbb_1, #cbbb_4, #cbbb_5, #cbbb_7, #cbbb_9, #cbbb_11, #cbbb_12, #cbbb_15, #cbbb_16, #cbbb_18, #cbbb_20, #cbbb_22{
margin-left: 21px;
}
#cbbb_3, #cbbb_14{
margin-left: 20.5px;
}
#cbbb_6, #cbbb_17{
margin-left: 23px;
}
#cbbb_8, #cbbb_10, #cbbb_19, #cbbb_21{
margin-left: 22px;
}
Now the chips can be placed and the game is taking shape. We want the chips to disappear after the spin has taken place. For this I had to create a recursive function because, for whatever reason, either the Javascript .remove() property was only removing half of the elements at a time or the loop was iterating through only half of the elements, or it was a combination of the two
function removeChips(){
var chips = document.getElementsByClassName('chip');
if(chips.length > 0){
for(i = 0; i < chips.length; i++){
chips[i].remove();
}
removeChips();
}
}
All that's doing is checking for all the elements with the class name "chip" and if there are one or more it removes the elements, then calls back on itself and repeats the action until all of the elements have been removed. We then call on the function at the end of the spin function.
Now we want to slow things down a bit between the spin button being pushed and the results being shown. So we stop our wheel and ball from spinning by removing the animation properties from the wheel and balltrack classes. Now we can get to work on making it spin and land on the number randomly chosen. I began by placing all the numbers on the wheel in anti-clockwise order into a global array at the top of the script so it doesn't have to keep on being set
let wheelnumbersAC = [0, 26, 3, 35, 12, 28, 7, 29, 18, 22, 9, 31, 14, 20, 1, 33, 16, 24, 5, 10, 23, 8, 30, 11, 36, 13, 27, 6, 34, 17, 25, 2, 21, 4, 19, 15, 32];
and added the variables for the wheel and ballTrack underneath the calls buildWheel and buildBettingBoard at the top of the script, again so they didn't have to keep on being set with each spin
let wheel = document.getElementsByClassName('wheel')[0];
let ballTrack = document.getElementsByClassName('ballTrack')[0];
Then I created a new function called spinWheel
function spinWheel(winningSpin){}
In this function I began by iterating over the wheelnumbersAC array and calculating the angle the ballTrack should stop at compared to the number that has been chosen
for(i = 0; i < wheelnumbersAC.length; i++){
if(wheelnumbersAC[i] == winningSpin){
var degree = (i * 9.73) + 362;
}
}
I added in an extra 362 degrees so the ball wouldn't just slowly crawl at the end to the numbers closest to zero. Then I added back in the animations we took away earlier
wheel.style.cssText = 'animation: wheelRotate 5s linear infinite;';
ballTrack.style.cssText = 'animation: ballRotate 1s linear infinite;';
followed by 4 timeout functions which will slow and eventually stop the ball. First was the function set to run after 2 seconds
setTimeout(function(){
ballTrack.style.cssText = 'animation: ballRotate 2s linear infinite;';
style = document.createElement('style');
style.type = 'text/css';
style.innerText = '@keyframes ballStop {from {transform: rotate(0deg);}to{transform: rotate(-'+degree+'deg);}}';
document.head.appendChild(style);
}, 2000);
This function is slowing the ball rotation down to half the speed as well as creating a new style to stop the ball in the next function. The "ballStop" keyframes here starts at 0deg but ends at minus the degree angle calculated at the beginning of the main function. Next, after a further 4 seconds or 6 seconds in total, I switched to the ballStop keyframes
setTimeout(function(){
ballTrack.style.cssText = 'animation: ballStop 3s linear;';
}, 6000);
As the ballTrack was set to 3 seconds, the next function would follow 3 seconds later or 9 seconds in total
setTimeout(function(){
ballTrack.style.cssText = 'transform: rotate(-'+degree+'deg);';
}, 9000);
This makes sure the ball stops at the angle we want it to instead of it zapping back to zero. Finally, after 10 seconds, we stop the wheel from rotating by removing its extra styling and we remove the ballStop keyframes style
setTimeout(function(){
wheel.style.cssText = '';
style.remove();
}, 10000);
Then, underneath the winningSpin variable in the spin() function, we call on the spinWheel() function and wrap the rest of the function in a timeout set to 9 seconds.
function spin(){
console.log(numbersBet);
let winningSpin = Math.floor(Math.random() * 36);
spinWheel(winningSpin);
setTimeout(function(){
if(numbersBet.includes(winningSpin)){
for(i = 0; i < bet.length; i++){
var numArray = bet[i].numbers.split(',').map(Number);
if(numArray.includes(winningSpin)){
console.log(winningSpin);
console.log('odds ' + bet[i].odds);
console.log('payout ' + ((bet[i].odds * bet[i].amt) + bet[i].amt));
}
}
}else{
console.log(winningSpin);
console.log('no win');
}
bet = [];
numbersBet = [];
removeChips();
}, 9000);
}
Now, when you refresh the page, after you've pressed "spin" the ball should appear to land on the number generated randomly and shown to you in the console.
The full code from part 1 up to this point is available on the Codepen demo here.
The full code for this part
Javascript
let wager = 5;
let bet = [];
let numbersBet = [];
let wheelnumbersAC = [0, 26, 3, 35, 12, 28, 7, 29, 18, 22, 9, 31, 14, 20, 1, 33, 16, 24, 5, 10, 23, 8, 30, 11, 36, 13, 27, 6, 34, 17, 25, 2, 21, 4, 19, 15, 32];
let wheel = document.getElementsByClassName('wheel')[0];
let ballTrack = document.getElementsByClassName('ballTrack')[0];
function setBet(e, n, t, o){
var obj = {
amt: wager,
type: t,
odds: o,
numbers: n
};
bet.push(obj);
let numArray = n.split(',').map(Number);
for(i = 0; i < numArray.length; i++){
if(!numbersBet.includes(numArray[i])){
numbersBet.push(numArray[i]);
}
}
let chip = document.createElement('div');
chip.setAttribute('class', 'chip');
e.append(chip);
}
function spin(){
console.log(numbersBet);
var winningSpin = Math.floor(Math.random() * 36);
spinWheel(winningSpin);
setTimeout(function(){
if(numbersBet.includes(winningSpin)){
for(i = 0; i < bet.length; i++){
var numArray = bet[i].numbers.split(',').map(Number);
if(numArray.includes(winningSpin)){
console.log(winningSpin);
console.log('odds ' + bet[i].odds);
console.log('payout ' + ((bet[i].odds * bet[i].amt) + bet[i].amt));
}
}
}else{
console.log(winningSpin);
console.log('no win');
}
bet = [];
numbersBet = [];
removeChips();
}, 3000);
}
function spinWheel(winningSpin){
for(i = 0; i < wheelnumbersAC.length; i++){
if(wheelnumbersAC[i] == winningSpin){
var degree = (i * 9.73) + 362;
}
}
wheel.style.cssText = 'animation: wheelRotate 5s linear infinite;';
ballTrack.style.cssText = 'animation: ballRotate 1s linear infinite;';
setTimeout(function(){
ballTrack.style.cssText = 'animation: ballRotate 2s linear infinite;';
style = document.createElement('style');
style.type = 'text/css';
style.innerText = '@keyframes ballStop {from {transform: rotate(0deg);}to{transform: rotate(-'+degree+'deg);}}';
document.head.appendChild(style);
}, 2000);
setTimeout(function(){
ballTrack.style.cssText = 'animation: ballStop 3s linear;';
}, 6000);
setTimeout(function(){
ballTrack.style.cssText = 'transform: rotate(-'+degree+'deg);';
}, 9000);
setTimeout(function(){
wheel.style.cssText = '';
style.remove();
}, 10000);
}
function removeChips(){
var chips = document.getElementsByClassName('chip');
if(chips.length > 0){
for(i = 0; i < chips.length; i++){
chips[i].remove();
}
removeChips();
}
}
css
.spinBtn{
position: relative;
top: 253px;
font-size:28px;
cursor:pointer
}
.chip{
width: 21px;
height: 21px;
background-color:#fff;
border: 3px solid;
border-radius: 100%;
position:absolute;
}
.gold{
border-color:gold;
}
.red{
border-color:red;
}
.green{
border-color:green;
}
.blue{
border-color:blue;
}
.tt1_block .chip{
margin-left: 19px;
margin-top: -24px;
}
.number_block .chip{
margin-left: 7px;
margin-top: -24px;
}
.wlrtl .chip{
margin-left: -9px;
margin-top: 9px;
}
.cbbb .chip{
margin-left: -4px;
margin-top: -5px;
}
.ttbbetblock .chip{
margin-left: -7px;
margin-top: -8px;
}
#wlttb_top .chip{
margin-left: -5px;
margin-top: -8px;
}
.bbtoptwo .chip{
margin-left: 108px;
margin-top: -25px;
}
.number_0 .chip{
margin-left: -8px;
margin-top: -22px;
}
.bo3_block .chip{
margin-left: 65px;
margin-top: -26px;
}
.oto_block .chip{
margin-left: 45px;
margin-top: -25px;
}
.ttbbetblock{
width: 19.1px;
height: 10px;
position: relative;
display: inline-block;
margin-left: 22.52px;
top: -2px;
cursor:pointer;
z-index:3;
}
#cbbb_1, #cbbb_4, #cbbb_5, #cbbb_7, #cbbb_9, #cbbb_11, #cbbb_12, #cbbb_15, #cbbb_16, #cbbb_18, #cbbb_20, #cbbb_22{
margin-left: 21px;
}
#cbbb_3, #cbbb_14{
margin-left: 20.5px;
}
#cbbb_6, #cbbb_17{
margin-left: 23px;
}
#cbbb_8, #cbbb_10, #cbbb_19, #cbbb_21{
margin-left: 22px;
}
That's it for this part. You can now place bets, lay chips, spin the wheel, have the ball land on a designated number and see your win/loss in the console. In the next and final part, we'll be wrapping up by styling the table, tidying up the bets, repositioning the spin button, adding numbers on the chips, preventing the chip elements from being set multiple times, adding in the ability to change bet value, remove bets from the table, view win/loss messages on the screen and remove all the console logs