choose function - カード選択処理
ユーザが1枚目、2枚目のカードをそれぞれクリックした際に実行されます。
最初にクリックイベントが発生したレイヤー上のマウスのX座標を取得しています。
このX座標の取得はブラウザ毎に異なっており、Google Chrome、Mozilla Firefox、Apple Safari用にはlayerXを、Microsoft Internet Explorer、Opera用にはoffsetXを取得し、そこから変数mx,myにそれぞれ座標位置を設定しています。
その後、if(i < deck.length)で1枚目、2枚目のクリックの判断を行いdrawImageメソッドを用いてそれぞれカード画像を描画しています。
選択したカードの1枚目、2枚目がマッチした場合はマッチフラグをONに設定し、カウントアップを行い、カウント数が定義したカード配列分に達したタイミングでゲームクリア処理を実行します。
ゲームクリア処理では、ゲーム開始からの時間(秒)を取得し、fillTextメソッドを利用してメッセージとともに表示しています。
また、1枚目と2枚目がマッチしなかった場合においては、マッチフラグをOFF、1回目選択フラグをONに設定し、setTimeoutメソッドを使って1000ミリ秒経過の後にflipBackファンクションを呼び出しカードの裏返し処理を行っています。
function choose(e) { var out; var mx; var my; var pick1; // イベント発生時のレイヤーXを取得(Chrome,Firefox,Safari) if (e.layerX || e.layerX == 0) { rect = e.target.getBoundingClientRect(); mx = e.clientX - rect.left; my = e.clientY - rect.top; // offsetXを取得(Internet Explorer,Opera) } else if (e.offsetX || e.offsetX == 0) { mx = e.offsetX; my = e.offsetY; } var i; for (i = 0; i < deck.length; i++){ var card = deck[i]; if (card.sx >= 0) { if ((mx > card.sx) && (mx < card.sx + card.swidth) && (my > card.sy) && (my < card.sy + card.sheight)) { if ((fstPick)|| (i!=fstCard)) { break; } } } } // カードクリック if (i < deck.length) { // 1枚目を選択 if (fstPick) { fstCard = i; fstPick = false; // カードの表を表示 ctx.drawImage(card.img,card.sx,card.sy,card.swidth,card.sheight); } // 2枚目を選択 else { scdCard = i; // カードの表を表示 ctx.drawImage(card.img,card.sx,card.sy,card.swidth,card.sheight); // 1枚目と2枚目がマッチ if (card.info == deck[fstCard].info) { // マッチフラグON matched = true; // カウントアップ count++; // 全て揃えばクリア処理実行 if (count >= .5*deck.length) { var now = new Date(); var nt = Number(now.getTime()); // 経過時間(秒)を取得 var seconds = Math.floor(.5+(nt-startTime)/1000); // ctx.strokeStyle = clrBorderColor; // ctx.strokeRect(0,0,900,600); ctx.fillStyle = "#0b305f"; // メッセージ生成 out = "ゲームクリア! 所要時間 "+String(seconds)+ "秒"; // フォントサイズ設定 ctx.font = "30px Arial"; // メッセージ描画 ctx.fillText(out, 280, 500); return; } } else { // マッチフラグOFF matched = false; } fstPick = true; setTimeout(flipBack,1000); } } }
flipBack function - カード裏返し処理
このファンクションではマッチフラグがOFFの場合に、drawメソッドによる再描画処理(裏返し処理)を実行しています。マッチしていた場合は再描画は行わずに画像を表示したままとしています。
// カードの裏返し function flipBack() { // マッチしていなかったらカードを裏返す if (!matched) { deck[fstCard].draw(); deck[scdCard].draw(); } else { // マッチしていた場合はそのまま表示 deck[scdCard].sx = -1; deck[fstCard].sx = -1; } }
init function - イニシャライズ
ページ呼び出し時にロードするイニシャライズメソッドです。
2dコンテキストを取得し、Canvasのクリックイベントリスナを登録した後にカードの生成、シャッフルの実行、スタート時間のセットを行っています。
function init() { var myCanvas = document.getElementById('canvas'); if (myCanvas && myCanvas.getContext) { // 2dコンテクスト取得 ctx = document.getElementById('canvas').getContext('2d'); if (ctx) { myCanvas.addEventListener('click', choose, false); // カード生成 makeDeck(); // カードシャッフルを実行 shuffle(); // スタート時間をセット startTime = new Date(); startTime = Number(startTime.getTime()); } } }
以上がmemory.jsの説明となります。
今回のサンプルで利用したmemory.html、並びにmemory.jsの全ソースは以下の通りです。
[memory.html]
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>神経衰弱ゲーム</title> <script type="text/javascript" src="./js/memory.js"></script> <!--[if lte IE 8.0]> <script type="text/javascript" src="./js/excanvas.js"></script> <![endif]--> <style> :root { background-color: #cccccc; } h1 { color: #0b305f; margin-top: 2em; text-align: center; font-size:36px; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.8); } canvas { display: block; margin: auto; } </style> </head> <body onload="init();"> <h1>神経衰弱</h1> <canvas id="canvas" width="900" height="600"> お使いのブラウザはHTML5のCanvas要素に対応していません。 </canvas> </body> </html> |
[memory.js]
// コンテキスト var ctx; // 1回目フラグ var fstPick = true; // 1枚目のカード var fstCard = -1; // 2枚目のカード var scdCard; // クリア時に表示 var clrBorderColor = "#0B0241"; // カードデッキ var deck = []; // デッキ1枚目のx座標位置 var firstx = 100; // デッキ1枚目のy座標位置 var firsty = 50; // カード間スペース var margin = 20; // カード横幅 var crdWidth = 125; // カード縦幅 var crdHeight = 190; // マッチフラグ var matched; // 開始時間 var startTime; // クリアカウント var count = 0; // ペアとなるカードを配列で定義 var pairs = [ ["one1.jpg", "one2.jpg"], ["two1.jpg", "two2.jpg"], ["three1.jpg", "three2.jpg"], ["four1.jpg", "four2.jpg"], ["five1.jpg", "five2.jpg"] ]; // カードオブジェクトの生成 function Card(sx, sy, swidth, sheight, img, info) { this.sx = sx; this.sy = sy; this.swidth = swidth; this.sheight = sheight; this.img = img; this.info = info; this.draw = drawBack; } // カードデッキの生成 function makeDeck() { var i; var acard; // ペア1枚目 var bcard; // ペア2枚目 var pica; // イメージ1 var picb; // イメージ2 var cx = firstx; // X座標 for (i = 0; i < pairs.length; i++) { // ペア(1枚目)の生成 // イメージオブジェクトの生成 pica = new Image(); // ファイルをセット pica.src = pairs[i][0]; // カードの生成 acard = new Card(cx, firsty, crdWidth, crdHeight, pica, i); deck.push(acard); // ペア(2枚目)の生成 picb = new Image(); picb.src = pairs[i][1]; bcard = new Card(cx, firsty + crdHeight + margin, crdWidth, crdHeight, picb, i); deck.push(bcard); // x座標にカード横幅とマージンを追加 cx = cx + crdWidth + margin; // ペア1枚目、2枚目の描画を実行 acard.draw(); bcard.draw(); } } // カードのシャッフル function shuffle() { var i; var k; var holderinfo; var holderimg; var nt; // ランダム処理を5回実行 for (nt = 0; nt < 6*deck.length; nt++) { // カードをランダムに取得 i = Math.floor(Math.random()*deck.length); k = Math.floor(Math.random()*deck.length); // カードデッキのinfoとimgを変数iに保持 holderinfo = deck[i].info; holderimg = deck[i].img; // 変数iからkへ格納 deck[i].info = deck[k].info; deck[i].img = deck[k].img; // infoとimgをセット deck[k].info = holderinfo; deck[k].img = holderimg; } } // カード背面の描画 function drawBack() { ctx.beginPath(); var grad = ctx.createLinearGradient(0,0, 0,500); grad.addColorStop(0.5,'rgb(155, 187, 89)'); // 緑 grad.addColorStop(1,'rgb(128, 100, 89)'); // 紫 /* グラデーションをfillStyleプロパティにセット */ ctx.fillStyle = grad; // fillRectメソッドで描画 ctx.fillRect(this.sx, this.sy, this.swidth, this.sheight); } // カード選択時処理 function choose(e) { var out; var mx; var my; var pick1; // イベント発生時のレイヤーXを取得(Chrome,Firefox,Safari) if (e.layerX || e.layerX == 0) { mx = e.layerX; my = e.layerY; // offsetXを取得(Opera) } else if (e.offsetX || e.offsetX == 0) { mx = e.offsetX; my = e.offsetY; } var i; for (i = 0; i < deck.length; i++){ var card = deck[i]; if (card.sx >= 0) { if ((mx > card.sx) && (mx < card.sx + card.swidth) && (my > card.sy) && (my < card.sy + card.sheight)) { if ((fstPick)|| (i!=fstCard)) { break; } } } } // カードクリック if (i < deck.length) { // 1枚目を選択 if (fstPick) { fstCard = i; fstPick = false; // カードの表を表示 ctx.drawImage(card.img,card.sx,card.sy,card.swidth,card.sheight); } // 2枚目を選択 else { scdCard = i; // カードの表を表示 ctx.drawImage(card.img,card.sx,card.sy,card.swidth,card.sheight); // 1枚目と2枚目がマッチ if (card.info == deck[fstCard].info) { // マッチフラグON matched = true; // カウントアップ count++; // 全て揃えばクリア処理実行 if (count >= .5*deck.length) { var now = new Date(); var nt = Number(now.getTime()); // 経過時間(秒)を取得 var seconds = Math.floor(.5+(nt-startTime)/1000); // ctx.strokeStyle = clrBorderColor; // ctx.strokeRect(0,0,900,600); ctx.fillStyle = "#0b305f"; // メッセージ生成 out = "ゲームクリア! 所要時間 "+String(seconds)+ "秒"; // フォントサイズ設定 ctx.font = "30px Arial"; // メッセージ描画 ctx.fillText(out, 280, 500); return; } } else { // マッチフラグOFF matched = false; } fstPick = true; setTimeout(flipBack,1000); } } } // カードの裏返し function flipBack() { // マッチしていなかったらカードを裏返す if (!matched) { deck[fstCard].draw(); deck[scdCard].draw(); } else { // マッチしていた場合はそのまま表示 deck[scdCard].sx = -1; deck[fstCard].sx = -1; } } function init() { var myCanvas = document.getElementById('canvas'); if (myCanvas "" myCanvas.getContext) { // 2dコンテクスト取得 ctx = document.getElementById('canvas').getContext('2d'); if (ctx) { myCanvas.addEventListener('click', choose, false); // カード生成 makeDeck(); // カードシャッフルを実行 shuffle(); // スタート時間をセット startTime = new Date(); startTime = Number(startTime.getTime()); } } } |
(文責:株式会社ベストクリエイト)