Audio interactive game for kids around letters and numbers learning
Description
Toddlers are attracted to computers, they want to play with it, press the keyboard all the time when their parents use it - pretty much for everything. I was browsing the web for games designed to help kids learn their letters and ABC when I decided to take the opportunity to build a simple game allowing the child to discover the letters, while taking an active role in building the game it self.Here is the concept:
The game displays a letter and at the same time plays an audio relating to the letter.
If the player presses the right key at the first attempt, a congratulation sound is played and lots of progress is made. If the right letter / character is found after several attempts, less progress is made, no congrats sound is played.
The child or the parents can record every sound matching the letters as well as the congrats messages. I got my daughter to record a short voice memo to match each letter and number, as well as congratulation messages that are played if the right letter is found at the first attempt.
Once the set is completed (5 letters or more), a rhyme is played in relation to the latest letter found.
Here, we used a set of rhymes amongst the numerous ABC rhymes we had gathered and that were hidden in the computer and never played. This is a way for the child to re discover them in a fun fashion.
We performed the recordings using a phone and the default voice memo app, and creating one short sound file for each letter and number.
Here is what a set looks and sounds like :
Download the game (zip package)
The package comes with a full set of sounds, that are all ... in french... . However, it will be simple to replace them all using your own.
How to play:
- Un-zip the file on your computer
- Open the file letter game_4.html in your browser, and play
How to customise the game using your own audio files :
- drop the files into the "sounds" folder
- edit the file script_lists_lettergame_4.js using a text editor.
It is a rough way of doing things, but quite simple.
Zip file includes :
- lettergame_4.html - the actual game
- style.css - the associated style sheet
- script_lists_lettergame_4.js - file to edit to add or replace the sound files to play for each letter
- sounds (folder) - where all the sound files are stored
Javascript code, css and hash tables
For enthusiasts, and to keep the same approach used throughout the blog, below is the code used for the game.Apologies to you if the code is not perfectly commented. I know it would require some tidy up to look pretty for others to use or tweak, but time is scarce.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<link rel="stylesheet" href="style.css"> | |
<script src="script_lists_lettergame_4.js"></script> | |
<script> | |
var attempt =0; | |
var charcode=0; | |
var letter = ""; | |
var rounds = 0; | |
var score =0; | |
var lettersound = ""; | |
</script> | |
</head> | |
<body> | |
<audio id="myAudio"> | |
<source src="" type="audio/mpeg"> | |
Your browser does not support the audio element. | |
</audio> | |
<div class="wrap" > | |
<p id="target" class="text-target"></p> | |
<p id="code" class="keycode-display"></p> | |
<p id="text" class="text-display"></p> | |
<div class="progress-border"> | |
<div id="progress" class="progress-color" ></div> | |
</div> | |
</div> | |
<script> | |
//initialise game : select a letter | |
pickletter(); | |
//handle a keypress event | |
function OnKeyPressed(event) { | |
var x = event.charCode; | |
//corrects the use of caps or not : all letters converted to caps | |
if (x>96 && x<123) { | |
x = x -32; | |
} | |
// corrects french keyboard numbers | |
if (listToConvert.indexOf(x)!==-1) { | |
x=convert_numbers[x]; | |
} | |
// when space pressed, play again the sound of the letter | |
if (x==32) { | |
document.getElementById("myAudio").src = "sounds/"+lettersound; | |
var y = document.getElementById("myAudio"); | |
y.play(); | |
document.getElementById("target").className="text-target"; | |
// also displays the letter again for an instant | |
var myvar = setTimeout(function () { | |
document.getElementById("target").className="text-targetfade"; | |
} | |
,500) ; | |
} | |
// main test | |
else | |
{ | |
//display the letter pressed | |
document.getElementById("code").innerHTML = String.fromCharCode(x); | |
attempt = attempt + 1; | |
//test if it's a win | |
if (String.fromCharCode(x) == letter) { | |
//stop litening to the key pressed | |
document.body.removeEventListener("keypress",OnKeyPressed); | |
//update the score | |
score = Math.min(score + Math.round(20 / attempt),100); | |
document.getElementById("text").className = "text-bravo"; | |
updateProgress(); | |
document.getElementById("target").className="text-target"; | |
//if letter found at the first attempt | |
if (attempt == 1) { | |
//play a congrats sound from the list | |
document.getElementById("myAudio").src = "sounds/" + get_random(listSoundBravo); | |
document.getElementById("text").innerHTML = "BRAVO !!!! " + attempt + " attempt"; | |
var z = document.getElementById("myAudio"); | |
z.play(); | |
//wait 4 secs and keep going | |
var myVar = setTimeout(function(){ | |
restart(); | |
}, 4000); | |
} | |
//If letter not found at first attempt | |
else { | |
//display the number of attempts and keep going | |
document.getElementById("text").innerHTML = "Well done ... " + attempt + " attempts"; | |
var myVar = setTimeout(function(){ | |
restart(); | |
}, 2000); | |
} | |
} | |
else | |
// if letter not found | |
{ | |
//each time 15 wrong attempts are made, play a reminder sound and display again the letter to be found to help | |
if (attempt % 15 == 0) { | |
document.getElementById("myAudio").src = "sounds/NImporteQuoi.m4a"; | |
var z = document.getElementById("myAudio"); | |
z.play(); | |
document.getElementById("target").className="text-target"; | |
// display the letter for an instant | |
var myvar = setTimeout(function () { | |
document.getElementById("target").className="text-targetfade"; | |
} | |
,500) ; | |
} | |
// if it is just a normal attempt, letter not found, display try again, | |
document.getElementById("text").className = "text-display"; | |
//display the letter pressed for a while | |
document.getElementById("text").innerHTML = "Not quite, your pressed " + String.fromCharCode(x) +"... try again"; | |
document.getElementById("code").className = "fade" ; | |
// then display the question mark after 1 sec | |
var myVar = setTimeout(function(){ | |
document.getElementById("code").className = "keycode-display" ; | |
document.getElementById("code").innerHTML = "?" | |
}, 1000); | |
} | |
} | |
} | |
function restart() { | |
//restart : tests if the score is 100 | |
if (score >= 100) { | |
//plays a song matching the letter found from the list | |
var song = get_random(keyToSong[charcode]); | |
document.getElementById("text").innerHTML = "Completed in only " + rounds + " letters ! Playing a song for your ! "+ song+" ... press a key to play again"; | |
document.body.addEventListener("keypress",stopsong); | |
document.getElementById("myAudio").src = "sounds/"+song; | |
var y = document.getElementById("myAudio"); | |
y.play(); | |
// initialise the score and rounds | |
rounds = 0; | |
score = 0; | |
updateProgress(); | |
} | |
// If the score is not at 100, selects a new letter | |
else { | |
pickletter(); | |
} | |
} | |
function stopsong() { | |
document.body.removeEventListener("keypress",stopsong); | |
var y = document.getElementById("myAudio"); | |
y.pause; | |
pickletter(); | |
} | |
function updateProgress() { | |
document.getElementById("progress").style.width = score+"%"; | |
} | |
function get_random(list) { | |
return list[Math.floor((Math.random()*list.length))]; | |
} | |
function pickletter() { | |
//draws a random item in the characters list | |
charcode = get_random(listCharacters); | |
// store the character as a letter | |
letter = String.fromCharCode(charcode) ; | |
document.getElementById("target").innerHTML = letter; | |
// creates the event listener to a key pressed | |
document.body.addEventListener("keypress",OnKeyPressed); | |
//increments the rounds | |
rounds= rounds + 1; | |
//initialise the attempts on the letter | |
attempt =0; | |
// displays the target letter for some time then fads out | |
document.getElementById("target").className="text-target"; | |
var myvar = setTimeout(function () { | |
document.getElementById("target").className="text-targetfade"; | |
} | |
,2000) ; | |
//displays question mark and instruction | |
document.getElementById("code").innerHTML ="?"; | |
document.getElementById("text").className = "text-display"; | |
document.getElementById("text").innerHTML = "press the matching character on the keyboard <br>press SPACE to listen and see it again"; | |
//plays one of the sounds matching the letter | |
lettersound= get_random(keyToSound[charcode]); | |
document.getElementById("myAudio").src = "sounds/"+lettersound; | |
var y = document.getElementById("myAudio"); | |
y.play(); | |
} | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var listToConvert = [ | |
224,38,233,34,39,40,167,232,33,231 | |
]; | |
var convert_numbers = { | |
224:[48], | |
38:[49], | |
233:[50], | |
34:[51], | |
39:[52], | |
40:[53], | |
167:[54], | |
232:[55], | |
33:[56], | |
231:[57] | |
}; | |
// | |
var listCharacters=[ | |
48,49,50,51,52,53,54,55,56,57,65,66,67,68, 69,70,71,72, 73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90 | |
]; | |
var keyToSound = { | |
48 : ["0.m4a"], | |
49 : ["1.m4a"], | |
50 : ["2.m4a"], | |
51 : ["3.m4a"], | |
52 : ["4.m4a"], | |
53 : ["5.m4a"], | |
54 : ["6.m4a"], | |
55 : ["7.m4a"], | |
56 : ["8.m4a"], | |
57 : ["9.m4a"], | |
65 : ["A.m4a","A.m4a"], | |
66 : ["B.m4a"], | |
67 : ["C.m4a"], | |
68 : ["D.m4a"], | |
69 : ["E.m4a"], | |
70 : ["F.m4a"], | |
71 : ["G.m4a"], | |
72 : ["H.m4a"], | |
73 : ["I.m4a"], | |
74 : ["J.m4a"], | |
75 : ["K.m4a"], | |
76 : ["L.m4a"], | |
77 : ["M.m4a"], | |
78 : ["N.m4a"], | |
79 : ["O.m4a"], | |
80 : ["P.m4a"], | |
81 : ["Q.m4a"], | |
82 : ["R.m4a"], | |
83 : ["S.m4a"], | |
84 : ["T.m4a"], | |
85 : ["U.m4a"], | |
86 : ["V.m4a"], | |
87 : ["W.m4a"], | |
88 : ["X.m4a"], | |
89 : ["Y.m4a"], | |
90 : ["Z.m4a"] | |
}; | |
var listSoundBravo = [ | |
"bravo1.m4a", | |
"bravo2.m4a", | |
"bravo3.m4a", | |
"bravowelldone.m4a" | |
]; | |
var keyToSong = { | |
48:["10 comptines10.mp3"], | |
49:["01 comptines1.mp3"], | |
50:["02 comptines2.mp3"], | |
51:["03 comptines3.mp3"], | |
52:["04 comptines4.mp3"], | |
53:["05 comptines5.mp3"], | |
54:["06 comptines6.mp3"], | |
55:["07 comptines7.mp3"], | |
56:["08 comptines8.mp3"], | |
57:["09 comptines9.mp3"], | |
65 : ["01 A comme Afrique.mp3","01 A comme Arrosoir.mp3"], | |
66 : ["02 B comme Bebes.mp3","02 B comme Basilic.mp3"], | |
67 : ["03 C comme Crocodile.mp3","03 C comme choux.mp3"], | |
68 : ["04 D comme Dromadaire.mp3","04 D comme doryphores.mp3"], | |
69 : ["05 E comme Elephant.mp3","05 E comme epouvantail.mp3"], | |
70 : ["06 F comme framboises.mp3"], | |
71 : ["07 G comme Girafe.mp3","07 G comme graines.mp3"], | |
72 : ["08 H comme Hippopotames.mp3","08 H comme hanneton.mp3"], | |
73 : ["09 I comme Insectes.mp3"], | |
74 : ["10 J comme Jaquot.mp3","10 J comme jardin.mp3"], | |
75 : ["11 K comme Kilimandjaro.mp3","11 K comme kiwi.mp3"], | |
76 : ["12 L comme Lion.mp3","12 L comme limaces.mp3"], | |
77 : ["13 M comme Margouillat.mp3","13 M comme Melon.mp3"], | |
78 : ["14 N comme navets.mp3"], | |
79 : ["15 O comme Oasis.mp3","15 O comme oignons.mp3"], | |
80 : ["16 P comme Pilon.mp3","16 P comme pomme de terre.mp3"], | |
81 : ["17 Q comme Quinine.mp3","17 Q comme quetsches.mp3"], | |
82 : ["18 R comme Recuperation.mp3","18 R comme rosier.mp3"], | |
83 : ["19 S comme Sorciers et serpents.mp3","19 S comme salades.mp3"], | |
84 : ["20 T comme Taxi-brousse.mp3","20 T comme tomates.mp3"], | |
85 : ["21 U comme urticant.mp3"], | |
86 : ["22 V comme Vautour.mp3","22 V comme ver de terre.mp3"], | |
87 : ["23 W,X,Y comme Wolof.._.mp3","23 W comme whoouhaouh.mp3"], | |
88 : ["23 W,X,Y comme Wolof.._.mp3"], | |
89 : ["16 Abecedaire.mp3"], | |
90 : ["24 Z comme Zebre et Zebu.mp3"] | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Reset */ | |
* { | |
margin: 0; | |
padding: 0; | |
} | |
html,body { | |
text-align: center; | |
height:100%; | |
width: 100%; | |
margin:0; | |
font-family: 'Montserrat', 'sans-serif'; | |
color:#424242; | |
overflow: hidden; | |
} | |
.progress-border{ | |
background: #EFF0F2; | |
border-radius: 4px; | |
width 100%; | |
height:20px; | |
padding 20px; | |
} | |
.progress-color{ | |
background: #00FF00; | |
height:20px; | |
width: 0%; | |
} | |
.fade { | |
transition: all 0.5s ease; | |
/*font-size:5px;*/ | |
opacity:0; | |
/*color: #330000;*/ | |
} | |
.display { | |
text-align: center; | |
display: table; | |
height:100%; | |
width: 100%; | |
margin:0 auto; | |
} | |
.wrap { | |
width: 50%; | |
margin-left:25%; | |
margin-right:25%; | |
/* background-color: powderblue*/ | |
} | |
p { | |
font-size: 100px; /* For lamers who don't support viewport sizing */ | |
font-size:40vmin; | |
text-align: center; | |
margin: 0; | |
} | |
p.text-target:hover | |
{ | |
color:#ff0000; | |
} | |
p.text-targetfade { | |
transition-duration: 3s; | |
transition-property: opacity; | |
transition-delay: 0s; | |
transition-timing-function: ease; | |
opacity: 0; | |
/*font-size:5px;*/ | |
/*color: #330000;*/ | |
display: inline-block; | |
color: #5E5E5E; | |
font: bold 40px arial; | |
text-decoration: none; | |
text-align: center; | |
margin: 20px auto; | |
padding: 15px 20px; | |
background: #EFF0F2; | |
border-radius: 4px; | |
border-top: 1px solid #F5F5F5; | |
box-shadow: inset 0 0 25px #E8E8E8, 0 1px 0 #C3C3C3, 0 2px 0 #C9C9C9, 0 2px 3px #333; | |
text-shadow: 0px 1px 0px #F5F5F5; | |
} | |
p.text-target { | |
/*font-size:5px;*/ | |
opacity:1; | |
/*color: #330000;*/ | |
display: inline-block; | |
color: #5E5E5E; | |
font: bold 40px arial; | |
text-decoration: none; | |
text-align: center; | |
margin: 20px auto; | |
padding: 15px 20px; | |
background: #EFF0F2; | |
border-radius: 4px; | |
border-top: 1px solid #F5F5F5; | |
box-shadow: inset 0 0 25px #E8E8E8, 0 1px 0 #C3C3C3, 0 2px 0 #C9C9C9, 0 2px 3px #333; | |
text-shadow: 0px 1px 0px #F5F5F5; | |
} | |
p.text-display { | |
display: block; | |
color: #5E5E5E; | |
font: bold 20px arial; | |
text-decoration: none; | |
text-align: center; | |
margin: 20px auto; | |
padding: 15px 20px; | |
background: #EFF0F2; | |
border-radius: 4px; | |
border-top: 1px solid #F5F5F5; | |
box-shadow: inset 0 0 25px #E8E8E8, 0 1px 0 #C3C3C3, 0 2px 0 #C9C9C9, 0 2px 3px #333; | |
text-shadow: 0px 1px 0px #F5F5F5; | |
} | |
p.text-bravo { | |
display: block; | |
color: #5E5E5E; | |
font: bold 20px arial; | |
text-decoration: none; | |
text-align: center; | |
margin: 20px auto; | |
padding: 15px 20px; | |
background: #00FF33; | |
border-radius: 4px; | |
border-top: 1px solid #F5F5F5; | |
box-shadow: inset 0 0 25px #E8E8E8, 0 1px 0 #C3C3C3, 0 2px 0 #C9C9C9, 0 2px 3px #333; | |
text-shadow: 0px 1px 0px #F5F5F5; | |
} | |
hello
ReplyDelete