html5手机游戏—五线谱打音符
1.[用五线谱打唱名]
2.[用唱名打五线谱]
3.[无限练习模式]
用来熟悉五线谱上音符的位置
代码不难,这回注释还是有认真写的[只是废代码没有全部删除。。。]
效果图:
---
在线地址:
http://wangxinsheng.herokuapp.com/staffgame
---
代码:
index.html
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <meta name="description" content="html5 staff game"> 6 <meta name="keywords" content="staff,html5,canvas,web,game"> 7 <meta name="author" content="WangXinsheng"> 8 <meta name="apple-mobile-web-app-capable" content="yes"> 9 <meta name="apple-mobile-web-app-status-bar-style" content="black"> 10 <meta name="viewport" id="viewport" content="width = device-width, initial-scale = 1, minimum-scale = 1, maximum-scale = 1, user-scalable=no"> 11 <meta http-equiv="X-UA-Compatible" content="chrome=1"> 12 <meta http-equiv="Pragma" content="no-cache"> 13 <meta http-equiv="Cache-Control" content="no-cache"> 14 <meta equiv="Expires" content="0"> 15 <meta http-equiv="content-script-type" content="text/javascript"> 16 <link type="image/x-icon" rel="shortcut icon" href="img/staffFavicon.ico" /> 17 <title>CopyRight©WangXinsheng</title> 18 <script src="requestNextAnimationFrame.js"></script> 19 <style type="text/css"> 20 html {color:#000;background:#fff;margin:0px;} 21 body {-webkit-user-select:none;margin:0px;} 22 #gameWorld{cursor:pointer;} 23 #btn_start{color:red;font-size:40px;font-weight:bold;z-index:999;background:#fff;text-align:center;overflow:hidden;} 24 #btn_start p {vertical-align:middle;cursor:pointer;background:yellow;margin:20px 0px;} 25 #scoreC,#lx{width:100%;color:red;font-size:20px;font-weight:bold;z-index:999;display:none;cursor:pointer;} 26 #btn_start #copy {font-size:15px;vertical-align:middle;cursor:pointer;background:white;color:blue;} 27 </style> 28 </head> 29 <body> 30 <section> 31 <div style='position:absolute;left:0px;top:0px;100%;height:100%' id='btn_start'> 32 <p id='s1' onclick='javascript:staffGameGo(0,false);'>五线谱打唱名</p> 33 <p id='s2' onclick='javascript:staffGameGo(1,false);'>唱名打五线谱</p> 34 <p id='s3' onclick='javascript:staffGameGo(0,true);'>无限练习<br />五线谱打唱名</p> 35 <p id='s4' onclick='javascript:staffGameGo(1,true);'>无限练习<br />唱名打五线谱</p> 36 <p id='copy'>powered by 王欣盛<br />2015/01/22+1+1<br />wangxsh42@126.com</p> 37 </div> 38 <div style='position:absolute;left:0px;top:0px;' id='scoreC'> 39 </div> 40 <div style='position:absolute;left:0px;top:0px;' id='lx'> 41 </div> 42 <canvas id="gameWorld" style="position: absolute; left: 0px; top: 0px;"> 43 <p>You need a modern browser to view this.</p> 44 </canvas> 45 <canvas id="gameWorldTouch" style="position: absolute; left: 0px; top: 0px;display:none;"> 46 </canvas> 47 </section> 48 </body> 49 <script src="staffGame.js"></script> 50 </html>
staffGame.js
1 ; 2 var debug = true; 3 var gameWorld = function (mode,goOn) { 4 //this.mode = mode; 5 /*function init params*/ 6 function doVarInit() { 7 //总线数 8 allLine = gyj.x + dyj.x + gy.x + dy.x + doo.x; 9 //总间数 10 allGap = gyj.j + dyj.j + gy.j + dy.j + doo.j; 11 if(debug) 12 console.log("总线数 "+allLine,"总间数 "+allGap); 13 jxObjLst=[]; 14 djBtnLst=[]; 15 circleDoLst=[]; 16 wxpDoLst=[]; 17 } 18 /*function on resize the window*/ 19 function doSize() { 20 if(!picIsLoaded()){setTimeout(doSize,200);} 21 document.getElementById("gameWorldTouch").style.display="block"; 22 caW = window.innerWidth; 23 caH = window.innerHeight; 24 caObj.width = caW; 25 caObj.height = caH; 26 caObj.style.width = caW + "px"; 27 caObj.style.height = caH + "px"; 28 caTObj.width = caW; 29 caTObj.height = caH; 30 caTObj.style.width = caW + "px"; 31 caTObj.style.height = caH + "px"; 32 bdjPX =Math.floor( caW / 80); 33 lastFpsUpdateTime = new Date; 34 lastFpsUpdateTimeBDJ = new Date; 35 score = 0; 36 wrong = 0; 37 /*线宽,间宽计算*/ 38 //1/3为五线谱,或按钮 39 buttonH = parseInt(caH / 3); 40 if(mode==0){ 41 //五线谱 高度 42 buttonH = parseInt(caH / 3 * 2); 43 //线宽为间宽的0.5 44 lineW = parseInt(buttonH / (allGap*2+allLine)); 45 //间宽 46 gapW = lineW * 2; 47 /*线等高于间 补丁,线太细就太难点中了*/ 48 lineW = parseInt(buttonH / (allGap+allLine)); 49 gapW = lineW; 50 //最高音 51 highest = gyj.x + gyj.j + gy.x + gy.j; 52 //最低音 53 low = dyj.x + dyj.j + dy.x + dy.j; 54 55 if(debug) 56 console.log("线宽 "+lineW,"间宽 "+gapW); 57 wxpO = new wxp(caH,caW,buttonH,gyj,dyj,gy,dy,doo,allLine,allGap,lineW,gapW,mode,picsLst); 58 wxpO.draw(caCt); 59 //gen("circleDo"); 60 61 /*生成间线对象列表*/ 62 if(debug)console.log("线间对象列表---Start"); 63 var nowTop = caH - (lineW * allLine + gapW * allGap) + 0.5; 64 var high = 0; 65 // 高音谱上加 66 var base = gy.x + gy.j; 67 for(i=gyj.x+gyj.j;i>=1;i--){ 68 if(i%2==0){ 69 high = lineW; 70 }else{ 71 high = gapW; 72 } 73 jxObjLst.push({"v":(base+i),"top":nowTop,"high":high,"type":i%2==0?"Line":"gap"}); 74 if(debug)console.log("gyj: v "+(base+i),"top "+nowTop,"high "+high,"type "+(i%2==0?"Line":"gap")); 75 nowTop += high; 76 } 77 // 高音谱 78 base = 0; 79 for(i=gy.x+gy.j;i>=1;i--){ 80 if(i%2==0){ 81 high = lineW; 82 }else{ 83 high = gapW; 84 } 85 jxObjLst.push({"v":(base+i),"top":nowTop,"high":high,"type":i%2==0?"Line":"gap"}); 86 if(debug)console.log("gy: v "+(base+i),"top "+nowTop,"high "+high,"type "+(i%2==0?"Line":"gap")); 87 nowTop += high; 88 } 89 // doo 90 jxObjLst.push({"v":0,"top":nowTop,"high":lineW,"type":"Line"}); 91 if(debug)console.log("doo: v "+0,"top "+nowTop,"high "+lineW,"type "+"Line"); 92 nowTop += lineW; 93 // 低音谱 94 base = 0; 95 for(i=1;i<=dy.x+dy.j;i++){ 96 if(i%2==0){ 97 high = lineW; 98 }else{ 99 high = gapW; 100 } 101 jxObjLst.push({"v":(base-i),"top":nowTop,"high":high,"type":i%2==0?"Line":"gap"}); 102 if(debug)console.log("dy: v "+(base-i),"top "+nowTop,"high "+high,"type "+(i%2==0?"Line":"gap")); 103 nowTop += high; 104 } 105 // 低音谱下加 106 base = -dy.x-dy.j; 107 for(i=1;i<=dyj.x+dyj.j;i++){ 108 if(i%2==0){ 109 high = lineW; 110 }else{ 111 high = gapW; 112 } 113 jxObjLst.push({"v":(base-i),"top":nowTop,"high":high,"type":i%2==0?"Line":"gap"}); 114 if(debug)console.log("dyj: v "+(base-i),"top "+nowTop,"high "+high,"type "+(i%2==0?"Line":"gap")); 115 nowTop += high; 116 } 117 if(debug)console.log("线间对象列表---End"); 118 119 }else if(mode==1){ 120 /*五线谱*/ 121 //五线谱 高度 122 buttonH = parseInt(caH / 3 * 2); 123 //线宽为间宽的0.5 124 lineW = parseInt(buttonH / (allGap*2+allLine)); 125 //间宽 126 gapW = lineW * 2; 127 /*线等高于间 补丁,线太细就太难点中了*/ 128 lineW = parseInt(buttonH / (allGap+allLine)); 129 gapW = lineW; 130 //最高音 131 highest = gyj.x + gyj.j + gy.x + gy.j; 132 //最低音 133 low = dyj.x + dyj.j + dy.x + dy.j; 134 //五线谱最左边 135 wxpDoLeft = gapW * 6; 136 137 if(debug) 138 console.log("线宽 "+lineW,"间宽 "+gapW); 139 wxpO = new wxp(caH,caW,buttonH,gyj,dyj,gy,dy,doo,allLine,allGap,lineW,gapW,mode,picsLst); 140 wxpO.draw(caCt); 141 //gen("circleDo"); 142 143 /*生成间线对象列表*/ 144 if(debug)console.log("线间对象列表---Start"); 145 var nowTop = 0; 146 var high = 0; 147 // 高音谱上加 148 var base = gy.x + gy.j; 149 for(i=gyj.x+gyj.j;i>=1;i--){ 150 if(i%2==0){ 151 high = lineW; 152 }else{ 153 high = gapW; 154 } 155 jxObjLst.push({"v":(base+i),"top":nowTop,"high":high,"type":i%2==0?"Line":"gap"}); 156 if(debug)console.log("gyj: v "+(base+i),"top "+nowTop,"high "+high,"type "+(i%2==0?"Line":"gap")); 157 nowTop += high; 158 } 159 // 高音谱 160 base = 0; 161 for(i=gy.x+gy.j;i>=1;i--){ 162 if(i%2==0){ 163 high = lineW; 164 }else{ 165 high = gapW; 166 } 167 jxObjLst.push({"v":(base+i),"top":nowTop,"high":high,"type":i%2==0?"Line":"gap"}); 168 if(debug)console.log("gy: v "+(base+i),"top "+nowTop,"high "+high,"type "+(i%2==0?"Line":"gap")); 169 nowTop += high; 170 } 171 // doo 172 jxObjLst.push({"v":0,"top":nowTop,"high":lineW,"type":"Line"}); 173 if(debug)console.log("doo: v "+0,"top "+nowTop,"high "+lineW,"type "+"Line"); 174 nowTop += lineW; 175 // 低音谱 176 base = 0; 177 for(i=1;i<=dy.x+dy.j;i++){ 178 if(i%2==0){ 179 high = lineW; 180 }else{ 181 high = gapW; 182 } 183 jxObjLst.push({"v":(base-i),"top":nowTop,"high":high,"type":i%2==0?"Line":"gap"}); 184 if(debug)console.log("dy: v "+(base-i),"top "+nowTop,"high "+high,"type "+(i%2==0?"Line":"gap")); 185 nowTop += high; 186 } 187 // 低音谱下加 188 base = -dy.x-dy.j; 189 for(i=1;i<=dyj.x+dyj.j;i++){ 190 if(i%2==0){ 191 high = lineW; 192 }else{ 193 high = gapW; 194 } 195 jxObjLst.push({"v":(base-i),"top":nowTop,"high":high,"type":i%2==0?"Line":"gap"}); 196 if(debug)console.log("dyj: v "+(base-i),"top "+nowTop,"high "+high,"type "+(i%2==0?"Line":"gap")); 197 nowTop += high; 198 } 199 if(debug)console.log("线间对象列表---End"); 200 /*唱名按钮*/ 201 var rw = Math.floor(caW / 8); 202 var rh = Math.floor((caH - Math.ceil(buttonH)) / 4); 203 var r = rw<rh?rw:rh; 204 if(debug)console.log("唱名打击按钮半径: ",rw,rh,r); 205 for(var i=0;i<7;i++){ 206 var name = ((i==0)?"do":(i==1)?"re":(i==2)?"mi":(i==3)?"fa":(i==4)?"so":(i==5)?"la":(i==6)?"si":"do"); 207 var diff = Math.floor(caH - Math.ceil(buttonH)); 208 var top = 0; 209 var left = 0; 210 if(i<3){ 211 top = Math.ceil(buttonH) + Math.floor(diff / 4); 212 left = (caW / 3) * (0.5 + i%3); 213 }else{ 214 top = Math.ceil(buttonH) + Math.floor(diff / 4 * 3); 215 left = (caW / 4) * (0.5 + (i-3)%4); 216 } 217 djBtnLst.push(new djBtn(bgCLst[i],fontCLst[i],name,name,top,r,left)); 218 djBtnLst[i].draw(caCt); 219 } 220 } 221 222 } 223 function gen(name) { 224 /*product object*/ 225 switch(name){ 226 case "circleDo": 227 //音值 228 var v = parseInt( 229 Math.random()>0.34 230 ?Math.random()*(highest) 231 :-1*low+Math.random()*(low) 232 ); 233 //唱名 234 var vT = Math.abs(v % 7); 235 vT = v<0?7-vT:vT; 236 //音阶 237 var yj = (v / 7)>0?Math.floor(v / 7):Math.ceil(v / 7); 238 var name2 = 239 v<0?((yj-1)+'').replace('-','↓'):((yj>=1&&v!=6)?"↑":'') 240 +((yj-((v+7)%7==0?1:0))+'').replace("0",'').replace("-1",''); 241 var name = ((vT==0)?"do":(vT==1)?"re":(vT==2)?"mi":(vT==3)?"fa":(vT==4)?"so":(vT==5)?"la":(vT==6)?"si":"do") + name2; 242 r = Math.floor((caH - buttonH)/4); 243 cy = Math.floor(r + Math.random()*(caH - buttonH - 2*r)); 244 if(debug)console.log("音值 "+v,"唱名 "+name,"音阶 "+yj,"唱名值 "+vT); 245 var cDo =new circleDo(bgCLst[vT],fontCLst[vT],v,name,cy,r,circleDoLst.length>0?circleDoLst[circleDoLst.length-1].left+2.5*circleDoLst[circleDoLst.length-1].r:caW-r); 246 circleDoLst.push(cDo); 247 //cDo.draw(caCt); 248 break; 249 case "wxpDo": 250 //音值 251 var v = parseInt( 252 Math.random()>0.34 253 ?Math.random()*(highest) 254 :-1*low+Math.random()*(low) 255 ); 256 //唱名 257 var vT = Math.abs(v % 7); 258 vT = v<0?7-vT:vT; 259 //音阶 260 var yj = (v / 7)>0?Math.floor(v / 7):Math.ceil(v / 7); 261 var name2 = 262 v<0?((yj-1)+'').replace('-','↓'):((yj>=1&&v!=6)?"↑":'') 263 +((yj-((v+7)%7==0?1:0))+'').replace("0",'').replace("-1",''); 264 var name = ((vT==0)?"do":(vT==1)?"re":(vT==2)?"mi":(vT==3)?"fa":(vT==4)?"so":(vT==5)?"la":(vT==6)?"si":"do") + name2; 265 r = Math.floor(gapW*1); 266 var cy = 0; 267 for(var j=0;j<jxObjLst.length;j++){ 268 if(jxObjLst[j].v==v){ 269 cy = jxObjLst[j].top+jxObjLst[j].high*0.5; 270 break; 271 } 272 } 273 if(debug)console.log("音值 "+v,"唱名 "+name,"音阶 "+yj,"唱名值 "+vT); 274 var cDo =new wxpDo('blue','white',v,name,cy,r,wxpDoLst.length>0?wxpDoLst[wxpDoLst.length-1].left+gapW*4:caW-gapW*2); 275 wxpDoLst.push(cDo); 276 cDo.draw(caCt); 277 //cDo.draw(caCt); 278 break; 279 default: 280 } 281 } 282 function picIsLoaded() { 283 return toLoadPicCount <= loadPicCount ? true : false; 284 } 285 function loadPics() { 286 /*load pic to objectList*/ 287 for (var i = 0; i < pics.length; i++) { 288 var imgTmp = new Image(); 289 imgTmp.src = pics[i]; 290 imgTmp.onload = loadedImg; 291 picsLst.push(imgTmp); 292 } 293 } 294 function loadedImg() { 295 //console.log(loadPicCount, toLoadPicCount); 296 return ++loadPicCount; 297 } 298 function animate(time) { 299 if (picIsLoaded()) { 300 if(!goOn && (wrong>=maxWrong || score<=-100 || score>15000)){ 301 var s = Math.floor(score); 302 var name=""; 303 if(s<=-50){ 304 name='音盲'; 305 }else if(s<500){ 306 name='普通人' 307 }else if(s<5000){ 308 name='识音达人' 309 }else if(s<10000){ 310 name='识音天才' 311 }else{ 312 name='绝对音感?' 313 } 314 document.getElementById("scoreC").innerHTML = "称号: "+name +",得分: "+s+" 【游戏结束】"; 315 316 document.getElementsByTagName('title')[0].innerHTML = name+",得分【"+Math.floor(score)+"】"; 317 document.getElementById("btn_start").style.display="block"; 318 document.getElementById("gameWorldTouch").style.display="none"; 319 return; 320 } 321 var now = (+new Date); 322 if (mode == 0 && now - lastFpsUpdateTimeBDJ > bdjTime) { 323 bdjLeft = circleDoLst.length>0?circleDoLst[0].left:r*2; 324 if(bdjLeft>=r){ 325 lastFpsUpdateTimeBDJ = now; 326 wxpO.clearCircleDo(caCt); 327 for(var i=0;i<circleDoLst.length;i++){ 328 circleDoLst[i].left -= bdjPX; 329 circleDoLst[i].draw(caCt); 330 } 331 bdjLeft = circleDoLst.length>0?circleDoLst[0].left:r*2; 332 if(circleDoLst.length>0 && (circleDoLst[circleDoLst.length-1].left+r)<= caW){ 333 gen("circleDo"); 334 } 335 /*draw canvas*/ 336 //caCt.save(); 337 //caCt.beginPath(); 338 //caCt.restore(); 339 }else{ 340 if(!goOn)score-=scoreFu; 341 } 342 } 343 if (mode == 1 && now - lastFpsUpdateTimeBDJ > bdjTime) { 344 bdjLeft = wxpDoLst.length>0?wxpDoLst[0].left:wxpDoLeft; 345 if(bdjLeft>=wxpDoLeft){ 346 lastFpsUpdateTimeBDJ = now; 347 wxpO.clearWXPDo(caCt); 348 for(var i=0;i<wxpDoLst.length;i++){ 349 wxpDoLst[i].left -= bdjPX; 350 wxpDoLst[i].draw(caCt); 351 } 352 bdjLeft = wxpDoLst.length>0?wxpDoLst[0].left:wxpDoLeft; 353 if(wxpDoLst.length>0 && wxpDoLst[wxpDoLst.length-1].left<= caW){ 354 gen("wxpDo"); 355 if(debug){console.log('a');} 356 } 357 /*draw canvas*/ 358 //caCt.save(); 359 //caCt.beginPath(); 360 //caCt.restore(); 361 }else{ 362 if(!goOn)score-=scoreFu; 363 } 364 } 365 366 /*score*/ 367 if(!goOn){ 368 document.getElementById("scoreC").innerHTML = "得分: "+Math.floor(score)+" 错误: "+wrong+" / "+maxWrong; 369 }else{ 370 document.getElementById("lx").innerHTML = "无限练习模式,点击此处返回菜单"; 371 document.getElementById("lx").addEventListener("click", backMenu, false); 372 document.getElementById("lx").addEventListener("touchstart", backMenu, false); 373 } 374 } 375 window.requestNextAnimationFrame(animate); 376 /*if (isStop) { 377 isStart = false; 378 btn_start.innerHTML += "<br />游戏结束,马上重新开始"; 379 reStart(); 380 return; 381 } 382 if (isStart) { 383 //var pastTime = Math.round(((new Date).getTime() - startTime) / 1E3 * 100) / 100; 384 btn_start.innerHTML = pastTime; 385 btn_start.innerHTML = "分数: " + goodPass + " <br />用时: " + pastTime + " 秒"; 386 var now = (+new Date); 387 if (now - lastFpsUpdateTime > 100) { 388 lastFpsUpdateTime = now; 389 goOn(); 390 caCt.fillStyle = "#fff"; 391 caCt.fillRect(0, 0, caObj.width, caObj.height); 392 caCt.fillStyle = "#000"; 393 //caCt.clearRect(0, 0, caObj.width, caObj.height); 394 drawBird(); 395 drawZALst(); 396 doJudge(); 397 } 398 } else { 399 caCt.clearRect(0, 0, caObj.width, caObj.height); 400 drawBird(); 401 drawZALst(); 402 }*/ 403 } 404 function backMenu(){ 405 document.getElementById("btn_start").style.display= "block"; 406 document.getElementById("gameWorldTouch").style.display="none"; 407 return; 408 } 409 function eventBund(){ 410 if(!v){ 411 //caTObj.addEventListener("mousemove", onMouseMove, false); 412 caTObj.addEventListener("click", onMouseClick, false); 413 }else{ 414 caTObj.addEventListener("touchstart", onTouchStart, false); 415 caTObj.addEventListener("touchmove", onTouchMove, false); 416 caTObj.addEventListener("touchend", stopEvent, false); 417 caTObj.addEventListener("touchcancel", stopEvent, false); 418 caTObj.addEventListener("gesturestart", stopEvent, false); 419 caTObj.addEventListener("gesturechange", stopEvent, false); 420 caTObj.addEventListener("gestureend", stopEvent, false); 421 } 422 //document.getElementById("s1").addEventListener("click", onStart, false); 423 //document.getElementById("s2").addEventListener("click", onStart, false); 424 } 425 function onStart(e){ 426 document.getElementById("btn_start").style.display="none"; 427 if(!goOn){ 428 document.getElementById("scoreC").style.display="block"; 429 }else{ 430 document.getElementById("lx").style.display="block"; 431 } 432 } 433 function onMouseMove(e){ 434 //mouseTObj.x = e.pageX; 435 //mouseTObj.y = e.pageY; 436 } 437 function onTouchMove(e){ 438 e.preventDefault(); 439 var touch = e.touches[0]; 440 //mouseTObj.x = touch.pageX; 441 //mouseTObj.y = touch.pageY; 442 return false; 443 } 444 function onTouchStart(e){ 445 e.preventDefault(); 446 var touch = e.touches[0]; 447 touched({"x":touch.pageX,"y":touch.pageY}); 448 //mouseTObj.x = touch.pageX; 449 //mouseTObj.y = touch.pageY; 450 return false; 451 } 452 function onMouseClick(e){ 453 touched({"x":e.pageX,"y":e.pageY}); 454 } 455 function touched(pos){ 456 if(mode==0){ 457 // 五线谱 458 if(debug){console.log("click: ",pos);} 459 /*判断哪个线间被点中*/ 460 //jxObjLst item: {"v":(base+i),"top":nowTop,"high":high,"type":i%2==0?"Line":"gap"} 461 var value = null; 462 for(i=0;i<jxObjLst.length;i++){ 463 //if(debug){console.log("loop: ",jxObjLst[i].top,jxObjLst[i].high);} 464 if(pos.y>jxObjLst[i].top){ 465 if(pos.y<=jxObjLst[i].top + jxObjLst[i].high){ 466 value = jxObjLst[i]; 467 break; 468 } 469 } 470 } 471 if(value==null)return; 472 if(debug){console.log("poisiton,value",pos,value);} 473 /*判断正确与否,并消除被打击对象*/ 474 if(debug)console.log('被打击对象列表: ',circleDoLst); 475 /*高亮提示当前所点线间*/ 476 if(value!=null){ 477 //唱名 478 var vT = Math.abs(value.v % 7); 479 vT = value.v<0?7-vT:vT; 480 var name = ((vT==0)?"do":(vT==1)?"re":(vT==2)?"mi":(vT==3)?"fa":(vT==4)?"so":(vT==5)?"la":(vT==6)?"si":"do"); 481 // 画图 482 caTCt.clearRect(0,0,caW,caH); 483 wxpO.drawOne(caTCt,value.top,value.high,alertColor); 484 wxpO.drawText(caTCt,caW/2,caH/2,caW/5,name,alertColor); 485 setTimeout(clearTouchCanvas,alertTime); 486 } 487 if(circleDoLst.length>0 && value!=null && circleDoLst[0].value == value.v){ 488 if(debug)console.log("%cclick right!!!","color:green"); 489 if(debug)console.log('被打击对象列表: ',circleDoLst); 490 circleDoLst.splice(0,1); 491 gen("circleDo"); 492 bdjLeft = circleDoLst.length>0?circleDoLst[0].left:2*r; 493 if(!goOn)score+=scoreOne; 494 //wxpO.clearCircleDo(caCt); 495 //gen("circleDo"); // temp 496 }else{ 497 if(debug)console.log("%cclick wrong!!!","color:red"); 498 if(!goOn)wrong++; 499 if(debug)console.log("error",wrong); 500 } 501 }else if(mode==1){ 502 // 五线谱 503 if(debug){console.log("click: ",pos);} 504 /*判断哪个按钮点中*/ 505 //djBtnLst item: (bgC,fontC,value,name,top,r,left) 506 var value = null; 507 for(i=0;i<djBtnLst.length;i++){ 508 //if(debug){console.log("loop: ",jxObjLst[i].top,jxObjLst[i].high);} 509 //var distance = Math.abs(((pos.x-djBtnLst[i].left)^2 + (pos.y-djBtnLst[i].top)^2)^0.5); 510 var calX = pos.x - djBtnLst[i].left; 511 var calY = pos.y - djBtnLst[i].top; 512 var distance = Math.pow((calX *calX + calY * calY), 0.5); 513 514 console.log(distance,djBtnLst[i].r); 515 if(distance<=djBtnLst[i].r){ 516 value = djBtnLst[i]; 517 break; 518 } 519 } 520 if(value==null)return; 521 if(debug){console.log("poisiton,value",pos,value);} 522 /*判断正确与否,并消除被打击对象*/ 523 if(debug)console.log('被打击对象列表: ',wxpDoLst); 524 /*高亮提示当前点击的所有线间*/ 525 caTCt.clearRect(0,0,caW,caH); 526 if(value!=null){ 527 //线间list 528 //var indexLst = []; 529 for(var i = 0;i<jxObjLst.length;i++){ 530 var vT = Math.abs(jxObjLst[i].v % 7); 531 vT = jxObjLst[i].v<0?7-vT:vT; 532 var name = ((vT==0)?"do":(vT==1)?"re":(vT==2)?"mi":(vT==3)?"fa":(vT==4)?"so":(vT==5)?"la":(vT==6)?"si":"do"); 533 if(name==value.name){ 534 wxpO.drawOne(caTCt,jxObjLst[i].top,jxObjLst[i].high,alertColor); 535 } 536 //if(name==value.name){indexLst.push(i);} 537 } 538 // 清空画图 539 setTimeout(clearTouchCanvas,alertTime); 540 } 541 if(wxpDoLst.length>0 && value!=null && wxpDoLst[0].name.indexOf(value.name)!=-1){ 542 if(debug)console.log("%cclick right!!!","color:green"); 543 if(debug)console.log('被打击对象列表: ',circleDoLst); 544 wxpDoLst.splice(0,1); 545 gen("wxpDo"); 546 bdjLeft = wxpDoLst.length>0?wxpDoLst[0].left:wxpDoLeft; 547 if(!goOn)score+=scoreOne; 548 //wxpO.clearCircleDo(caCt); 549 //gen("circleDo"); // temp 550 }else{ 551 if(debug)console.log("%cclick wrong!!!","color:red"); 552 if(!goOn)wrong++; 553 if(debug)console.log("error",wrong); 554 } 555 } 556 } 557 function clearTouchCanvas(){ 558 caTCt.clearRect(0,0,caW,caH); 559 if(debug)console.log('clear'); 560 } 561 function stopEvent(e) { e.preventDefault(); e.stopPropagation(); } 562 var v = navigator.userAgent.toLowerCase().indexOf("android") != -1 || navigator.userAgent.toLowerCase().indexOf("iphone") != -1 || navigator.userAgent.toLowerCase().indexOf("ipad") != -1, 563 caW = window.innerWidth, 564 caH = window.innerHeight, 565 caObj = document.getElementById("gameWorld"), 566 caCt = caObj.getContext("2d"), 567 caTObj = document.getElementById("gameWorldTouch"), 568 caTCt = caTObj.getContext("2d"), 569 //rabitPicLst = ["img/rabit_left_stop.png", "img/rabit_on_ground_left_jump0.png", "img/rabit_on_ground_left_jump1.png", "img/rabit_right_stop.png", "img/rabit_on_ground_right_jump0.png", "img/rabit_on_ground_right_jump1.png", "img/rabit_on_air_left_stop.png", "img/rabit_on_air_left_down.png", "img/rabit_on_air_right_stop.png", "img/rabit_on_air_right_down.png"], 570 //rabitPicOLst = [], 571 pics = ['img/gyph.png','img/dyph.png'], 572 loadPicCount = 0, 573 toLoadPicCount = 2, 574 /*线与间*/ 575 //高音普上加线,3线,2间,上下无间 576 gyj = {x:2,j:2,up:0,down:0}, 577 //低音普上加线,2线,1间,上下无间 578 dyj = {x:0,j:0,up:0,down:0}, 579 //高音普线,5线,6间,上下有间 580 gy = {x:5,j:5,up:1,down:1}, 581 //低音普线,5线,6间,上下有间 582 dy = {x:5,j:5,up:1,down:1}, 583 //高音低音间do 584 doo = {x:1,j:1,up:0,down:0}, 585 //最高音 五线谱用 586 highest = 0, 587 //最低音 五线谱用 588 low = 0, 589 //被打击对象列表 五线谱用 590 circleDoLst = [], 591 //被打击对象列表 唱名用 592 wxpDoLst = [], 593 //总线数 594 allLine = 0, 595 //总间数 596 allGap = 0, 597 //线宽 598 lineW = 0, 599 //间宽 600 gapW = 0, 601 //打击区总高度 602 buttonH = 0, 603 //五线谱object 604 wxpO = null, 605 //唱名object 606 cmO = null, 607 //模式 0:五线谱打,1:唱名打 608 mode = mode, 609 //间线对象列表 610 jxObjLst = [], 611 //颜色 五线谱用 612 bgCLst = ["green","red","blue","green","pink","orange","yellow","gray"], 613 fontCLst = ["yellow","yellow","white","white","blue","white","black","yellow"], 614 // 被打击对象平移更新时间 615 bdjTime = 100, 616 // 被打击对象平移速度 617 bdjPX = 5, 618 // 被打击对象最左端 619 bdjLeft = 0, 620 // 被打击对象半径 621 r = 0, 622 // 唱名打击用 623 // 唱名button列表 624 djBtnLst = [], 625 // 被打击对象初期数 626 bdjInitCount = 5, 627 // 提示颜色 628 alertColor = "rgba(102,0,255,0.5)", 629 // 提示时间 630 alertTime = 500, 631 // 五线谱音符最左边 632 wxpDoLeft = 0, 633 scoreOne=50, 634 scoreFu = 0.1; 635 score=0, 636 wrong=0, 637 maxWrong = 10, 638 picsLst=[], 639 goOn = goOn 640 ; 641 642 this.init = function () { 643 mode = this.mode; 644 goOn = this.goOn; 645 //*********load images********* 646 loadPics(); 647 //*********init params******* 648 doVarInit(); 649 //*********init size and vars******* 650 doSize(); 651 //*********product bell and rabit******* 652 for(var i = 0;i<bdjInitCount;i++) 653 if(mode==0){ 654 gen("circleDo"); 655 }else{ 656 gen("wxpDo"); 657 } 658 //*********Event*********** 659 eventBund(); 660 //*********Gen*********** 661 //*********animate*********** 662 animate(); 663 } 664 } 665 666 /* 667 * 五线谱 object 668 */ 669 function wxp(caH,caW,buttonH,gyj,dyj,gy,dy,doo,allLine,allGap,lineW,gapW,mode,picLst) { 670 this.mode = mode; //0: 打谱,1: 打唱名 671 this.caH = caH; // 画面高度 672 this.caW = caW; // 画面宽度 673 this.buttonH=buttonH; // 打击区高度 674 this.gyj=gyj; // 高音上 675 this.dyj=dyj; // 低音下 676 this.gy=gy; // 高音 677 this.dy=dy; // 低音 678 this.doo=doo; // 中间do 679 this.allLine=allLine; // 总线 680 this.allGap=allGap; // 总间 681 this.lineW=lineW; // 线高 682 this.gapW=gapW; // 间高 683 this.picLst = picLst; 684 } 685 wxp.prototype.clearCircleDo = function (context) { 686 // 打谱用 687 var circleDoH = this.caH - (this.lineW * this.allLine + this.gapW * this.allGap) + 0.5; 688 context.clearRect(0,0,this.caW,circleDoH); 689 /*context.save(); 690 context.fillStyle = 'white'; 691 context.fillRect(0,0,this.caW,circleDoH); 692 context.restore();*/ 693 } 694 wxp.prototype.clearWXPDo = function (context) { 695 // 打唱名用 696 context.clearRect(0,0,this.caW,this.buttonH); 697 this.draw(context); 698 /*context.save(); 699 context.fillStyle = 'white'; 700 context.fillRect(0,0,this.caW,circleDoH); 701 context.restore();*/ 702 } 703 wxp.prototype.drawOne = function (context,top,high,color) { 704 context.save(); 705 context.beginPath(); 706 context.fillStyle = color; 707 context.fillRect(0,top,this.caW,high); 708 context.closePath(); 709 context.restore(); 710 } 711 wxp.prototype.drawText = function (context,x,y,size,text,color) { 712 context.save(); 713 context.beginPath(); 714 context.fillStyle = color; 715 context.font = parseInt(size)+"pt Calibri"; 716 context.textBaseline = 'middle'; 717 context.textAlign='center'; 718 context.fillText(text,x,y); 719 context.closePath(); 720 context.restore(); 721 } 722 wxp.prototype.draw = function (context) { 723 var gyphT = 0,gyphH = (this.gapW+this.lineW) * 6,gyphW = this.gapW * 3; 724 var dyphT = 0,dyphH = (this.gapW+this.lineW) * 3,dyphW = this.gapW * 3; 725 /*画线*/ 726 var nowTop = 0; 727 if(this.mode==0){ 728 nowTop = this.caH - (this.lineW * this.allLine + this.gapW * this.allGap) + 0.5; 729 } 730 context.save(); 731 for(var i=1;i<=this.gyj.x;i++){ 732 context.beginPath(); 733 context.lineWidth = this.lineW/2; 734 context.fillStyle = "gray"; 735 context.strokeStyle = "gray"; 736 context.moveTo(0,nowTop+this.lineW/2); 737 context.lineTo(this.caW,nowTop+this.lineW/2); 738 context.stroke(); 739 context.fill(); 740 nowTop += this.lineW + this.gapW; 741 } 742 for(var i=1;i<=this.gy.x;i++){ 743 if(i==1)gyphT = nowTop - this.gapW * 2; 744 context.beginPath(); 745 context.lineWidth = this.lineW/2; 746 context.fillStyle = "black"; 747 context.strokeStyle = "black"; 748 context.moveTo(0,nowTop+this.lineW/2); 749 context.lineTo(this.caW,nowTop+this.lineW/2); 750 context.stroke(); 751 context.fill(); 752 nowTop += this.lineW + this.gapW; 753 } 754 for(var i=1;i<=this.doo.x;i++){ 755 context.beginPath(); 756 context.lineWidth = this.lineW/2; 757 context.fillStyle = "red"; 758 context.strokeStyle = "red"; 759 context.moveTo(0,nowTop+this.lineW/2); 760 context.lineTo(this.caW,nowTop+this.lineW/2); 761 context.stroke(); 762 context.fill(); 763 nowTop += this.lineW + this.gapW; 764 } 765 for(var i=1;i<=this.dy.x;i++){ 766 if(i==1)dyphT = nowTop + this.gapW * 0; 767 context.beginPath(); 768 context.lineWidth = this.lineW/2; 769 context.fillStyle = "black"; 770 context.strokeStyle = "black"; 771 context.moveTo(0,nowTop+this.lineW/2); 772 context.lineTo(this.caW,nowTop+this.lineW/2); 773 context.stroke(); 774 context.fill(); 775 nowTop += this.lineW + this.gapW; 776 } 777 for(var i=1;i<=this.dyj.x;i++){ 778 context.beginPath(); 779 context.lineWidth = this.lineW/2; 780 context.fillStyle = "gray"; 781 context.strokeStyle = "gray"; 782 context.moveTo(0,nowTop+this.lineW/2); 783 context.lineTo(this.caW,nowTop+this.lineW/2); 784 context.stroke(); 785 context.fill(); 786 nowTop += this.lineW + this.gapW; 787 } 788 context.closePath(); 789 context.restore(); 790 /*画谱号*/ 791 /*var gImg = new Image(); 792 var dImg = new Image(); 793 gImg.src = 'img/gyph.png'; 794 dImg.src = 'img/dyph.png'; 795 gImg.onload = function(){context.drawImage(gImg,10,gyphT,gyphW,gyphH);} 796 dImg.onload = function(){context.drawImage(dImg,10,dyphT,dyphW,dyphH);}*/ 797 798 context.drawImage(this.picLst[0],10,gyphT,gyphW,gyphH); 799 context.drawImage(this.picLst[1],10,dyphT,dyphW,dyphH); 800 } 801 802 /* 803 * 五线谱用 被打击对象 object 804 */ 805 function circleDo(bgC,fontC,value,name,top,r,left) { 806 this.bgC = bgC; // 背景颜色 807 this.fontC = fontC; // 字体颜色 808 this.value=value; // 音值 809 this.name=name; // 显示文字 810 this.left=left; // r,left 811 this.top=top; // top 812 this.r=r; // 半径 813 } 814 circleDo.prototype.draw = function (context) { 815 context.save(); 816 context.fillStyle = this.bgC; 817 context.beginPath(); 818 context.arc(this.left/* + 75*/,this.top/* +75*/,this.r,0,2*Math.PI); 819 context.closePath(); 820 context.fill(); 821 822 context.fillStyle = this.fontC; 823 context.font = parseInt(this.r/2)+"pt Calibri"; 824 context.textBaseline = 'middle'; 825 context.textAlign='center'; 826 context.fillText(this.name, this.left/* + 75*/,this.top/* +75*/); 827 context.restore(); 828 } 829 830 /* 831 * 唱名用 唱名button object 832 */ 833 function djBtn(bgC,fontC,value,name,top,r,left) { 834 this.bgC = bgC; // 背景颜色 835 this.fontC = fontC; // 字体颜色 836 this.value=value; // 音值 837 this.name=name; // 显示文字 838 this.left=left; // r,left 839 this.top=top; // top 840 this.r=r; // 半径 841 } 842 djBtn.prototype.draw = function (context) { 843 context.save(); 844 context.fillStyle = this.bgC; 845 context.beginPath(); 846 context.arc(this.left/* + 75*/,this.top/* +75*/,this.r,0,2*Math.PI); 847 context.closePath(); 848 context.fill(); 849 850 context.fillStyle = this.fontC; 851 context.font = parseInt(this.r/2)+"pt Calibri"; 852 context.textBaseline = 'middle'; 853 context.textAlign='center'; 854 context.fillText(this.name, this.left/* + 75*/,this.top/* +75*/); 855 context.restore(); 856 } 857 /* 858 * 唱名用 被打击对象 object 859 */ 860 function wxpDo(bgC,fontC,value,name,top,r,left) { 861 this.bgC = bgC; // 背景颜色 862 this.fontC = fontC; // 字体颜色 863 this.value=value; // 音值 864 this.name=name; // 显示文字 865 this.left=left; // left 866 this.top=top; // top 867 this.r=r; // 半径 868 } 869 wxpDo.prototype.draw = function (context) { 870 context.save(); 871 context.strokeStyle = this.bgC; 872 context.lineWidth = this.r*0.5; 873 this.ParamEllipse(context,this.left,this.top,this.r*1.5,this.r); 874 875 var lineLeft1 = 0; 876 var lineTop1 = 0; 877 var lineLeft2 = 0; 878 var lineTop2 = 0; 879 if(this.value>=6){ 880 //第三线以上,下尾巴 881 lineLeft1=lineLeft2=-1*this.r*1.4; 882 lineTop1=0; 883 lineTop2=this.r*5; 884 }else{ 885 lineLeft1=lineLeft2=this.r*1.4; 886 lineTop1=0; 887 lineTop2=-1*this.r*5; 888 } 889 context.beginPath(); 890 context.moveTo(lineLeft1,lineTop1); 891 context.lineTo(lineLeft2,lineTop2); 892 context.stroke(); 893 context.closePath(); 894 895 context.restore(); 896 } 897 //---------使用三次贝塞尔曲线模拟椭圆1--------------------- 898 //此方法也会产生当lineWidth较宽,椭圆较扁时, 899 //长轴端较尖锐,不平滑的现象 900 wxpDo.prototype.ParamEllipse = function(context, x, y, a, b){ 901 //关键是bezierCurveTo中两个控制点的设置 902 //0.5和0.6是两个关键系数(在本函数中为试验而得) 903 var ox = 0.5 * a, 904 oy = 0.6 * b; 905 //context.save(); 906 context.translate(x, y); 907 context.beginPath(); 908 //从椭圆纵轴下端开始逆时针方向绘制 909 context.moveTo(0, b); 910 context.bezierCurveTo(ox, b, a, oy, a, 0); 911 context.bezierCurveTo(a, -oy, ox, -b, 0, -b); 912 context.bezierCurveTo(-ox, -b, -a, -oy, -a, 0); 913 context.bezierCurveTo(-a, oy, -ox, b, 0, b); 914 context.closePath(); 915 context.stroke(); 916 //context.restore(); 917 }; 918 /*example of object*/ 919 /* 920 * bell object 921 */ 922 /*function bell(top, left, width, height, si, maxSI) { 923 this.t = top; // 高度 924 } 925 bell.prototype.disappear = function (speed) { 926 this.a -= speed; 927 return this.a <= 0 ? true : false; 928 }*/ 929 930 /*example of extends*/ 931 /* 932 * bird object 933 */ 934 /*function bird(top, left, width, height, si, maxSI, direction) { 935 this.t = top; // 高度 936 } 937 bird.prototype = new bell; 938 */ 939 940 var gameWorldObj = null; 941 onload = function () { 942 document.getElementsByTagName('title')[0].innerHTML = "[WXS]五线谱游戏"; 943 /*gameWorldObj = new gameWorld(0); 944 gameWorldObj.init();*/ 945 } 946 function staffGameGo(mode,goOn){ 947 if(gameWorldObj == null) 948 gameWorldObj = new gameWorld(mode,goOn); 949 gameWorldObj.goOn = goOn; 950 gameWorldObj.mode = mode; 951 gameWorldObj.init(); 952 document.getElementById("btn_start").style.display="none"; 953 if(!goOn){ 954 document.getElementById("scoreC").style.display="block"; 955 document.getElementById("lx").style.display="none";} 956 else{ 957 document.getElementById("lx").style.display="block"; 958 document.getElementById("scoreC").style.display="none"; 959 } 960 }
---
CSDN下载: