Monaca+HTML+JS(Cancas)で早押しアプリを作る!2つ目の記事です。
前回は約3時間ほどでブログを書きながらAndroidの早押しアプリを作ろうと頑張っていました。
Monaca+HTML+JS(Canvas)で早押しアプリを作る!
残念ながら、3時間ではゲームの大まかな流れとタップ操作の取得しかできなかったので、その続きを作成し完成させるまでの流れです。
以前の記事では、アプリを作成しながらブログを書いていたので、途中のソースコードなども結構貼っていたのですが、今回の記事はほとんどアプリが完成した状態でブログを書いています。途中のソースがあんまり詳しくないのは勘弁してください><
あと、前回から変数名が多少変わってたりしますが、これもあまり深く考えないで頂きたいですw
次回は作成したAndroidアプリをPlayストアに公開するまでをまとめました!
連打を防ぐ
このゲームは画面の色が変わった瞬間にできるだけ早くタップするゲームです。そのゲームの性質上、画面の色が変わる前から連打することによってずるができてしまいます。
そこで、そのような事を防ぐために同じ場所は連打できないという仕様を追加したいと思います。
当たり?判定
このような状況で”当たり”という単語が適切なのか微妙ですが、とりあえず既にタップした円の中を当たりとし、この場合は新たにタップできないようにしましょう。
画像を見るとわかりやすいと思うのですが、先にタップされている点(黒色)に対し、半径2r以内はタップできないようにしました。以下の図の通り半径r以内をタップできないようにした場合には、新たにタップした点と既存の点の円が被ってしまい、見にくくなってしまいます。
これを実装するためのソースコードとしては以下のようになります。
// すでにその位置に円が描かれていないか判定 // dataは既に書かれている座標のリスト. data[n][1]x座標,data[n][2]y座標 function hit_chk(x, y, r, data){ // return 1 -&amp;amp;gt; 衝突 // return 0 -&amp;amp;gt; 非衝突 for (var i=0; i&amp;amp;lt;data.length; i++){ if( Math.pow(data[i][1] - x, 2) + Math.pow(data[i][2] - y, 2) &amp;amp;lt;= Math.pow(r*2,2)){ return 1; } } return 0; }
3平方の定理より、2点間の距離は
√(「x座標での距離の2乗」+「y座標での距離の2乗」)
で求めることができます。この値が2倍の半径より小さければ良いわけです。プログラムでは、√を取るのが嫌だったので、逆に当たり判定の半径を2乗しています。
※ソースコードの全文はこのブログの最後にまとめて記載します。
ソースコード
とりあえず全体のソースコードを載せておきます。
index.html
<!-- bodyの中身のみを表示 --> <body> <div id="canvas_cover"> </div> <script type="text/javascript" src="js/firster.js"></script> </body>
style.css
/* style.css */ /* 謎のマージンが入らないように */ body { margin: 0; } /* canvasが動かないように */ #canvas_cover{ overflow: hidden; }
firster.js
/* firster.js */ // canvas要素を作成する。 //var canvas_div = document.getElementById('canvas_cover'); $("#canvas_cover").append('<canvas id="game_canvas"></canvas>'); $("#game_canvas").attr('width', window.innerWidth); $("#game_canvas").attr('height', window.innerHeight); var canvas = $("#game_canvas").get(0); var ctx = canvas.getContext('2d'); // 画面に表示する文字 // (あとで文字幅とか計算するのに宣言しておくと便利) var wait_str = "wait"; var touch_str = "touch"; var soon_str = "早い"; var ok_str = "OK"; // 背景文字色 var light_red = '#ff7856'; var red = '#ff0a0a'; var light_green = '#c4ff89'; var green = '#0aff0a'; var light_blue = '#a5eeff'; var blue_1 = '#7fffd4'; var gray = '#bfbfbf'; var black = '#000'; var orange = '#ff8205'; // 金 銀 銅 をなんとなく表現 var rank_color = ['#e6b422', '#C0C0C0', '#C47222']; var rank_color_other = '#0f87ff'; // スワイプによるスクロールを禁止させる document.body.addEventListener('touchstart', function(event) { event.preventDefault(); }); /* ここからゲームに関する記述 */ var c_w = canvas.width; var c_h = canvas.height; var startTime, endTime; function game(){ var game_state = 0; var tap_datas = []; wait(); function wait(){ tap_datas = []; game_state = 1; // 背景色を設定 ctx.fillStyle = gray; ctx.fillRect(0, 0, c_w, c_h); // Waitの文字を描画 ctx.fillStyle = red; ctx.font = "50px 'MS ゴシック'"; metrics = ctx.measureText(wait_str); // 文字列幅を得たい ctx.fillText(wait_str, ((c_w-metrics.width)/2), (c_h/2)); // wait画面 // 1~4秒でwaitを表示 setTimeout(touch, 1000 + Math.random()*3000); } function touch(){ startTime = new Date(); game_state = 2; // 背景の描画 ctx.fillStyle = light_blue; ctx.fillRect(0,0,canvas.width, canvas.height); for(var i=0; i<tap_datas.length; i++){ draw_soon(tap_datas[i][1], tap_datas[i][2]); } // touchの文字を描画 ctx.fillStyle = green; ctx.font = "50px 'MS ゴシック'"; metrics = ctx.measureText(touch_str); // 文字列幅を得たい ctx.fillText(touch_str, ((c_w-metrics.width)/2), (c_h/2) + 25); setTimeout(game_end, 3000); } // スコアの表示、その他 function game_end(){ game_state = 3; // 背景色を設定 ctx.fillStyle = light_green; ctx.fillRect(0, 0, c_w, c_h); for (var i=0, rank=1; i < tap_datas.length; i++){ if(tap_datas[i][0] == 1){ // 早いタップ位置について表示 draw_soon(tap_datas[i][1], tap_datas[i][2]); }else if(tap_datas[i][0] == 2){ // OKなタップ位置について表示 if((rank-1) < rank_color.length){ draw_score(tap_datas[i][1], tap_datas[i][2], rank, tap_datas[i][3], rank_color[rank-1]); }else{ draw_score(tap_datas[i][1], tap_datas[i][2], rank, tap_datas[i][3]); } rank++; } } setTimeout(tap_game_restart, 2000); } function tap_game_restart(){ game_state=4; // touchの文字を描画 ctx.fillStyle = light_green; ctx.font = "50px 'MS ゴシック'"; ctx.fillStyle = orange; metrics = ctx.measureText("タップでもどる"); // 文字列幅を得たい ctx.fillText("たっぷでもどる", ((c_w-metrics.width)/2), 50); } // 画面をタップした(瞬間の)座標を取得 canvas.addEventListener('touchstart', function(e) { for(var i=0; i< e.touches.length; i++){ var touch = e.touches[i]; // タップ操作の分岐 if(hit_chk(touch.clientX, touch.clientY, c_w/10, tap_datas) === 0){ endTime = new Date(); if(game_state == 1){ // wait画面でのタップ draw_soon(touch.clientX, touch.clientY); }else if(game_state == 2){ draw_ok(touch.clientX, touch.clientY); } var touch_data = [game_state, touch.clientX, touch.clientY, endTime - startTime]; tap_datas.push(touch_data); } if(game_state == 4){ setTimeout(wait(), 0); } } }, false); } // すでにその位置に円が描かれていないか判定 function hit_chk(x, y, r, data){ // return 1 -> 衝突 // return 0 -> 非衝突 for (var i=0; i<data.length; i++){ if( Math.pow(data[i][1] - x, 2) + Math.pow(data[i][2] - y, 2) <= Math.pow(r*2,2)){ return 1; } } return 0; } // 早すぎ描画 function draw_soon(x, y){ // wait画面でのタップ ctx.fillStyle = '#ff0000'; ctx.font = "20px 'MS ゴシック'"; metrics = ctx.measureText(soon_str); // 文字列幅を得たい ctx.fillText(soon_str, x - (metrics.width/2), y); ctx.beginPath(); ctx.strokeStyle = '#ff7856'; ctx.arc( x, y, c_w/10, 0, Math.PI*2, true); ctx.stroke(); } // OK描画 function draw_ok(x, y){ // touch画面でのタップ ctx.fillStyle = '#0000ff'; ctx.font = "20px 'MS ゴシック'"; metrics = ctx.measureText(ok_str); // 文字列幅を得たい ctx.fillText("OK", x - (metrics.width/2), y); ctx.beginPath(); ctx.strokeStyle = orange; ctx.arc(x, y, c_w/10, 0, Math.PI*2, true); ctx.stroke(); } // デフォルト引数的な使い方 function draw_score(x, y, rank, time, color){ if (!color){ color = rank_color_other; } ctx.beginPath(); ctx.strokeStyle = color; ctx.arc(x, y, c_w/10, 0, Math.PI*2, true); ctx.stroke(); ctx.font = "20px 'MS ゴシック'"; ctx.fillStyle = color; rank_str1 = rank + "位"; rank_str2 = time + "ms"; metrics = ctx.measureText(rank_str1); // 文字列幅を得たい ctx.fillText(rank_str1, x - metrics.width/2, y - 10);// - c_w/(2*10));// - metrics.height/2); metrics = ctx.measureText(rank_str2); // 文字列幅を得たい ctx.fillText(rank_str2, x - metrics.width/2, y + 10);// + c_w/(2*10));// + metrics.height/2); } //ゲーム開始 game();
スクリーンショット
とりあえずこんな感じのアプリです。Playストアに公開されているので、よろしければダウンロードしてみてください♪
関連記事
① ブログを書きながらアプリを3時間で作ろうとした。 Monaca+HTML+JS(Canvas)で早押しアプリを作る!
② アプリを仕上げる(この記事) : Monaca+HTML+JS(Canvas)で早押しアプリを作る! – part2 –
③ アプリをストアに公開する : Monaca+HTML+JS(Canvas)で早押しアプリを作る! – part3 –
Pingback: Monaca+HTML+JS(Canvas)で早押しアプリを作る! | たくのこ Web