| 01 | <!DOCTYPE html>
|
|---|
| 02 | <html lang="ja">
|
|---|
| 03 | <head>
|
|---|
| 04 | <meta charset="utf-8">
|
|---|
| 05 | <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0 user-scalable=no">
|
|---|
| 06 | <title>WEB Audio API を使ったゲーム</title>
|
|---|
| 07 | </head>
|
|---|
| 08 | <body style="background-color:#224;">
|
|---|
| 09 | <canvas style="position:absolute; top:0; bottom:0; left:0; right:0; margin:auto;" id="bg"></canvas>
|
|---|
| 10 |
|
|---|
| 11 | <script>
|
|---|
| 12 | //キャンバスの準備
|
|---|
| 13 | var winW = window.innerWidth;
|
|---|
| 14 | var winH = window.innerHeight;
|
|---|
| 15 | var CWIDTH = 480;
|
|---|
| 16 | var CHEIGHT = 480;
|
|---|
| 17 | if( winW < winH )
|
|---|
| 18 | winH = winW;
|
|---|
| 19 | else
|
|---|
| 20 | winW = winH;
|
|---|
| 21 | var SCALE = winW / CWIDTH;
|
|---|
| 22 |
|
|---|
| 23 | var canvas = document.getElementById("bg");
|
|---|
| 24 | var cnt = canvas.getContext("2d");
|
|---|
| 25 | canvas.width = winW;
|
|---|
| 26 | canvas.height = winH;
|
|---|
| 27 | cnt.scale( SCALE, SCALE );
|
|---|
| 28 | cnt.textAlign = "center";
|
|---|
| 29 | cnt.textBaseline = "middle";
|
|---|
| 30 |
|
|---|
| 31 | //マウスとタップ入力
|
|---|
| 32 | var tapC = 0;
|
|---|
| 33 | canvas.addEventListener( "touchstart", touchStart );
|
|---|
| 34 | canvas.addEventListener( "touchend", touchEnd );
|
|---|
| 35 | function touchStart(e) { e.preventDefault(); tapC = 1; }
|
|---|
| 36 | function touchEnd(e) { tapC = 0; }
|
|---|
| 37 |
|
|---|
| 38 | canvas.addEventListener( "mousedown", mouseDown );
|
|---|
| 39 | canvas.addEventListener( "mouseup", mouseUp );
|
|---|
| 40 | function mouseDown(e) { tapC = 1; }
|
|---|
| 41 | function mouseUp(e) { tapC = 0; }
|
|---|
| 42 |
|
|---|
| 43 | //キー入力
|
|---|
| 44 | var key = 0;
|
|---|
| 45 | window.onkeydown = function(event) { key = event.keyCode; }
|
|---|
| 46 | window.onkeyup = function(event) { key = 0; }
|
|---|
| 47 |
|
|---|
| 48 | //画像ファイルの処理
|
|---|
| 49 | var img = [];
|
|---|
| 50 | var imgPre = [];
|
|---|
| 51 |
|
|---|
| 52 | function loadImg( n ) {//画像を読み込む
|
|---|
| 53 | imgPre[n] = false;
|
|---|
| 54 | img[n] = new Image();
|
|---|
| 55 | img[n].src = "example332_" + n + ".png";
|
|---|
| 56 | img[n].onload = function() { imgPre[n] = true; }
|
|---|
| 57 | }
|
|---|
| 58 |
|
|---|
| 59 | function drawChr( dx, dy ) {//キャラの表示
|
|---|
| 60 | if( imgPre[0] != true ) return;
|
|---|
| 61 | var sx = (tmr%2)*60;
|
|---|
| 62 | var sy = 0;
|
|---|
| 63 | cnt.drawImage( img[0], sx, sy, 60, 80, dx-30, dy-40, 60, 80 );
|
|---|
| 64 | }
|
|---|
| 65 |
|
|---|
| 66 | function drawBG( dx, dy ) {//背景の表示
|
|---|
| 67 | if( imgPre[1] != true ) return;
|
|---|
| 68 | cnt.drawImage( img[1], dx, dy );
|
|---|
| 69 | }
|
|---|
| 70 |
|
|---|
| 71 | function toInt( val ) {//整数を返す関数
|
|---|
| 72 | return parseInt(val);
|
|---|
| 73 | }
|
|---|
| 74 |
|
|---|
| 75 | function rnd( max ) {//乱数を返す関数
|
|---|
| 76 | return toInt( Math.random()*max );
|
|---|
| 77 | }
|
|---|
| 78 |
|
|---|
| 79 | function getDis( x1, y1, x2, y2 ) {//2点間の距離
|
|---|
| 80 | return toInt( Math.sqrt( (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) ) );
|
|---|
| 81 | }
|
|---|
| 82 |
|
|---|
| 83 | function setAlp( per ) {//透明度
|
|---|
| 84 | cnt.globalAlpha = per/100;
|
|---|
| 85 | }
|
|---|
| 86 |
|
|---|
| 87 | function fText( str, x, y, siz, col ) {//影付文字の表示
|
|---|
| 88 | cnt.font = siz + "px monospace";
|
|---|
| 89 | cnt.fillStyle = "#000";
|
|---|
| 90 | cnt.fillText( str, x+2, y+2 );
|
|---|
| 91 | cnt.fillStyle = col;
|
|---|
| 92 | cnt.fillText( str, x, y );
|
|---|
| 93 | }
|
|---|
| 94 |
|
|---|
| 95 | function fRect( x, y, w, h, col ) {//矩形
|
|---|
| 96 | cnt.fillStyle = col;
|
|---|
| 97 | cnt.fillRect( x, y, w, h );
|
|---|
| 98 | }
|
|---|
| 99 |
|
|---|
| 100 | function fArc( x, y, r, col ) {//円(塗り潰し)
|
|---|
| 101 | cnt.fillStyle = col;
|
|---|
| 102 | cnt.beginPath();
|
|---|
| 103 | cnt.arc( x, y, r, 0, Math.PI*2, false );
|
|---|
| 104 | cnt.fill();
|
|---|
| 105 | }
|
|---|
| 106 |
|
|---|
| 107 | function sArc( x, y, r, col, wid ) {//円(線)
|
|---|
| 108 | cnt.strokeStyle = col;
|
|---|
| 109 | cnt.lineWidth = wid;
|
|---|
| 110 | cnt.beginPath();
|
|---|
| 111 | cnt.arc( x, y, r, 0, Math.PI*2, false );
|
|---|
| 112 | cnt.stroke();
|
|---|
| 113 | }
|
|---|
| 114 |
|
|---|
| 115 | //ゲーム用の変数
|
|---|
| 116 | var idx = 0;
|
|---|
| 117 | var tmr = 0;
|
|---|
| 118 |
|
|---|
| 119 | var gtime = 0;
|
|---|
| 120 | var score = 0;
|
|---|
| 121 | var hisco = 200;
|
|---|
| 122 | var scrl = 0;
|
|---|
| 123 |
|
|---|
| 124 | var ix = 100;
|
|---|
| 125 | var iy = 0;
|
|---|
| 126 | var yp = 0;
|
|---|
| 127 |
|
|---|
| 128 | var BUBBLE = 7;
|
|---|
| 129 | var BBLCOL = ["#f00", "#e80", "#dc0", "#4d0", "#0ac", "#48f", "#c4f" ];
|
|---|
| 130 | var bx = [];
|
|---|
| 131 | var by = [];
|
|---|
| 132 | var bb = [];
|
|---|
| 133 |
|
|---|
| 134 | //WEB Audio API
|
|---|
| 135 | var aCtx, ac_osci, ac_dest;
|
|---|
| 136 | try {
|
|---|
| 137 | aCtx = new AudioContext;
|
|---|
| 138 | ac_osci = aCtx.createOscillator();
|
|---|
| 139 | ac_dest = aCtx.destination;
|
|---|
| 140 | ac_osci.frequency.value = (400-iy)*4;
|
|---|
| 141 | ac_osci.type = "square";
|
|---|
| 142 | ac_osci.connect(ac_dest);
|
|---|
| 143 | ac_osci.start();
|
|---|
| 144 | }
|
|---|
| 145 | catch(e) { alert( "Web Audio に対応していません" ); }
|
|---|
| 146 |
|
|---|
| 147 | function setHZ() { try { ac_osci.frequency.value = (400-iy)*4; } catch(e) {} }
|
|---|
| 148 | function susWAA() { try { aCtx.suspend(); } catch(e) {} }
|
|---|
| 149 | function resWAA() { try { aCtx.resume(); } catch(e) {} }
|
|---|
| 150 |
|
|---|
| 151 | window.onload = acGame();
|
|---|
| 152 | function acGame() {
|
|---|
| 153 | tmr ++;
|
|---|
| 154 |
|
|---|
| 155 | //背景のスクロール
|
|---|
| 156 | scrl += 1; if( idx == 2 ) scrl += 3;
|
|---|
| 157 | drawBG(-scrl%480,0);
|
|---|
| 158 | drawBG(480-scrl%480,0);
|
|---|
| 159 |
|
|---|
| 160 | drawChr(ix,iy);//猫のキャラ
|
|---|
| 161 |
|
|---|
| 162 | switch( idx ) {
|
|---|
| 163 |
|
|---|
| 164 | case 0://初期化
|
|---|
| 165 | loadImg(0);
|
|---|
| 166 | loadImg(1);
|
|---|
| 167 | idx = 1;
|
|---|
| 168 | break;
|
|---|
| 169 |
|
|---|
| 170 | case 1://タイトル
|
|---|
| 171 | fText( "Tap to start.", 240, 240, 40, "#0cf" );
|
|---|
| 172 | if( iy < 380 ) {//猫が落ちてくる処理
|
|---|
| 173 | yp ++;
|
|---|
| 174 | iy = iy + yp;
|
|---|
| 175 | if( iy > 380 ) {
|
|---|
| 176 | iy = 380;
|
|---|
| 177 | susWAA();
|
|---|
| 178 | }
|
|---|
| 179 | else {
|
|---|
| 180 | setHZ();
|
|---|
| 181 | }
|
|---|
| 182 | }
|
|---|
| 183 | if( key == 32 || tapC == 1 ) {
|
|---|
| 184 | for( var i = 0; i < BUBBLE; i ++ ) {
|
|---|
| 185 | bx[i] = 480+rnd(480);
|
|---|
| 186 | by[i] = rnd(400);
|
|---|
| 187 | bb[i] = 0;
|
|---|
| 188 | }
|
|---|
| 189 | idx = 2;
|
|---|
| 190 | gtime = 500;
|
|---|
| 191 | score = 0;
|
|---|
| 192 | }
|
|---|
| 193 | break;
|
|---|
| 194 |
|
|---|
| 195 | case 2:
|
|---|
| 196 | //猫のジャンプ処理
|
|---|
| 197 | if( key == 32 || tapC == 1 ) {
|
|---|
| 198 | if( iy == 380 ) {
|
|---|
| 199 | yp = -28;
|
|---|
| 200 | resWAA();
|
|---|
| 201 | }
|
|---|
| 202 | }
|
|---|
| 203 | iy = iy + yp;
|
|---|
| 204 | if( iy > 380 ) {
|
|---|
| 205 | iy = 380;
|
|---|
| 206 | yp = 0;
|
|---|
| 207 | susWAA();
|
|---|
| 208 | }
|
|---|
| 209 | else {
|
|---|
| 210 | if( key == 32 || tapC == 1 )
|
|---|
| 211 | yp = yp + 1;
|
|---|
| 212 | else
|
|---|
| 213 | yp = yp + 6;
|
|---|
| 214 | }
|
|---|
| 215 | setHZ();//猫のY座標に応じて周波数を変化させる
|
|---|
| 216 |
|
|---|
| 217 | //シャボン玉の処理
|
|---|
| 218 | for( var i = 0; i < BUBBLE; i ++ ) {
|
|---|
| 219 | bx[i] -= (4+i);
|
|---|
| 220 | if( bx[i] < 0 ) bx[i] += 600;
|
|---|
| 221 | if( bb[i] == 0 ) {
|
|---|
| 222 | setAlp(60);
|
|---|
| 223 | fArc( bx[i], by[i], 24, BBLCOL[i] );
|
|---|
| 224 | setAlp(30);
|
|---|
| 225 | fArc( bx[i]-8, by[i]-8, 12, "#fff" );
|
|---|
| 226 | fArc( bx[i]-8, by[i]-8, 6, "#fff" );
|
|---|
| 227 | setAlp(100);
|
|---|
| 228 | if( getDis(ix,iy,bx[i],by[i]) < 50 ) {
|
|---|
| 229 | score += 10; if( score > hisco ) hisco = score;
|
|---|
| 230 | bb[i] = 10;
|
|---|
| 231 | }
|
|---|
| 232 | }
|
|---|
| 233 | else {
|
|---|
| 234 | sArc( bx[i], by[i], 20+(11-bb[i])*4, BBLCOL[i], bb[i] );
|
|---|
| 235 | bb[i] --;
|
|---|
| 236 | if( bb[i] == 0 ) {
|
|---|
| 237 | bx[i] = 480+rnd(480);
|
|---|
| 238 | by[i] = rnd(400);
|
|---|
| 239 | }
|
|---|
| 240 | }
|
|---|
| 241 | }
|
|---|
| 242 |
|
|---|
| 243 | gtime --;//ゲーム時間のカウント
|
|---|
| 244 | if( gtime == 0 ) {
|
|---|
| 245 | susWAA();
|
|---|
| 246 | idx = 3;
|
|---|
| 247 | tmr = 0;
|
|---|
| 248 | }
|
|---|
| 249 | break;
|
|---|
| 250 |
|
|---|
| 251 | case 3:
|
|---|
| 252 | fText( "Time is up.", 240, 240, 40, "#ff0" );
|
|---|
| 253 | if( tmr > 100 ) idx = 1;
|
|---|
| 254 | break;
|
|---|
| 255 |
|
|---|
| 256 | }
|
|---|
| 257 |
|
|---|
| 258 | //時間とスコアの表示
|
|---|
| 259 | var col = "#fff"; if( gtime < 100 && gtime%10 < 5 ) col = "#ff0";
|
|---|
| 260 | fText( "TIME " +gtime, 240, 450, 32, col );
|
|---|
| 261 | fText( "SCORE "+score, 120, 30, 32, "#8ff" );
|
|---|
| 262 | fText( "HISCORE "+hisco, 360, 30, 32, "#af8" );
|
|---|
| 263 |
|
|---|
| 264 | setTimeout( acGame, 50 );
|
|---|
| 265 | }
|
|---|
| 266 |
|
|---|
| 267 | </script>
|
|---|
| 268 |
|
|---|
| 269 | <a href="../jsh5_033.html" style="color:#fff;">講座に戻る</a>
|
|---|
| 270 | </body>
|
|---|
| 271 | </html> |
|---|