前提・実現したいこと
ここに質問の内容を詳しく書いてください。
HTMLとJavascriptで音階当てゲームを作っています。
現在、実装しようとしている機能は、クイズ開始前に各音の確認をするために
クリック、又はキーボードで音を鳴らす仕組みです。
発生している問題・エラーメッセージ
Google Chromeで動作確認を行っているのですが、鍵盤のキーボードをクリックしても音が鳴りません。 Chromeの検証ツールで確認したところ、下記エラーが表示されましたが、対処方法が分かりません。 Uncaught TypeError: Cannot read property 'classList' of null
該当のソースコード
Javascript
1<!DOCTYPE html> 2<html> 3<head> 4<meta charset="UTF-8"> 5<title>音当てゲーム</title> 6<script> 7var audioContext = new AudioContext(); 8var oscillator = new Array(); 9var gain = new Array(); 10var gainNode; 11var qNo,answer,cnt,total; 12var status; 13var startTime,timer1,timer2; 14var minNotoNo = 72; 15 16var doremi = ["ド","ド#","レ","レ#","ミ","ファ","ファ#","ソ","ソ#","ラ","ラ#","シ"]; 17 18var keyboard = ["Z","S","X","C","F","V","G","B","N","J","M","K"]; 19 20function init(){ 21 22for(var i=0;i<keyboard.length;i++){ 23 var notoNo; 24 25 notoNo = i+minNotoNo; 26 27var key = document.createElement("button"); 28key.id = "note" + notoNo; 29key.id = "key_" + i; 30key.onclick = hitKey; 31key.onmousedown = mouseKeyDown; 32key.onmouseup = mouseKeyUp; 33key.onmouseleave = mouseKeyUp; 34 35 36if(doremi[notoNo%12].indexOf("#") > 0){ 37 //黒鍵 38 key.classList.add("black"); 39 }else{ 40 //白鍵 41 key.classList.add("white"); 42 var baseKey = document.createElement("div"); 43 } 44 45 baseKey.appendChild(key); 46 47 document.getElementById("piano").appendChild(baseKey); 48 49 setSound(notoNo); 50 } 51 52 53 gainNode = audioContext.createGain(); 54 setVolume(); 55} 56 57function setSound(notoNo){ 58 59 var f = 440*Math.pow(2,(notoNo-69)/12); 60 61 oscillator[notoNo] = audioContext.createOscillator(); 62 gain[notoNo] = audioContext.createGain(); 63 64 65 oscillator[notoNo].connect(gain[notoNo]); 66 gain[notoNo].connect(audioContext.destination); 67 68 69 oscillator[notoNo].frequency.value = f; 70 gain[notoNo].gain.value = 0; 71 72 73 oscillator[notoNo].start(); 74 } 75 76 function mouseKeyDown(event){ 77 78 var notoNo = event.target.id.substr(4); 79 80 playKey(notoNo); 81 } 82 83 function mouseKeyUp(event){ 84 85 var notoNo = event.target.id.substr(4); 86 87 stopKey(notoNo); 88 } 89 90 document.onkeydown = function(event){ 91 92 event.preventDefault(); 93 94 for(var i=0;i<keyboard.length;i++){ 95 if(event.key == keyboard[i].toLowerCase()) playKey(i+minNotoNo); 96 } 97 }; 98 99 document.onkeyup = function(event){ 100 101 for(var i=0;i<keyboard.length;i++){ 102 if(event.key == keyboard[i].toLowerCase()) stopKey(i+minNotoNo); 103 } 104 }; 105 106 function playKey(notoNo){ 107 108 gain.value = document.getElementById("volume").value; 109 110 document.getElementById("note"+notoNo).classList.add("strike"); 111 } 112 113 function stopKey(notoNo){ 114 115 gain.value = 0; 116 117 document.getElementById("note"+notoNo).classList.remove("strike"); 118 } 119 120function hitKey(event){ 121 if(status == "question"){ 122 123 cnt++; 124 status = "answer"; 125 126 var noteNo = Number(event.target.id.split("_")[1]) + 72; 127 event.target.classList.add("red"); 128 129 sound(noteNo); 130 } 131} 132 133function sound(noteNo){ 134 //oscillatorノードの作成 135 var oscillatorNode = audioContext.createOscillator(); 136 var f = 440 * Math.pow(2,(noteNo-69) / 12); 137 oscillatorNode.frequency.setValueAtTime(f,audioContext.currentTime); 138 139 oscillatorNode.connect(gainNode); 140 gainNode.connect(audioContext.destination); 141 142 oscillatorNode.start(audioContext.currentTime); 143 oscillatorNode.stop(audioContext.currentTime + 0.2); 144 if(status == "answer")oscillatorNode.onended = checkNote; 145} 146 147function setVolume(){ 148 149 var volume = document.getElementById("volume").value; 150 gainNode.gain.setValueAtTime(volume,audioContext.currentTime); 151 document.getElementById("volumeText").innerHTML = "[" + volume + "]"; 152} 153 154 155 156function checkNote(){ 157 158 var message,key; 159 for(var i=0;i<doremi.length;i++){ 160 key = document.getElementById("key_" + i); 161 if(key.classList.contains("red")){ 162 if(key.id.split("_")[1] == answer){ 163 message = "正解![" + doremi[answer] + "]"; 164 if(cnt == 1)total++; 165 166 timer2 = setTimeout(function(){ 167 qNo++; 168 169 if(qNo < 11){ 170 startGame(); 171 }else{ 172 stopGame(); 173 } 174 },5000); 175 }else{ 176 message = "不正解!!"; 177 status = "question"; 178 } 179 key.classList.remove("red"); 180 document.getElementById("message").innerText = message; 181 } 182 } 183} 184 185function initGame(){ 186 187 total = 0; 188 qNo = 1; 189 190 document.getElementById("start").disabled = true; 191 startGame(); 192} 193 194function startGame(){ 195 196 cnt = 0; 197 status = "wait"; 198 document.getElementById("qNo").innerText = qNo; 199 document.getElementById("memo").innerText = "白鍵のみ"; 200 if(qNo > 5){ 201 document.getElementById("memo").innerText = "白鍵+黒鍵"; 202 } 203 startTime = Date.now(); 204 timer1 = setInterval(countTime,100); 205} 206 207function stop2Game(){ 208 209 status = "wait"; 210 var message = "終了 (正解数:" + total + "/" + qNo + ")" 211 document.getElementById("message").innerText = message; 212 document.getElementById("start").disabled = false; 213} 214 215function stopGame(){ 216 217 status = "wait"; 218 var message = "終了 (正解数:" + total + "/10)" 219 document.getElementById("message").innerText = message; 220 document.getElementById("start").disabled = false; 221} 222 223function countTime(){ 224 225 var time = 3 - Math.floor((Date.now() - startTime)/1000); 226 document.getElementById("message").innerHTML = "<b>" + time + "</b>"; 227 228 if(time == 0){ 229 status = "question"; 230 clearInterval(timer1); 231 document.getElementById("message").innerText = ""; 232 answer = Math.floor(Math.random() * 12); 233 234 if((qNo < 6)&&(doremi[answer].indexOf("#") > 0)) answer++; 235 sound(answer + 72); 236 } 237} 238 239function showKeyboard(){ 240 var noteNo,keyText; 241 for(var i=0;i<doremi.length;i++){ 242 noteNo = i+minNotoNo; 243 keyText = "<div id='text"+noteNo+"'>"+doremi[noteNo%12]+"</div>"; 244 document.getElementById("key_" + i).innerHTML = keyText; 245 } 246} 247</script> 248<style> 249#piano {margin-top: 10px;} 250#piano div { 251 position: relative; 252 width: 80px; 253 height: 400px; 254 float: left; 255} 256#piano button {position: absolute;} 257.white{ 258 background-color: white; 259 top: 0px; 260 width: 80px; 261 height: 400px; 262 border-radius: 20px; 263 z-index: 0; 264} 265.black{ 266 background-color: black; 267 top: 0px; 268 left: 50px; 269 width: 60px; 270 height: 240px; 271 border-radius: 20px; 272 z-index: 1; 273} 274button div{ 275 position: absolute; 276 bottom: 0px; 277 left: 0px; 278 width: 100px; 279 font-size: 20px; 280} 281white div {color: black;} 282black div {color: gray;} 283.red{background-color: red;} 284#memo {color: #0000CC;} 285#message {color: #CC0000;} 286</style> 287<body onload="init()"> 288<p>音当てゲーム</p> 289<input type="button" id="start" value="スタート" onclick="initGame()"> 290<input type="button" id="stop" value="ストップ" onclick="stop2Game()"> 291<input type="button" value="ドレミを表示" onclick="showKeyboard()"> 292【第<span id="qNo">1</span>問:<span id="memo">白鍵のみ</span>】 293<span id="message"></span> 294<hr> 295volume:<input type="range" id="volume" value="0.5" min="0" max="1" 296step="0.1" onchange="setVolume()"> 297<span id="volumeText">[0.5]</span> 298<div id="piano"></div> 299</body> 300</html> 301
試したこと
エラーの該当箇所「document.getElementById("note"+notoNo).classList.remove("strike");」
(117行目)から変数のスペルミス等確認していますがよくわかりません。
補足情報(FW/ツールのバージョンなど)
Google Chrome最新バージョン:75.0.3770.142(Official Build) (64 ビット)
回答2件
あなたの回答
tips
プレビュー