■補講 Canvasを使ったゲーム(迷路脱出ゲーム)  この補習講義では迷路脱出ゲームについて説明します。迷路は自動生成するものと、そうでないものがあります。RPG(ロールプレイング)風にするなら、あらかじめ迷路は作成しておいた方がよいでしょう。様々なトラップを仕掛けることができるからです。  ここでは上から見た迷路ではなく、横から見た迷路にします。このため、重力が存在し操作するキャラクタは下に落下することがあります。また、上にのぼる場合はハシゴを使います。  今回作成する迷路脱出ゲームは以前の補習講義で解説したレーダー表示タイプのゲームのプログラムを流用しています。単純に言えば重力がある、ハシゴがあるという以外は同じだということです。ここでは、差分のみ解説します。 ------------------------------------------------------------------------------------------------ ■迷路データの準備  まず、3つの迷路のデータを用意しておきます。迷路のデータはmap.jsファイルに入れておきます。迷路のデータもレーダー表示タイプと同じ変数名でroundMap配列に入れます。  迷路のデータは文字で示し以下のように対応しています。 【表】 0 : なにもない 1 : 通り抜けられないブロック 2 : はしご 3 : ドア(脱出用。ここに到達するとゲームクリア) 4 : つらら(氷) 5 : ブロック(通り抜けられる) 9 : 操作するキャラクタのスタート位置 データは上記の0〜9までの文字で表現し横は60文字、縦は42行で用意します。これは実際に表示される範囲よりもかなり大きいものになります。これはゲームの背景がスクロールするようにするため、実際に表示される範囲よりも大きくなくてはいけません。実際に表示されるのは480×320ピクセルになります。ブロック数にすると横15個×縦10個になります。 また、自分のキャラの開始位置を設定しておく必要があります。これを忘れると以前の場所にキャラが表示されてしまいます。 ------------------------------------------------------------------------------------------------ ■初期化  それでは初期化部分を見てみましょう。自分のキャラの座標とラウンドデータ、マップの表示位置をし示す座標等を入れるプロパティを設定しています。  これまでと異なるのはfadeCountです。これは何かというとゲームオーバーになった時にCanvas画面を黒でフェードアウトさせるためのカウンタです。 var game = { round : 1, // ゲームの面(ラウンド) charX : 8, // キャラのマップ内の位置(X座標) charY : 8, // キャラのマップ内の位置(Y座標) key : 38, // 押されたキーのコード(最初は↑キーと同じにする。つまり上方向に走行) roundData : new Array(), // ラウンドマップのデータを格納する配列 charSize : 32, // 画像の幅(32×32) mapWidth : 60, // マップの横幅(roundMap[0][0].length) mapHeight : 36, // マップの縦幅(roundMap[0].length) fadeCount : 0 // フェードアウト処理のためのカウンタ=不透明度(0〜0.75) }; ------------------------------------------------------------------------------------------------ ■ページ読み込み後の処理  ページが読み込まれた後にはレーダー対応のゲームと同じようにCanvasのコンテキストの取得を行い、その後迷路を読み出し配列に設定します。この段階では迷路は描画されません。  あとは、タイマーを設定します。あまり高速に処理するように設定してしまうと操作しにくくなるので、遅めに設定した方がよいかもしれません。 window.addEventListener("load", function(){ var canvasObj = document.getElementsByTagName("canvas")[0]; context = canvasObj.getContext("2d"); window.document.addEventListener("keydown", moveMyChar, false); initMapData(game.round); // 最初はラウンド1 timerID = setInterval("moveChar()", 150); }, true); ------------------------------------------------------------------------------------------------ ■迷路のデータをマップデータ配列に  initMapData関数では迷路のマップデータの初期化のみ行い描画は行いません。このゲームでもキャラクタは画面の中心にいるため描画は別途行う必要があります。 今回はマップ内での自分の位置を決めるために"9"の文字列があった場合、そこを自分のキャラクタの位置としています。これ以外は以前の補習講義で説明した処理と同じです。 function initMapData(n){ for(var y=0; y= roundMap.length){ // 最終面をクリアした clearInterval(timerID); // タイマーをクリア alert("全面クリアしました"); game.round = game.round - 1; drawMapData(); // 最後に迷宮を描く(表示されているキャラとの位置を合わせるため) game.fadeCount = 20; // フェードアウト処理 fadeout(); // フェードアウト処理 return; } // 次にラウンドデータを表示する initMapData(game.round); return; } } drawMapData(); ------------------------------------------------------------------------------------------------ ■フェードアウトの処理  最後にフェードアウトの処理を見てみましょう。フェードアウト処理はすでに描画済みの画面に対して薄い黒の四角形を描くことで実現します。つまり、不透明度0.1にしておいて、タイマーを使って定期的に描画するだけです。  不透明度などを変化させる場合、念のためコンテキストの状態をsave()を使って保存しておきます。何が保存されるかなどは本書の7章を参照してください。不透明度はglobalAlphaプロパティに設定した後、fillRect()メソッドを使って塗り潰された四角形を描画します。あとはgame.fadeCountから1を減らしていき、0になるまでタイマーを呼び出します。これでCanvas画面が黒でフェードアウトするようになります。 function fadeout(){ context.save(); // Canvasの状態を保存 context.globalAlpha = 0.05; // 不透明度を5%にする context.fillStyle = "black"; // 黒でフェード context.fillRect(0,0, 480, 320); // 全面を黒で塗り潰す context.restore(); // Canvasの状態を戻す game.fadeCount = game.fadeCount - 1; if (game.fadeCount > 0){ setTimeout("fadeout()", 150); } } これで、できあがりです。改良して2段ジャンプできるようにするとか、スライムやゴブリンなどのモンスターを出現させてみるのも面白いでしょう。 ------------------------------------------------------------------------------------------------ ■HTML (index.html) ------------------------------------------------------------------------------------------------ 階段があるゲーム(迷路) Canvasが使えるブラウザでどうぞ
カーソルキー(←→↑↓)を動かすと操作できます
------------------------------------------------------------------------------------------------ ■JavaScript(maze.js) ------------------------------------------------------------------------------------------------ // 迷路脱出ゲーム // Game用の変数 var context = null; var timerID = null; var game = { round : 1, // ゲームの面(ラウンド) charX : 8, // キャラのマップ内の位置(X座標) charY : 8, // キャラのマップ内の位置(Y座標) key : 38, // 押されたキーのコード(最初は↑キーと同じにする。つまり上方向に走行) roundData : new Array(), // ラウンドマップのデータを格納する配列 charSize : 32, // 画像の幅(32×32) mapWidth : 60, // マップの横幅(roundMap[0][0].length) mapHeight : 36, // マップの縦幅(roundMap[0].length) fadeCount : 0 // フェードアウト処理のためのカウンタ=不透明度(0〜0.75) }; // ページが読み込まれた時の処理 window.addEventListener("load", function(){ var canvasObj = document.getElementsByTagName("canvas")[0]; context = canvasObj.getContext("2d"); window.document.addEventListener("keydown", moveMyChar, false); initMapData(game.round); // 最初はラウンド1 timerID = setInterval("moveChar()", 150); }, true); // 移動&表示処理 function moveChar(){ var tx = game.charX, ty = game.charY; // 自分の座標(一時的に利用する) var temp = tx+(ty+1)*game.mapWidth; // マップ上での自分の下の位置を算出 if (game.roundData[temp] == "0"){ // 何もない空間の場合は落下させる game.charY = game.charY + 1; // Y座標を1つ下に移動 drawMapData(); // 迷宮を描く return; // 落下中は何もできない } // 自分のキャラの移動処理(マップ内で移動させる。キャラは常に画面の中央なので) if (game.key == 37){ tx = tx - 1; } if (game.key == 39){ tx = tx + 1; } if (game.key == 38){ ty = ty - 1; } if (game.key == 40){ ty = ty + 1; } game.key = 0; // オートリピートなし var mp = tx+ty*game.mapWidth; // マップ上での自分の位置を算出 if (game.roundData[mp] != "1"){ game.charX = tx; game.charY = ty; if (game.roundData[mp] == "3"){ alert("脱出しました。ラウンドクリアです"); game.round = game.round + 1; // ラウンド数に1を足す if (game.round >= roundMap.length){ // 最終面をクリアした clearInterval(timerID); // タイマーをクリア alert("全面クリアしました"); game.round = game.round - 1; drawMapData(); // 最後に迷宮を描く(表示されているキャラとの位置を合わせるため) game.fadeCount = 20; // フェードアウト処理 fadeout(); // フェードアウト処理 return; } // 次にラウンドデータを表示する initMapData(game.round); return; } } drawMapData(); } // 自分の移動処理 function moveMyChar(evt){ game.key = evt.keyCode; } // マップを初期化 function initMapData(n){ for(var y=0; y 0){ setTimeout("fadeout()", 150); } } ------------------------------------------------------------------------------------------------ ■JavaScript (map.js) // 地下迷宮のデータ // 0 : なにもない // 1 : 通り抜けられないブロック // 2 : はしご // 3 : ドア // 4 : つらら(氷) // 5 : ブロック(通り抜けられる) // 9 : スタート位置 var roundMap = new Array(); // 配列を用意 roundMap[1] = [ "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111151111111111", "111111111111111155511111111111111111111111111115111111111111", "111111511111111111111111115111111155111111151111111111111111", "111511111111111111111111111111111111111111111111111111111111", // ここから上は全部ブロック "111111114444444444444444444440044440042004444004440411111111", "111115110300000000000000001112111000002000000000000011111111", "111111110112110000000000000002000001102000000000000011111111", "111111510442000000000000000002000001102000000000000011151111", "111115110002000000000000000002000001102000000000000011111111", "111111111102000000000000000002000000002000000000000011111111", "111111114002000000000000000002000000002000000000000015511111", "111151110002000000000000000002000000002000000000000011111111", "111111110002000000000000000021000000001111111111121111511111", "111111110111111111111211111111000000000444441100020011111111", "111111110044400444400204444440000000000000000000020011111111", "111111110000000000000200000000001111000000000000020011115111", "111115110000000000000200000000001111000000000000020011111111", "111111110000000000000200000000001111000000000000020011111111", "115111110000000000000200000000000000000000000000020011151111", "111111110000000000000200000000100000000000000001020011111111", "111111111111110121111111100000111211111111110001121111151111", "111115110200000020000111100000000204444004400000424411151111", "111155110200000020000044000000000200000000000000020011511111", "111111110200000020000000000000000200000000000000020015111111", "111111111111211111100000000001111200000000000000020011111151", "111111119000200000000000000004444200000000000000020011111111", "111111111111111111111111111111111111111111111111111111511111", // ここから下は全部ブロック "111111111511111511111111111111511111151111111155111111111111", "111111111111111111111111111111111111111111111111151111111111", "111111111111151111111111511111111111551111111111111111111111", "111155111111111111511111111111111111111151111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111"]; roundMap[2] = [ "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", // ここから上は全部ブロック "111111119444440044004004440004400444400440044004444411111111", "111111110000000000000000000000000000000000000000000011111111", "111111110000000000001110000110011111110021111111211111111111", "111111111111011100001110011000011000000020000000244411111111", "111111114441014400001111100000011111000020000000200011111111", "111111110001010000001114110000011000000020000000200011111111", "111111110001010000001110011100011000000020000000000011111111", "111111110000040000004440000000044000000020000000000011111111", "111111111211000000000002111112000000000020000001000011111111", "111111114244000000000002044402000000000020000001000011111111", "111111110200100000000002000002000000000020000001000011111111", "111111110200100000000002000002111100011111121111000011111111", "111111110200100000000002000002000000004444020000000011111111", "111111110200100111211111100002000000000000020000000011111111", "111111110200100044200444000002000000000000020000000011111111", "111111110200100000200000000002001111111120020011110111111111", "111111110200400000200011111102004444410020020004440411111111", "111111110200000000200014440002000000010020020000111111111111", "111111110200111120200111000002000000010011120000000011111111", "111111110200144420200111000011120001110000020015000011111111", "11111111020010002020011100000002000111000002005100011111111", "111111110200100020200111000000020005550000020055000311111111", "111111111111111111111111111111111111111111111111111111111111", // ここから下は全部ブロック "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111"]; roundMap[3] = [ "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", // ここから上は全部ブロック "111111110444440044004444000020044440040400444004440411111111", "111111110000000000000000000020000000000000000000000011111111", "111111110000000000000000021111000000000000000000000011111111", "111111110000000000000000020444111000000000000000000011111111", "111111110000000000000000020000444111000000000000000011111111", "111111110000000000002200020000000444000000000000000011111111", "111111110000000000221111220000000002111112000000000011111111", "111111110000000022110000000000000002444442000000000011111111", "111111110000002222000000000000000002000002000000000011111111", "111111110000221100000000000000000002000002000000000011111111", "111111110022110000000000000000000002000002000000000011111111", "111111110021000000111111000000000002000011111011101111111111", "111111110020000000144441000000211111000000000000000011111111", "111111110020000000400004000000204440001110000000000011111111", "111111110020000000000000000000200000000001111100211011111111", "111111110021111100000000000000200000000000000222200011111111", "111111110024444411100000000000200000000000000000000011111111", "111111110020000044411100000000200000000000000000010011111111", "111111110020000000044411100000200000000000000021110011111111", "1111111102200000000000444111002000000000000000200010011111111", "111111110200000000000000044411100000000000000020010011111111", "111111110200000000000000000000000000000000000020910311111111", "111111111111111111111111111111111111111111111111111111111111", // ここから下は全部ブロック "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111", "111111111111111111111111111111111111111111111111111111111111"]; ------------------------------------------------------------------------------------------------