It’s about time you wrap your presents if you haven’t done so already. Christmas is 3 days away! We’ll therefore be using 22 LEDs in a simple memory game related to gift wrapping.
You’ll need:
- 5×4 5mm LEDs (yellow, red, white, blue, gree)
- 2 10mm LEDs (red & green)
- Makey Makey
- Arduino UNO
- Breadboard + wires + alligator clips
- Conductive tape
1) The game logic
This game is pretty simple, it will display a gift, with a wrapper, a ribbon and a pattern that have different colours for a few seconds, and you’ll have to remember the colours to score points. Picking a colour will be done by tapping the area next to the LEDs with the associated colour. You will consecutively be picking the wrapper, the ribbon, and then the pattern.
a- HTML
Let’s start by drawing our gift on the screen, simply with divs
<body> <div class="score">0</div> <div class="ribbon-top"></div> <div class="gift"> <div class="patterns"> <div class="pattern"></div> <div class="pattern"></div> <div class="pattern"></div> <div class="pattern"></div> <div class="pattern"></div> <div class="pattern"></div> <div class="pattern"></div> <div class="pattern"></div> <div class="pattern"></div> <div class="pattern"></div> <div class="pattern"></div> <div class="pattern"></div> <div class="pattern"></div> <div class="pattern"></div> <div class="pattern"></div> <div class="pattern"></div> <div class="pattern"></div> <div class="pattern"></div> <div class="pattern"></div> <div class="pattern"></div> </div> <div class="ribbon vertical"></div> <div class="ribbon horizontal"></div> </div> </body>
b- CSS
Now let’s style this to make it look more like a present with a bit of CSS.
body { width: 100%; height: auto; overflow: hidden; } .gift { position: relative; width: 400px; height: 500px; margin: 0 auto; border: 2px solid black; background-color: white; } .ribbon { position: absolute; width: 20px; height: 100%; border: 1px solid black; background-color: white; } .horizontal { height: 80%; left: 190px; top: 30px; -webkit-transform: rotate(90deg); } .vertical { top: 0; left: 190px; } .ribbon-top { width: 100px; height: 50px; border-radius: 50px; background-color: white; border: 1px solid black; margin: 100px auto 0 auto; } .patterns { position: absolute; width: 100%; height: 100%; } .pattern { border: 1px solid black; background-color: white; width: 50px; height: 50px; border-radius: 50px; float: left; margin: 25px 20px 20px 25px; }
c- JavaScript
var colours = ["yellow", "red", "blue", "green", "white"]; var wrapProgressSelectors =[".gift", ".ribbon, .ribbon-top", ".pattern"]; var selectedColours =[]; var wrap_progress = 0; var score = 0; pickWrapping(); function pickWrapping() { selectedColours =[]; pickWrapperColour(); pickRibbonColour(); pickPatternColour(); setTimeout(function(){ resetWrapper(); }, 1500); } function pickWrapperColour() { var random = Math.floor(Math.random()*1000%colours.length); $(wrapProgressSelectors[0]).css({'background-color': colours[random]}); selectedColours.push(colours[random]); } function pickRibbonColour() { var random = Math.floor(Math.random()*1000%colours.length); $(wrapProgressSelectors[1]).css('background-color', colours[random]); selectedColours.push(colours[random]); } function pickPatternColour() { var random = Math.floor(Math.random()*1000%colours.length); $(wrapProgressSelectors[2]).css('background-color', colours[random]); selectedColours.push(colours[random]); }
We set up the variables, and pick our first wrapper, display it for 1.5 seconds and hide it wit the resetWrapper() function:
function resetWrapper() { $('.gift, .ribbon, .ribbon-top, .pattern').css({'background-color':'white'}); }
Because the Makey Makey works with specific keyboard inputs, we assign those keys to a colour and update the display of the gift when a key is pressed:
$(document).keydown(detectKey); function detectKey(event){ var unicode=event.keyCode? event.keyCode : event.charCode; switch(unicode) { case 32: //Space updateGiftWrap(colours[0]); break; case 38: //up updateGiftWrap(colours[1]); break; case 40: //down updateGiftWrap(colours[2]); break; case 39: //right updateGiftWrap(colours[3]); break; case 37: //left updateGiftWrap(colours[4]); break; } } function updateGiftWrap(colour) { $(wrapProgressSelectors[wrap_progress]).css({'background-color': colour}); if(selectedColours[wrap_progress] == colour) { score += 10; } $('.score').text(''+score); updateWrappingStatus(); }
Once we’ve compared which colours was picked for the wrapper, the ribbon and the pattern with the original present and updated the score accordingly, we pick a new design:
function updateWrappingStatus() { if(wrap_progress > 1) { wrap_progress = 0; resetWrapper(); setTimeout(function(){ pickWrapping(); }, 1000); } else { wrap_progress++; } }
2) Adding the hardware
Now group the LEDs by colours, link each colour to 1 Arduino pin. If you’d like to know more about BreakoutJS, Arduino and Makey Makey, have a look at the Whack-A-Grinch project. We’re actually going to do something a bit simpler.
We’ll have the LEDs on all the time, but switched off on keyPress, to notice whether it’s been selected or not.
And we’ll use a green and a red LED to show if the present produced was the same as the one requested.
We need to declare the Arduino board and all the LED pins, then we light them on and finally switch them off on key press, before resetting them.
function init() { ledY = new LED(arduino, arduino.getDigitalPin(10)); ledY.on(); ledR = new LED(arduino, arduino.getDigitalPin(12)); ledR.on(); ledB = new LED(arduino, arduino.getDigitalPin(9)); ledB.on(); ledG = new LED(arduino, arduino.getDigitalPin(8)); ledG.on(); ledW = new LED(arduino, arduino.getDigitalPin(11)); ledW.on(); winLED = new LED(arduino, arduino.getDigitalPin(5)); loseLED = new LED(arduino, arduino.getDigitalPin(6)); ledColours.push(ledY, ledR, ledB, ledG, ledW); pickWrapping(); } function detectKey(event){ var unicode=event.keyCode? event.keyCode : event.charCode; switch(unicode) { case 32: //Space currentLED = ledColours[0]; playerInput.push(colours[0]); updateGiftWrap(colours[0]); break; case 38: //up currentLED = ledColours[1]; playerInput.push(colours[1]); updateGiftWrap(colours[1]); break; case 40: //down currentLED = ledColours[2]; playerInput.push(colours[2]); updateGiftWrap(colours[2]); break; case 39: //right currentLED = ledColours[3]; playerInput.push(colours[3]); updateGiftWrap(colours[3]); break; case 37: //left currentLED = ledColours[4]; playerInput.push(colours[4]); updateGiftWrap(colours[4]); break; } } function updateGiftWrap(colour) { currentLED.off(); $(wrapProgressSelectors[wrap_progress]).css({'background-color': colour}); $('.score').text(''+score); setTimeout(function(){ currentLED.on(); updateWrappingStatus(); currentLED = ""; }, 100); }
I am going to update the score to show only the number of gifts properly wrapped, instead of increasing it per correct colour.
That way, if the whole wrapping is correct, I can light up the green LED, and if not, the red one. I reset these when I pick a new wrapping instruction.
function updateScore (){ var total = 0; for(var i = 0; i<selectedColours.length; i++){ if(selectedColours[i] == playerInput[i]){ total++; } } if(total == 3){ winLED.blink(200,4); } else { loseLED.blink(300,4); } setTimeout(function(){ resetWrapper(); pickWrapping(); }, 1000); }