情報学部 菅沼ホーム JavaScript 目次 索引

タワーディフェンスゲーム

  1. ステップ1: マップの表示

      基本的に,「ゲーム枠の作成」で説明した方法とほぼ同じ方法で作成します.以下,各プログラムに対して,「ゲーム枠の作成」の場合との違いについて説明していきます.

    1. HTML ファイル

        基本的な考え方は,「ゲーム枠の作成」における HTML ファイルと同じです.しかし,このゲームでは,アクションゲーム(その2)と同様,画面を格子状に区切り,各格子内に小さな画像を配置し,それらの組合せによって背景や障害物を描いています.さらに,各格子の状態(マップ)を編集可能にしています.そのため,マップを記述する別のファイル Map.js を作成し,ディレクトリ map に入れることにします( 10 行目).また,マップの編集に移行するためのボタンも用意してあります( 19 行目).

        また,このゲームでは,いくつかのパラメータを変更して実行可能なようになっています.そこで,23 行目以降において,FORM 要素内に,マップを選択するための SELECT 要素OPTION 要素ドロップダウンリスト),敵と味方の数を入力するための INPUT 要素を追加しています.各要素に関しては,それらを使用する箇所で詳しく説明します.

      01	<!DOCTYPE HTML>
      02	<HTML>
      03	<HEAD>
      04		<TITLE>タワーディフェンスゲーム:ステップ1</TITLE>
      05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
      06		<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
      07		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../master.css">
      08		<SCRIPT TYPE="text/javascript" SRC="main/MainPanel.js"></SCRIPT>
      09		<SCRIPT TYPE="text/javascript" SRC="start/StartPanel.js"></SCRIPT>
      10		<SCRIPT TYPE="text/javascript" SRC="map/Map.js"></SCRIPT>
      11		<SCRIPT TYPE="text/javascript" SRC="game/GamePanel.js"></SCRIPT>
      12		<SCRIPT TYPE="text/javascript" SRC="clear/GameClearPanel.js"></SCRIPT>
      13		<SCRIPT TYPE="text/javascript" SRC="over/GameOverPanel.js"></SCRIPT>
      14	</HEAD>
      15	<BODY CLASS="eeffee" onLoad="mp_start()">
      16		<H1>タワーディフェンスゲーム:ステップ1</H1>
      17		<CANVAS ID="canvas_e" STYLE="background-color: #ffffff;" WIDTH="900" HEIGHT="500" TABINDEX="1"></CANVAS><BR>
      18		<A HREF="method.htm" TARGET="method"><BUTTON ID="method" CLASS="std">遊び方</BUTTON></A>
      19		<BUTTON ID="map" CLASS="std" onClick="map_edit()">マップ編集</BUTTON>
      20		<BUTTON ID="start" CLASS="std" onClick="gp_start()">ゲーム開始</BUTTON>
      21		<BUTTON ID="first" CLASS="std" onClick="st_start()">スタート画面</BUTTON>
      22		<BUTTON ID="finish" CLASS="std" onClick="mp.finish()">ゲーム終了</BUTTON><BR><BR>
      23		<FORM ID="i_set">
      24			使用するマップ: 
      25				<SELECT SIZE="1" ID="map_sel" STYLE="font-size: 90%">
      26					<OPTION VALUE="map1"> マップ1 </OPTION><BR>
      27					<OPTION VALUE="map2"> マップ2 </OPTION><BR>
      28					<OPTION VALUE="map3"> マップ3 </OPTION><BR>
      29					<OPTION VALUE="new"> 新規 </OPTION><BR>
      30				</SELECT><BR>
      31			味方の数制限: 
      32				味方1: <INPUT ID="fr1" TYPE="text" VALUE="10" SIZE="2" STYLE="font-size:90%"> 
      33				味方2: <INPUT ID="fr2" TYPE="text" VALUE="4" SIZE="2" STYLE="font-size:90%"><BR>
      34			敵の数: 
      35				敵1: <INPUT ID="en1" TYPE="text" VALUE="10" SIZE="2" STYLE="font-size:90%"> 
      36				敵2: <INPUT ID="en2" TYPE="text" VALUE="5" SIZE="2" STYLE="font-size:90%">
      37		</FORM>
      38	</BODY>
      39	</HTML>
      				

    2. MainPanel

        このプログラムに関しても,「ゲーム枠の作成」における MainPanel とほとんど同じです.ボタンの制御部分が異なっていると共に,12 行目において,Map オブジェクト( Map.js )を生成しています.

      01	mp = null;   // MainPanel オブジェクト
      02	
      03				//
      04				// MainPanel の開始
      05				//
      06	function mp_start()
      07	{
      08						// キャンバス情報
      09		let canvas = document.getElementById('canvas_e');   // キャンバス要素の取得
      10		let ctx    = canvas.getContext('2d');   // キャンバスからコンテキストを取得
      11						// Map オブジェクト
      12		MP = new Map();
      13						// MainPanel オブジェクト
      14		mp = new MainPanel(canvas, ctx);
      15						// StartPanel の表示
      16		st_start();
      17	}
      18				//
      19				// MainPanel オブジェクト(プロパティ)
      20				//
      21	function MainPanel(canvas, ctx)
      22	{
      23		this.canvas = canvas;   // キャンバス要素
      24		this.ctx    = ctx;   // キャンバスのコンテキスト
      25		return this;
      26	}
      27				//
      28				// MainPanel オブジェクト(メソッド)
      29				//
      30	MainPanel.prototype.finish = function()
      31	{
      32						// キャンバスのクリア
      33		mp.ctx.clearRect(0, 0, mp.canvas.width, mp.canvas.height);
      34						// ボタンを非表示
      35		document.getElementById('method').style.display = "none";
      36		document.getElementById('map').style.display = "none";
      37		document.getElementById('start').style.display = "none";
      38		document.getElementById('first').style.display = "none";
      39		document.getElementById('finish').style.display = "none";
      40		document.getElementById('i_set').style.display = "none";
      41	}
      				

        また,Map.js の内容は,以下に示すとおりです.

      001	MP = null;   // Map オブジェクト
      002	
      003	function Map()
      004	{
      005						// ブロック画像
      006		this.block_image        = new Array();   // ブロック画像
      007		this.block_image[0]     = new Image();
      008		this.block_image[0].src = "image/barrier1.jpg";
      009		this.block_image[1]     = new Image();
      010		this.block_image[1].src = "image/barrier2.jpg";
      011						// ブロックの大きさ
      012		this.block_width  = 25;   // ブロックの幅
      013		this.block_height = 25;   // ブロックの高さ
      014						// マップ
      015		this.map_row = 20;   // マップの行数
      016		this.map_col = 30;   // マップの列数
      017		this.map1    = new Array();
      018		for (let i1 = 0; i1 < 4; i1++)
      019			this.map1[i1] = new Array();
      020								// マップ1
      021		this.map1[0][0] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      022		this.map1[0][1] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0);
      023		this.map1[0][2] = new Array(0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0);
      024		this.map1[0][3] = new Array(0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0);
      025		this.map1[0][4] = new Array(0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      026		this.map1[0][5] = new Array(0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0);
      027		this.map1[0][6] = new Array(0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0);
      028		this.map1[0][7] = new Array(0, 0, 0, 0, 1, 0, 1, 0, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0);
      029		this.map1[0][8] = new Array(0, 0, 2, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 2, 0, 2, 1, 0, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0);
      030		this.map1[0][9] = new Array(0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 2, 2, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0);
      031		this.map1[0][10] =new Array(0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 1, 0, 0);
      032		this.map1[0][11] =new Array(0, 0, 0, 0, 2, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, 0, 0, 0, 0);
      033		this.map1[0][12] =new Array(0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2, 2, 2, 0, 0, 0, 0, 1, 0, 0);
      034		this.map1[0][13] =new Array(0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0);
      035		this.map1[0][14] =new Array(0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0);
      036		this.map1[0][15] =new Array(0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0);
      037		this.map1[0][16] =new Array(0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 2, 0, 0, 0, 0, 1, 0, 1, 0, 0);
      038		this.map1[0][17] =new Array(0, 0, 0, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0);
      039		this.map1[0][18] =new Array(0, 0, 1, 0, 0, 1, 0, 0, 0, 2, 2, 2, 0, 0, 0, 1, 0, 1, 0, 0, 2, 0, 0, 0, 0, 1, 0, 1, 0, 0);
      040		this.map1[0][19] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      041								// マップ2
      042		this.map1[1][0] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      043		this.map1[1][1] = new Array(0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      044		this.map1[1][2] = new Array(0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 1, 0, 2, 2, 0, 0);
      045		this.map1[1][3] = new Array(0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 2, 2, 0, 1, 0, 1, 0, 0, 2, 2, 0, 0);
      046		this.map1[1][4] = new Array(0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      047		this.map1[1][5] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 1, 0, 0, 1, 0, 2, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0);
      048		this.map1[1][6] = new Array(0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0);
      049		this.map1[1][7] = new Array(0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 2, 0, 0, 0);
      050		this.map1[1][8] = new Array(0, 0, 0, 0, 0, 2, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      051		this.map1[1][9] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0);
      052		this.map1[1][10] =new Array(0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0);
      053		this.map1[1][11] =new Array(0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0);
      054		this.map1[1][12] =new Array(0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 2, 2, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0, 0);
      055		this.map1[1][13] =new Array(0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 1, 0, 0);
      056		this.map1[1][14] =new Array(0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
      057		this.map1[1][15] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0);
      058		this.map1[1][16] =new Array(0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0);
      059		this.map1[1][17] =new Array(0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      060		this.map1[1][18] =new Array(0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0);
      061		this.map1[1][19] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      062								// マップ3
      063		this.map1[2][0] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      064		this.map1[2][1] = new Array(0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0);
      065		this.map1[2][2] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0);
      066		this.map1[2][3] = new Array(0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 1, 1, 0, 1, 0, 0, 0);
      067		this.map1[2][4] = new Array(0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0);
      068		this.map1[2][5] = new Array(0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0);
      069		this.map1[2][6] = new Array(0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0);
      070		this.map1[2][7] = new Array(0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 1, 1, 0, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0);
      071		this.map1[2][8] = new Array(0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 2, 0, 0, 0);
      072		this.map1[2][9] = new Array(0, 0, 0, 0, 0, 2, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0);
      073		this.map1[2][10] =new Array(0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0);
      074		this.map1[2][11] =new Array(0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 2, 0, 2, 2, 2, 0, 0);
      075		this.map1[2][12] =new Array(0, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      076		this.map1[2][13] =new Array(0, 0, 0, 2, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0);
      077		this.map1[2][14] =new Array(0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0);
      078		this.map1[2][15] =new Array(0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0);
      079		this.map1[2][16] =new Array(0, 0, 0, 2, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0);
      080		this.map1[2][17] =new Array(0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0);
      081		this.map1[2][18] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
      082		this.map1[2][19] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      083								// 新規
      084		this.map1[3][0] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      085		this.map1[3][1] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      086		this.map1[3][2] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      087		this.map1[3][3] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      088		this.map1[3][4] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      089		this.map1[3][5] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      090		this.map1[3][6] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      091		this.map1[3][7] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      092		this.map1[3][8] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      093		this.map1[3][9] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      094		this.map1[3][10] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      095		this.map1[3][11] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      096		this.map1[3][12] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      097		this.map1[3][13] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      098		this.map1[3][14] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      099		this.map1[3][15] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      100		this.map1[3][16] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      101		this.map1[3][17] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      102		this.map1[3][18] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      103		this.map1[3][19] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
      104								// 初期設定
      105		this.map = this.map1[0];   // 使用マップ
      106	
      107		return this;
      108	}
      001						// ブロック画像
      				
      006 行目~ 010 行目

        障害物を構成する画像です.ここでは,2 種類の画像を使用します.

      012 行目~ 013 行目

        マップを構成するブロックの幅と高さです.

      015 行目~ 016 行目

        マップの行数及び列数です.

      017 行目~ 103 行目

        4 種類のマップを定義しています.0 以外の値が障害物を表しています.従って,4 番目のマップは,障害物が全く存在しないマップです.マップを,3 次元配列 map1[4][20][30] を使用して表現しています.最初の添え字が,マップの種類を表し,次の 2 つの添え字が実際のマップに対応します.このように,3 次元配列は,まず,配列を定義し( 17 行目),その各要素も配列として定義し( 18,19 行目),さらに,その各要素も配列として定義( 021 行目~ 103 行)するといった方法で定義することが可能です.

        例えば,配列 x[4][2][3] のイメージは以下に示す図のようになります.まず,x が 4 個のポインタ配列の先頭を指すアドレスであり,4 個の各ポインタは,各々,2 個のポインタ配列の先頭アドレスを指しています.2 個の各ポインタは,各々,3 個のデータが入る先頭アドレスを指しています.この結果,x[i] は 2 次元配列として,また,x[i][j] は 1 次元配列として扱うことができます.
        一般に,配列の各要素を配列として定義することによって,多次元配列を定義することが可能です.以下に示すのは 2 行 3 列の 2 次元配列の例です.
      	let a = new Array(2);   // let a = new Array(); でも可
      	for (let i1 = 0; i1 < 2; i1++)
      		a[i1] = new Array(3);					
      初期設定も同時に行いたい場合は,例えば,以下のようにして行います.
      	let a = new Array(2);   // let a = new Array(); でも可
      	a[0] = new Array(1, 2, 3);
      	a[1] = new Array(4, 5, 6);
      					
      105 行目

        map は,ゲームで使用するマップを指定する変数であり,この文により,マップを指定しない場合,マップ1( map1[0] )が使用されます.map に map1[0] が代入されているため,map は,2 次元配列になる点に注意してください.また,上で説明しましたように,map1[0] はアドレスとみなせますので,代入と言っても,map1[0] の指す全てのデータがコピーされて map に代入されるわけではありません.map と map1[0] が,同じデータを指すことになるだけです.従って,map を介してデータを変更すれば,map1[0] 内の対応するデータも変化します(逆も同様).

    3. StartPanel

        このプログラムに関しても,「ゲーム枠の作成」における StartPanel とほとんど同じです.ボタンの制御部分が異なっているだけです.当然のことながら,ゲームタイトル及び「遊び方」の内容を変更しています.

      			//
      			// StartPanel の開始
      			//
      function st_start()
      {
      					// キャンバスのクリア
      	mp.ctx.clearRect(0, 0, mp.canvas.width, mp.canvas.height);
      					// ゲームタイトルの表示
      	mp.ctx.font = "40px 'MS ゴシック'";
      	mp.ctx.textBaseline = "middle";
      	mp.ctx.textAlign = "center";
      	mp.ctx.fillStyle = "rgb(0, 0, 0)";
      	mp.ctx.fillText("タワーディフェンスゲーム", mp.canvas.width/2, mp.canvas.height/2);
      					// ボタンの表示制御
      	document.getElementById('method').style.display = "";
      	document.getElementById('map').innerHTML = "マップ編集";
      	document.getElementById('map').style.display = "";
      	document.getElementById('start').innerHTML = "ゲーム開始";
      	document.getElementById('start').style.display = "";
      	document.getElementById('first').style.display = "none";
      	document.getElementById('finish').style.display = "none";
      	document.getElementById('i_set').style.display = "";
      }
      				

    4. GamePanel

        GamePanel は,実際のゲームを実現する部分です.従って,「ゲーム枠の作成」における GamePanel とは,ゲームの種類によってその内容は大きく異なります.今後,このプログラムを完成させていくことになりますが,ここでは,マップを表示しているだけです.

      01	gp = null;   // GamePanel オブジェクト
      02	
      03				//
      04				// GamePanel の開始
      05				//
      06	function gp_start()
      07	{
      08						// GamePanel オブジェクト
      09		gp = new GamePanel();
      10		gp.draw();
      11						// ボタンの表示制御
      12		document.getElementById('method').style.display = "none";
      13		document.getElementById('map').style.display = "none";
      14		document.getElementById('start').style.display = "none";
      15		document.getElementById('first').style.display = "none";
      16		document.getElementById('finish').style.display = "none";
      17		document.getElementById('i_set').style.display = "none";
      18						// 確認
      19	//	gop_start();   // ゲームオーバー
      20	//	gcp_start();   // ゲームクリア
      21	}
      22				//
      23				// GamePanel オブジェクト(プロパティ)
      24				//
      25	function GamePanel()
      26	{
      27						// マップの選択
      28		let k = 0;
      29		for (let i1 = 0; i1 < document.getElementById('map_sel').options.length; i1++) {
      30			if (document.getElementById('map_sel').options[i1].selected) {
      31				k = i1;
      32				break;
      33			}
      34		}
      35		MP.map = MP.map1[k];
      36	
      37		return this;
      38	}
      39				//
      40				// GamePanel オブジェクト(メソッド draw)
      41				//
      42	GamePanel.prototype.draw = function()
      43	{
      44						// キャンバスのクリア
      45		mp.ctx.clearRect(0, 0, mp.canvas.width, mp.canvas.height);
      46						// 背景の描画
      47		for (let i1 = 0; i1 < MP.map_col; i1++) {
      48			let x = MP.block_width * i1;
      49			for (let i2 = 0; i2 < MP.map_row; i2++) {
      50				if (MP.map[i2][i1] > 0) {
      51					let y = i2 * MP.block_height;
      52					mp.ctx.drawImage(MP.block_image[MP.map[i2][i1]-1], x, y, MP.block_width, MP.block_height);
      53				}
      54			}
      55		}
      56	}
      				
      09 行目( gp_start 関数)

        GamePanel オブジェクトを生成し,その結果をグローバル変数 gp( 01 行目)に代入しています.具体的には,25 行目~ 38 行目に記述された GamePanel 関数が実行されます.

      10 行目( gp_start 関数)

        描画を実行するため,GamePanel オブジェクトの draw メソッド( 42 行目~ 56 行目)を実行しています.

      12 行目~ 17 行目( gp_start 関数)

        ボタン等を非表示にしています.

      19 行目~ 20 行目( gp_start 関数)

        コメントを外し,ゲームクリア画面及びゲームオーバー画面の状態をチェックするための文です.

      28 行目~ 35 行目( GamePanel 関数)

        スタート画面にあるドロップダウンリスト( HTML ファイルの 24 行目~ 29 行目)によって選択されたマップを,Map オブジェクトのプロパティ map に設定しています.29 行目の length は,ドロップダウンリストにおける選択肢の数( OPTION 要素の数)を表しています.また,32 行目の break 文が実行されると,break 文が入っている最も内側のループの外に出て(ループの処理を中止して),そのループの次の文が実行されます.

      45 行目( draw メソッド)

        キャンバス領域をクリアしています.

      47 行目~ 55 行目( draw メソッド)

        マップの情報に基づき背景(障害物)を描画しています.

    5. GameClearPanel

        このプログラムに関しても,「ゲーム枠の作成」における GameClearPanel とほとんど同じです.ただし,このゲームではレベルを設定せず,スタート画面においてパラメータを設定し直すことによってゲームレベルに相当する設定を行っています.そのため,同じパラメータでもう一度実行するか,または,スタート画面に戻るかの選択になります.

      			//
      			// GameClearPanel の開始
      			//
      function gcp_start()
      {
      					// キャンバスのクリア
      	mp.ctx.clearRect(0, 0, mp.canvas.width, mp.canvas.height);
      					// タイトルの表示
      	mp.ctx.font = "40px 'MS ゴシック'";
      	mp.ctx.textBaseline = "middle";
      	mp.ctx.textAlign = "center";
      	mp.ctx.fillStyle = "rgb(0, 0, 0)";
      	mp.ctx.fillText("Game Clear!", mp.canvas.width/2, mp.canvas.height/2);
      					// ボタンの表示制御
      	document.getElementById('method').style.display = "none";
      	document.getElementById('map').style.display = "none";
      	document.getElementById('start').innerHTML = "もう一度";
      	document.getElementById('start').style.display = "";
      	document.getElementById('first').innerHTML = "スタート画面";
      	document.getElementById('first').style.display = "";
      	document.getElementById('finish').style.display = "";
      	document.getElementById('i_set').style.display = "none";
      }
      				

    6. GameOverPanel

        このプログラムに関しても,「ゲーム枠の作成」における GameOverPanel とほとんど同じです.ボタンの制御部分が異なっているだけです.

      			//
      			// GameOverPanel の開始
      			//
      function gop_start()
      {
      					// キャンバスのクリア
      	mp.ctx.clearRect(0, 0, mp.canvas.width, mp.canvas.height);
      					// タイトルの表示
      	mp.ctx.font = "40px 'MS ゴシック'";
      	mp.ctx.textBaseline = "middle";
      	mp.ctx.textAlign = "center";
      	mp.ctx.fillStyle = "rgb(0, 0, 0)";
      	mp.ctx.fillText("Game Over!", mp.canvas.width/2, mp.canvas.height/2);
      					// ボタンの表示制御
      	document.getElementById('method').style.display = "none";
      	document.getElementById('map').style.display = "none";
      	document.getElementById('start').innerHTML = "もう一度";
      	document.getElementById('start').style.display = "";
      	document.getElementById('first').innerHTML = "スタート画面";
      	document.getElementById('first').style.display = "";
      	document.getElementById('finish').style.display = "";
      	document.getElementById('i_set').style.display = "none";
      }
      				

  2. ステップ2: マップの編集

      マップの編集機能を追加します.スタート画面にあるドロップダウンリストから編集したいマップを選択した後,「マップ編集」ボタンをクリックすると,map_edit 関数が呼ばれ,マップの編集が可能になります.マップを保存する機能はありませんので,ゲームを再読込すれば編集した結果は失われますが,スタート画面等から行うゲームの再実行の際には,編集結果は保持されます.ファイル Map.js を以下に示すように修正します.

    001	MP = null;   // Map オブジェクト
    002	
    003	function Map()
    004	{
    005						// ブロック画像
    006		this.block_image        = new Array();   // ブロック画像
    007		this.block_image[0]     = new Image();
    008		this.block_image[0].src = "image/barrier1.jpg";
    009		this.block_image[1]     = new Image();
    010		this.block_image[1].src = "image/barrier2.jpg";
    011						// ブロックの大きさ
    012		this.block_width  = 25;   // ブロックの幅
    013		this.block_height = 25;   // ブロックの高さ
    014						// マップ
    015		this.map_row = 20;   // マップの行数
    016		this.map_col = 30;   // マップの列数
    017		this.map1    = new Array();
    018		for (let i1 = 0; i1 < 4; i1++)
    019			this.map1[i1] = new Array();
    020								// マップ1
    021		this.map1[0][0] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    022		this.map1[0][1] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0);
    023		this.map1[0][2] = new Array(0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0);
    024		this.map1[0][3] = new Array(0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0);
    025		this.map1[0][4] = new Array(0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    026		this.map1[0][5] = new Array(0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0);
    027		this.map1[0][6] = new Array(0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0);
    028		this.map1[0][7] = new Array(0, 0, 0, 0, 1, 0, 1, 0, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0);
    029		this.map1[0][8] = new Array(0, 0, 2, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 2, 0, 2, 1, 0, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0);
    030		this.map1[0][9] = new Array(0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 2, 2, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0);
    031		this.map1[0][10] =new Array(0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 1, 0, 0);
    032		this.map1[0][11] =new Array(0, 0, 0, 0, 2, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 2, 0, 0, 0, 0);
    033		this.map1[0][12] =new Array(0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2, 2, 2, 0, 0, 0, 0, 1, 0, 0);
    034		this.map1[0][13] =new Array(0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0);
    035		this.map1[0][14] =new Array(0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0);
    036		this.map1[0][15] =new Array(0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0);
    037		this.map1[0][16] =new Array(0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 2, 0, 0, 0, 0, 1, 0, 1, 0, 0);
    038		this.map1[0][17] =new Array(0, 0, 0, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0);
    039		this.map1[0][18] =new Array(0, 0, 1, 0, 0, 1, 0, 0, 0, 2, 2, 2, 0, 0, 0, 1, 0, 1, 0, 0, 2, 0, 0, 0, 0, 1, 0, 1, 0, 0);
    040		this.map1[0][19] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    041								// マップ2
    042		this.map1[1][0] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    043		this.map1[1][1] = new Array(0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    044		this.map1[1][2] = new Array(0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 1, 0, 2, 2, 0, 0);
    045		this.map1[1][3] = new Array(0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 2, 2, 0, 1, 0, 1, 0, 0, 2, 2, 0, 0);
    046		this.map1[1][4] = new Array(0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    047		this.map1[1][5] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 1, 0, 0, 1, 0, 2, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0);
    048		this.map1[1][6] = new Array(0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0);
    049		this.map1[1][7] = new Array(0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 2, 0, 0, 0);
    050		this.map1[1][8] = new Array(0, 0, 0, 0, 0, 2, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    051		this.map1[1][9] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0);
    052		this.map1[1][10] =new Array(0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0);
    053		this.map1[1][11] =new Array(0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0);
    054		this.map1[1][12] =new Array(0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 2, 2, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0, 0);
    055		this.map1[1][13] =new Array(0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 1, 0, 0);
    056		this.map1[1][14] =new Array(0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
    057		this.map1[1][15] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0);
    058		this.map1[1][16] =new Array(0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0);
    059		this.map1[1][17] =new Array(0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    060		this.map1[1][18] =new Array(0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0);
    061		this.map1[1][19] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    062								// マップ3
    063		this.map1[2][0] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    064		this.map1[2][1] = new Array(0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0);
    065		this.map1[2][2] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0);
    066		this.map1[2][3] = new Array(0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 1, 1, 0, 1, 0, 0, 0);
    067		this.map1[2][4] = new Array(0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0);
    068		this.map1[2][5] = new Array(0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0);
    069		this.map1[2][6] = new Array(0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0);
    070		this.map1[2][7] = new Array(0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 1, 1, 0, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0);
    071		this.map1[2][8] = new Array(0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 2, 0, 0, 0);
    072		this.map1[2][9] = new Array(0, 0, 0, 0, 0, 2, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0);
    073		this.map1[2][10] =new Array(0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0);
    074		this.map1[2][11] =new Array(0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 2, 0, 2, 2, 2, 0, 0);
    075		this.map1[2][12] =new Array(0, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    076		this.map1[2][13] =new Array(0, 0, 0, 2, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0);
    077		this.map1[2][14] =new Array(0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0);
    078		this.map1[2][15] =new Array(0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0);
    079		this.map1[2][16] =new Array(0, 0, 0, 2, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0);
    080		this.map1[2][17] =new Array(0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0);
    081		this.map1[2][18] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
    082		this.map1[2][19] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    083								// 新規
    084		this.map1[3][0] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    085		this.map1[3][1] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    086		this.map1[3][2] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    087		this.map1[3][3] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    088		this.map1[3][4] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    089		this.map1[3][5] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    090		this.map1[3][6] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    091		this.map1[3][7] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    092		this.map1[3][8] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    093		this.map1[3][9] = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    094		this.map1[3][10] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    095		this.map1[3][11] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    096		this.map1[3][12] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    097		this.map1[3][13] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    098		this.map1[3][14] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    099		this.map1[3][15] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    100		this.map1[3][16] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    101		this.map1[3][17] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    102		this.map1[3][18] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    103		this.map1[3][19] =new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    104								// 初期設定
    105		this.map = this.map1[0];   // 使用マップ
    106	
    107		return this;
    108	}
    109	
    110	map_ed = null;   // MapEdit オブジェクト
    111	
    112				//
    113				// MapEdit の開始
    114				//
    115	function map_edit()
    116	{
    117						// MapEdit オブジェクト
    118		map_ed = new MapEdit();
    119						// イベントリスナの追加
    120		mp.canvas.addEventListener("mousedown", map_ed.onMouseDown);
    121		mp.canvas.addEventListener("keydown", map_ed.onKeyDown, false);
    122						// ボタンの表示制御
    123		document.getElementById('method').style.display = "none";
    124		document.getElementById('map').style.display = "none";
    125		document.getElementById('start').style.display = "none";
    126		document.getElementById('first').innerHTML = "OK";
    127		document.getElementById('first').style.display = "";
    128		document.getElementById('finish').style.display = "none";
    129		document.getElementById('i_set').style.display = "none";
    130						// マップの選択
    131		let k = 0;
    132		for (let i1 = 0; i1 < document.getElementById('map_sel').options.length; i1++) {
    133			if (document.getElementById('map_sel').options[i1].selected) {
    134				k = i1;
    135				break;
    136			}
    137		}
    138		MP.map = MP.map1[k];
    139		map_ed.draw();
    140	}
    141				//
    142				// MapEdit オブジェクト(プロパティ)
    143				//
    144	function MapEdit()
    145	{
    146		this.k1 = 0;
    147		this.k2 = 0;
    148		this.mouse = false;
    149		return this;
    150	}
    151				//
    152				// MapEdit オブジェクト(メソッド draw)
    153				//
    154	MapEdit.prototype.draw = function()
    155	{
    156						// キャンバスのクリア
    157		mp.ctx.clearRect(0, 0, mp.canvas.width, mp.canvas.height);
    158						// 背景の描画
    159		for (let i1 = 0; i1 < MP.map_col; i1++) {
    160			let x = MP.block_width * i1;
    161			for (let i2 = 0; i2 < MP.map_row; i2++) {
    162				if (MP.map[i2][i1] > 0) {
    163					let y = i2 * MP.block_height;
    164					mp.ctx.drawImage(MP.block_image[MP.map[i2][i1]-1], x, y);
    165				}
    166			}
    167			mp.ctx.moveTo(x, 0);
    168			mp.ctx.lineTo(x, MP.map_row*MP.block_height);
    169			mp.ctx.stroke();
    170			if (i1 == MP.map_col-1) {
    171				x += MP.block_height;
    172				mp.ctx.moveTo(x, 0);
    173				mp.ctx.lineTo(x, MP.map_row*MP.block_height);
    174				mp.ctx.stroke();
    175			}
    176		}
    177	
    178		for (let i1 = 0; i1 < MP.map_row; i1++) {
    179			let y = i1 * MP.block_height;
    180			mp.ctx.moveTo(0, y);
    181			mp.ctx.lineTo(MP.map_col*MP.block_width, y);
    182			mp.ctx.stroke();
    183			if (i1 == MP.map_row-1) {
    184				y += MP.block_width;
    185				mp.ctx.moveTo(0, y);
    186				mp.ctx.lineTo(MP.map_col*MP.block_width, y);
    187				mp.ctx.stroke();
    188			}
    189		}
    190	}
    191				//
    192				// MapEdit オブジェクト(メソッド onMouseDown)
    193				//
    194	MapEdit.prototype.onMouseDown = function(event)
    195	{
    196		let x_base = mp.canvas.offsetLeft;   // キャンバスの左上のx座標;
    197		let y_base = mp.canvas.offsetTop;   // キャンバスの左上のy座標;
    198		let x = event.pageX - x_base;
    199		let y = event.pageY - y_base;
    200		map_ed.k1 = Math.floor(y / MP.block_height);
    201		map_ed.k2 = Math.floor(x / MP.block_width);
    202		if (map_ed.k1 >= 0 && map_ed.k1 < MP.map_row && map_ed.k2 >= 0 && map_ed.k2 < MP.map_col)
    203			map_ed.mouse = true;
    204		else
    205			map_ed.mouse = false;
    206	}
    207				//
    208				// MapEdit オブジェクト(メソッド onKeyDown)
    209				//
    210	MapEdit.prototype.onKeyDown = function(event)
    211	{
    212		if(map_ed.mouse && event.keyCode >= 48 && event.keyCode <= 50) {
    213			if (event.keyCode == 48)   // キー 0
    214				MP.map[map_ed.k1][map_ed.k2] = 0;
    215			else if (event.keyCode == 49)   // キー 1
    216				MP.map[map_ed.k1][map_ed.k2] = 1;
    217			else if (event.keyCode == 50)   // キー 2
    218				MP.map[map_ed.k1][map_ed.k2] = 2;
    219			map_ed.draw();
    220		}
    221	}
    			

    110 行目,118 行目( map_edit 関数)

      MapEdit オブジェクトを生成し,その結果をグローバル変数 map_ed( 110 行目)に代入しています.具体的には,144 行目~ 150 行目に記述された MapEdit 関数が実行されます.

    120,121 行目( map_edit 関数)

      mousedownkeydown に対するイベントリスナを追加しています.マップの編集は,障害物を設置したい場所(ブロック)をクリックし,その後,そこへ設置したい障害物をキーで指定することによって実行されます.そのため,これらのイベントリスナが必要になります.

    123 行目~ 129 行目( map_edit 関数)

      「スタート画面」ボタンの表示を「OK」に修正し( 126 行目),それ以外のボタンを非表示にしています.

    131 行目~ 138 行目( map_edit 関数)

      スタート画面にあるドロップダウンリストによって選択されたマップを,Map オブジェクトのプロパティ map に設定しています.

    139 行目( map_edit 関数)

      描画を実行するため,MapEdit オブジェクトの draw メソッド( 154 行目~ 190 行目)を実行しています.

    146,147 行目( MapEdit 関数)

      マウスでクリックされたマップ上の位置( k1 行 k2 列)を保存するための変数です.

    148 行目( MapEdit 関数)

      マウスでクリックされると true になり,障害物が指定されると false に戻ります.

    159 行目( MapEdit 関数)

      この for 文によって,160 行目~ 175 行目の処理が,マップの列の数だけ繰り返されます.

    160 行目~ 166 行目( draw メソッド)

      マップ情報に基づき,障害物を描画しています.

    167 行目~ 175 行目( draw メソッド)

      ブロックを区切る縦線を描画しています.170 行目~ 175 行目は,一番右の縦線の描画です.

    178 行目~ 189 行目( draw メソッド)

      ブロックを区切る横線を描画しています.

    194 行目~ 206 行目( onMouseDown メソッド)

      マウスがクリックされたときの処理です.マウスがクリックされた位置をキャンバス座標に変換し( 196 行目~ 199 行目),それを,マップ上の行 k1 と列 k2 に変換しています.変数 k1,k2 は,配列 map の添え字となりますので,整数である必要があります.しかし,代入演算子の右側で計算された値は必ずしも整数とはなりません.そこで,Math オブジェクトのメソッド floor を使して,小数点以下を切り捨てています( 200 行目~ 201 行目).その後,その行と列がマップ内の値であった場合は,変数 mouse の値を true にし,そうでない場合は,false に設定しています.

    210 行目~ 221 行目( onKeyDown メソッド)

      マウスがクリックされた後,数字キーが押された場合の処理です.キー 0 の場合は障害物を除き,キー 1 または 2 の場合は,対応する障害物をマップ上の指定されたブロックに設定した後,描画しています( 219 行目).

  3. ステップ3: 敵の生成

      ここでは,敵を生成し動かします.敵は画面左側のランダムな位置から出現し,右方向へ一定の速度で動いていきます.敵が画面右側のマップの外に達するとゲームオーバーになります.ただし,この段階では,ゲームオーバー処理は行いません.敵には 2 種類あり,敵1は障害物を避けながら移動しますが,敵2は障害物を無視して移動します.修正するプログラムは,gp_start 関数,GamePanel 関数,draw メソッド( GamePanel オブジェクトのメソッド),及び,Enemy 関数です.

    001	gp = null;   // GamePanel オブジェクト
    002	
    003				//
    004				// GamePanel の開始
    005				//
    006	function gp_start()
    007	{
    008						// GamePanel オブジェクト
    009		gp = new GamePanel();
    010						// タイマーのスタート
    011		gp.timerID = setInterval('gp.draw()', 33);
    012						// ボタンの表示制御
    013		document.getElementById('method').style.display = "none";
    014		document.getElementById('map').style.display = "none";
    015		document.getElementById('start').style.display = "none";
    016		document.getElementById('first').style.display = "none";
    017		document.getElementById('finish').style.display = "none";
    018		document.getElementById('i_set').style.display = "none";
    019	}
    020				//
    021				// GamePanel オブジェクト(プロパティ)
    022				//
    023	function GamePanel()
    024	{
    025		this.timerID = -1;   // タイマー
    026		this.count   = 0;   // カウンタ
    027						// マップの選択
    028		let k = 0;
    029		for (let i1 = 0; i1 < document.getElementById('map_sel').options.length; i1++) {
    030			if (document.getElementById('map_sel').options[i1].selected) {
    031				k = i1;
    032				break;
    033			}
    034		}
    035		MP.map = MP.map1[k];
    036						// 敵
    037								// 敵の数
    038		this.n_enemy    = new Array();   // 敵の数
    039		this.n_enemy[0] = parseInt(document.getElementById('en1').value);
    040		this.n_enemy[1] = parseInt(document.getElementById('en2').value);
    041		this.n_e_now    = this.n_enemy[0] + this.n_enemy[1];   // 出現していない敵の数
    042								// 敵の初期状態
    043		this.e_state = new Array();   // 0:存在,1:動作中,-1:消滅
    044		this.enemy   = new Array();
    045		k = 0;
    046		for (let i1 = 0; i1 < this.n_enemy.length; i1++) {
    047			for (let i2 = 0; i2 < this.n_enemy[i1]; i2++) {
    048				this.e_state[k] = 0;
    049				this.enemy[k] = new Enemy(i1);
    050				k++;
    051			}
    052		}
    053								// 次の敵
    054		this.next_time = Math.floor(30 * Math.random());
    055		this.next      = Math.floor(this.e_state.length * Math.random());
    056		if (this.next >= this.e_state.length)
    057			this.next = this.e_state.length - 1;
    058	
    059		return this;
    060	}
    061				//
    062				// GamePanel オブジェクト(メソッド draw)
    063				//
    064	GamePanel.prototype.draw = function()
    065	{
    066		gp.count++;
    067						// キャンバスのクリア
    068		mp.ctx.clearRect(0, 0, mp.canvas.width, mp.canvas.height);
    069						// 背景の描画
    070		for (let i1 = 0; i1 < MP.map_col; i1++) {
    071			let x = MP.block_width * i1;
    072			for (let i2 = 0; i2 < MP.map_row; i2++) {
    073				if (MP.map[i2][i1] > 0) {
    074					let y = i2 * MP.block_height;
    075					mp.ctx.drawImage(MP.block_image[MP.map[i2][i1]-1], x, y, MP.block_width, MP.block_height);
    076				}
    077			}
    078		}
    079						// 敵の描画
    080		for (let i1 = 0; i1 < gp.e_state.length; i1++) {
    081			if (gp.e_state[i1] > 0) {
    082				let sw = 0;
    083								// 敵1
    084				if (gp.enemy[i1].type == 0) {
    085										// 右へ移動
    086					if (gp.enemy[i1].state == 0) {
    087						gp.enemy[i1].x += gp.enemy[i1].v;
    088						let k2 = Math.floor((gp.enemy[i1].x + MP.block_width) / MP.block_width);
    089						if (k2 >= MP.map_col)
    090							sw = 1;
    091						else {
    092							let k1 = Math.floor(gp.enemy[i1].y / MP.block_height);
    093							if (MP.map[k1][k2] > 0) {
    094								gp.enemy[i1].x = (k2 - 1) * MP.block_width;
    095								let r = Math.random();
    096								if (k1 == MP.map_row-1 && MP.map[k1-1][k2-1] == 0
    								    || k1 > 0 && k1 < MP.map_row-1 && (MP.map[k1+1][k2-1] > 0
    								    || r > 0.5 && MP.map[k1+1][k2-1] == 0 && MP.map[k1-1][k2-1] == 0))
    097									gp.enemy[i1].state = -1;   // 上へ
    098								else if (k1 == 0 && MP.map[k1+1][k2-1] == 0
    								    || k1 > 0 && k1 < MP.map_row-1 && (MP.map[k1-1][k2-1] > 0
    								    || r <= 0.5 && MP.map[k1+1][k2-1] == 0 && MP.map[k1-1][k2-1] == 0))
    099									gp.enemy[i1].state = 1;   // 下へ
    100							}
    101						}
    102					}
    103										// 上へ移動
    104					else if (gp.enemy[i1].state < 0) {
    105						gp.enemy[i1].y -= gp.enemy[i1].v;
    106						let k1 = Math.floor((gp.enemy[i1].y + MP.block_height) / MP.block_height);
    107						let k2 = Math.floor(gp.enemy[i1].x / MP.block_width) + 1;
    108						if (MP.map[k1][k2] == 0) {
    109							gp.enemy[i1].y = k1 * MP.block_height;
    110							gp.enemy[i1].state = 0;   // 右へ
    111						}
    112						else if (k1 == 0 || MP.map[k1-1][k2-1] > 0)
    113							gp.enemy[i1].state = 1;   // 下へ
    114					}
    115										// 下へ移動
    116					else {
    117						gp.enemy[i1].y += gp.enemy[i1].v;
    118						let k1 = Math.floor(gp.enemy[i1].y / MP.block_height);
    119						let k2 = Math.floor(gp.enemy[i1].x / MP.block_width) + 1;
    120						if (k1 >= MP.map_row-1) {
    121							gp.enemy[i1].y = k1 * MP.block_height;
    122							if (MP.map[k1][k2] == 0)
    123								gp.enemy[i1].state = 0;   // 右へ
    124							else
    125								gp.enemy[i1].state = -1;   // 上へ
    126						}
    127						else {
    128							if (MP.map[k1][k2] == 0) {
    129								gp.enemy[i1].y = k1 * MP.block_height;
    130								gp.enemy[i1].state = 0;   // 右へ
    131							}
    132							else if (MP.map[k1+1][k2-1] > 0)
    133								gp.enemy[i1].state = -1;   // 上へ
    134						}
    135					}
    136				}
    137								// 敵2
    138				else if (gp.enemy[i1].type == 1) {
    139					gp.enemy[i1].x += gp.enemy[i1].v;
    140					let k2 = Math.floor((gp.enemy[i1].x + MP.block_width) / MP.block_width);
    141					if (k2 >= MP.map_col)
    142						sw = 1;
    143				}
    144								// ゲームオーバーか否か
    145				if (sw == 0)
    146					mp.ctx.drawImage(gp.enemy[i1].image, gp.enemy[i1].x, gp.enemy[i1].y, MP.block_width, MP.block_height);
    147				else {
    148	//				clearInterval(gp.timerID);   // タイマーの停止
    149	//				gop_start();   // ゲームオーバー
    150				}
    151			}
    152		}
    153						// 次の敵
    154		if (gp.count == gp.next_time) {
    155			gp.n_e_now--;
    156			gp.count            = 0;
    157			gp.e_state[gp.next] = 1;
    158			if (gp.n_e_now > 0) {
    159				gp.next_time = Math.floor(5 * 30 - 30 * Math.random());
    160				gp.next = -1;
    161				while (gp.next < 0) {
    162					gp.next = Math.floor(gp.e_state.length * Math.random());
    163					if (gp.next >= gp.e_state.length)
    164						gp.next = gp.e_state.length - 1;
    165					if (gp.e_state[gp.next] != 0)
    166						gp.next = -1;
    167				}
    168			}
    169			else
    170				gp.next_time = -1;
    171		}
    172	}
    173				//
    174				// Enemy オブジェクト(プロパティ)
    175				//
    176	function Enemy(sw)
    177	{
    178		this.image = new Image();
    179		if (sw == 0)
    180			this.image.src = "image/enemy1.jpg";
    181		else
    182			this.image.src = "image/enemy2.jpg";
    183	
    184		this.type  = sw;   // 敵のタイプ
    185		this.state = 0;   // 0:右へ移動,1:下へ移動,-1:上へ移動
    186	
    187		this.x = 0;
    188		this.y = Math.floor(MP.map_row * Math.random ());
    189		if (this.y >= MP.map_row)
    190			this.y = MP.map_row - 1;
    191		this.y *= MP.block_height;
    192		this.v = 2;   // 移動速度
    193	
    194		return this;
    195	}
    			
    011 行目,25 行目( gp_start 関数,GamePanel 関数)

      33 ms 毎に再描画( GamePanel オブジェクトの draw メソッドを呼ぶ)させるため,タイマーを起動しています.

    026 行目( GamePanel 関数)

      敵をランダムな時間間隔で出現させるために使用されるカウンタです.

    038 行目~ 040 行目( GamePanel 関数)

      配列を定義し,敵1及び敵2の数を,スタート画面のテキストフィールドに設定された値から読み込んでいます.なお,parseInt は,トップレベル関数の一つであり,文字列を整数に変換します.

    041 行目( GamePanel 関数)

      まだ画面上に出現していない敵の数の初期値です(敵1と敵2を加えた数).

    043 行目~ 052 行目( GamePanel 関数)

      敵( Enemy オブジェクト)を生成( 049 行目)すると共に,それらの初期設定( 048 行目)を行っています.

    054 行目~ 057 行目( GamePanel 関数)

      次に敵が現れる時間( next_time ),及び,敵の番号 next( [0, n_e_now-1] 区間の一様乱数)を設定しています.この設定の結果,最初の敵は 1 秒以内( next_time × 描画周期)に画面上に現れることになります.なお,length は,Array オブジェクトのプロパティであり,配列の要素数を表します.

    066 行目( draw メソッド)

      カウントアップしています.011 行目から,カウンタの値 30 がほぼ 1 秒に相当します.

    080 行目~ 152 行目( draw メソッド)

      080 行目の for 文によって,081 行目~ 151 行目が,敵の数だけ繰り返されます.081 行目の if 文により,移動中の敵(画面に表示されている敵,つまり,e_state[i1] = 1 である敵)に対して以下の処理が実行されます.082 行目の変数 sw は,敵がマップの外に出ると 1 に設定され,ゲームオーバーとなります.084 行目~ 136 行目が敵1,また,138 行目~ 143 行目が敵2に対する処理です.

    • 087 行目~ 101 行目: 敵の進行方向は,185 行目のように記述されます.ここは,敵1が右に進んでいる場合の処理です.右側のマップの外に出た場合はゲームオーバーにしています( 090 行目).そうでない場合は,障害物に衝突したか否かの判定( 093 行目)を行い,衝突した場合は回避行動に移らせています.上下に障害物が無い場合は,上または下がランダムに選択されますが,上または下に障害物が存在した場合は,障害物の無い方向に移動します.

    • 105 行目~ 113 行目: 敵1が障害物を避け上に進んでいる場合に対する処理です.右側に障害物が無い場合は右への移動を開始します.また,上にある障害物と衝突した場合は,下に向かって進み始めます.

    • 117 行目~ 134 行目: 敵1が障害物を避け下に進んでいる場合に対する処理です.右側に障害物が無い場合は右への移動を開始します.また,下にある障害物と衝突した場合は,上に向かって進み始めます.

    • 139 行目~ 142 行目: 敵2は障害物を無視して移動しますので,単に右に移動させ,ゲームオーバー判定を行っているだけです.

    • 145 行目~ 150 行目: ゲーム-バーで無い場合は再描画し( 146 行目),ゲームオーバーの場合は,タイマーを停止し,ゲームオーバー画面に移動しています.ただし,デバッグ等の関係から,この処理はコメントにしてあります(コメントを外せば確認できます).

    154 行目~ 171 行目( draw メソッド)

      カウンタの値が次の敵出現時刻( next_time )に一致した場合は,指定された敵を画面上に出現させます( 157 行目).その後,まだ画面上に出現していない敵が残っている場合は,次の敵の出現時刻と敵の番号を決定します( 159 行目~ 167 行目).159 行目の指定により,次の敵は 4 ~ 5 秒後に現れることになります.出現していない敵が残っていない場合は,next_time の値を -1 に設定します( 169,170 行目).

    176 行目~ 195 行目( Enemy 関数)

      Enemy オブジェクトのプロパティを設定する関数です.178 行目~ 182 行目では,敵のタイプによって画像を変えています.敵のタイプと右への移動を初期設定( 184,185 行目)すると共に,敵の y 座標の初期値をランダムに決めています( 188 行目~ 191 行目).188 行目において,位置をブロックの境界に合わせるため,Math オブジェクトのメソッド floor を使用して,小数点以下を切り捨てていることに注意してください.

  4. ステップ4: 味方の生成

      ここでは,味方を生成し動かします.味方は,マウスでクリックすることによって,最初に設定された数の制限内であれば,マップ上の任意の位置に置くことができます.味方には 2 種類あり,味方1は障害物を避けながら左に移動しますが,味方2は最初に置かれた位置に止まります.ただし,味方1は敵と衝突することによって敵を消滅させることができますが,味方2は,その近傍を通った敵を消滅させることができます.すべての敵を消滅させることができれば,ゲームクリアになります.ただし,この段階では,まだ,敵の消滅を行ってはいません.修正するプログラムは,gp_start 関数,GamePanel 関数,draw メソッド( GamePanel オブジェクトのメソッド),及び,Friend 関数です.

    001	gp = null;   // GamePanel オブジェクト
    002	
    003				//
    004				// GamePanel の開始
    005				//
    006	function gp_start()
    007	{
    008						// GamePanel オブジェクト
    009		gp = new GamePanel();
    010						// タイマーのスタート
    011		gp.timerID = setInterval('gp.draw()', 33);
    012						// イベントリスナの追加
    013		mp.canvas.addEventListener("mousedown", gp.onMouseDown);
    014		mp.canvas.addEventListener("keydown", gp.onKeyDown, false);
    015						// ボタンの表示制御
    016		document.getElementById('method').style.display = "none";
    017		document.getElementById('map').style.display = "none";
    018		document.getElementById('start').style.display = "none";
    019		document.getElementById('first').style.display = "none";
    020		document.getElementById('finish').style.display = "none";
    021		document.getElementById('i_set').style.display = "none";
    022	}
    023				//
    024				// GamePanel オブジェクト(プロパティ)
    025				//
    026	function GamePanel()
    027	{
    028		this.timerID  = -1;   // タイマー
    029		this.count    = 0;   // カウンタ
    030		this.mark     = new Image();   // マーカー
    031		this.mark.src = "image/mark.jpg";
    032		this.mouse    = false;
    033		this.mark_x   = 0;   // マーカーのx座標
    034		this.mark_y   = 0;   // マーカーのy座標
    035						// マップの選択
    036		let k = 0;
    037		for (let i1 = 0; i1 < document.getElementById('map_sel').options.length; i1++) {
    038			if (document.getElementById('map_sel').options[i1].selected) {
    039				k = i1;
    040				break;
    041			}
    042		}
    043		MP.map = MP.map1[k];
    044						// 味方
    045								// 味方の数
    046		this.n_friend    = new Array();   // 味方の数
    047		this.n_friend[0] = parseInt(document.getElementById('fr1').value);
    048		this.n_friend[1] = parseInt(document.getElementById('fr2').value);
    049								// 味方の初期状態
    050		this.f_state = new Array();   // 0:存在,1:動作中,-1:消滅
    051		this.friend  = new Array();
    052		for (let i1 = 0; i1 < this.n_friend.length; i1++) {
    053			this.f_state[i1] = new Array();   // 0:存在,1:動作中,-1:消滅
    054			this.friend[i1] = new Array();
    055			for (let i2 = 0; i2 < this.n_friend[i1]; i2++) {
    056				this.f_state[i1][i2] = 0;
    057				this.friend[i1][i2] = new Friend(i1);
    058			}
    059		}
    060						// 敵
    061								// 敵の数
    062		this.n_enemy    = new Array();   // 敵の数
    063		this.n_enemy[0] = parseInt(document.getElementById('en1').value);
    064		this.n_enemy[1] = parseInt(document.getElementById('en2').value);
    065		this.n_e_now    = this.n_enemy[0] + this.n_enemy[1];   // 出現していない敵の数
    066								// 敵の初期状態
    067		this.e_state = new Array();   // 0:存在,1:動作中,-1:消滅
    068		this.enemy   = new Array();
    069		let k = 0;
    070		for (let i1 = 0; i1 < this.n_enemy.length; i1++) {
    071			for (let i2 = 0; i2 < this.n_enemy[i1]; i2++) {
    072				this.e_state[k] = 0;
    073				this.enemy[k] = new Enemy(i1);
    074				k++;
    075			}
    076		}
    077								// 次の敵
    078		this.next_time = Math.floor(30 * Math.random());
    079		this.next      = Math.floor(this.e_state.length * Math.random());
    080		if (this.next >= this.e_state.length)
    081			this.next = this.e_state.length - 1;
    082	
    083		return this;
    084	}
    085				//
    086				// GamePanel オブジェクト(メソッド draw)
    087				//
    088	GamePanel.prototype.draw = function()
    089	{
    090		gp.count++;
    091						// キャンバスのクリア
    092		mp.ctx.clearRect(0, 0, mp.canvas.width, mp.canvas.height);
    093						// 背景の描画
    094		for (let i1 = 0; i1 < MP.map_col; i1++) {
    095			let x = MP.block_width * i1;
    096			for (let i2 = 0; i2 < MP.map_row; i2++) {
    097				if (MP.map[i2][i1] > 0) {
    098					let y = i2 * MP.block_height;
    099					mp.ctx.drawImage(MP.block_image[MP.map[i2][i1]-1], x, y, MP.block_width, MP.block_height);
    100				}
    101			}
    102		}
    103						// マーカーの描画
    104		mp.ctx.drawImage(gp.mark, gp.mark_x, gp.mark_y, MP.block_width, MP.block_height);
    105						// 味方の描画
    106								// 味方1
    107		for (let i1 = 0; i1 < gp.f_state[0].length; i1++) {
    108			if (gp.f_state[0][i1] > 0) {
    109										// 左へ移動
    110				if (gp.friend[0][i1].state == 0) {
    111					gp.friend[0][i1].x -= gp.friend[0][i1].v;
    112					if (gp.friend[0][i1].x < 0)
    113						gp.f_state[0][i1] = -1;
    114					else {
    115						let k1 = Math.floor(gp.friend[0][i1].y / MP.block_height);
    116						let k2 = Math.floor(gp.friend[0][i1].x / MP.block_width);
    117						if (MP.map[k1][k2] > 0) {
    118							gp.friend[0][i1].x = (k2 + 1) * MP.block_width;
    119							let r = Math.random();
    120							if (k1 == MP.map_row-1 && MP.map[k1-1][k2+1] == 0
    							    || k1 > 0 && k1 < MP.map_row-1 && (MP.map[k1+1][k2+1] > 0
    							    || r > 0.5 && MP.map[k1+1][k2+1] == 0 && MP.map[k1-1][k2+1] == 0))
    121								gp.friend[0][i1].state = -1;   // 上へ
    122							else if (k1 == 0 && MP.map[k1+1][k2+1] == 0
    							    || k1 > 0 && k1 < MP.map_row-1 && (MP.map[k1-1][k2+1] > 0
    							    || r <= 0.5 && MP.map[k1+1][k2+1] == 0 && MP.map[k1-1][k2+1] == 0))
    123								gp.friend[0][i1].state = 1;   // 下へ
    124						}
    125					}
    126				}
    127										// 上へ移動
    128				else if (gp.friend[0][i1].state < 0) {
    129					gp.friend[0][i1].y -= gp.friend[0][i1].v;
    130					let k1 = Math.floor((gp.friend[0][i1].y + MP.block_height) / MP.block_height);
    131					let k2 = Math.floor(gp.friend[0][i1].x / MP.block_width) - 1;
    132					if (MP.map[k1][k2] == 0) {
    133						gp.friend[0][i1].y = k1 * MP.block_height;
    134						gp.friend[0][i1].state = 0;   // 左へ
    135					}
    136					else if (k1 == 0 || MP.map[k1-1][k2+1] > 0)
    137						gp.friend[0][i1].state = 1;   // 下へ
    138				}
    139										// 下へ移動
    140				else {
    141					gp.friend[0][i1].y += gp.friend[0][i1].v;
    142					let k1 = Math.floor(gp.friend[0][i1].y / MP.block_height);
    143					let k2 = Math.floor(gp.friend[0][i1].x / MP.block_width) - 1;
    144					if (k1 >= MP.map_row-1) {
    145						gp.friend[0][i1].y = k1 * MP.block_height;
    146						if (MP.map[k1][k2] == 0)
    147							gp.friend[0][i1].state = 0;   // 左へ
    148						else
    149							gp.friend[0][i1].state = -1;   // 上へ
    150					}
    151					else {
    152						if (MP.map[k1][k2] == 0) {
    153							gp.friend[0][i1].y = k1 * MP.block_height;
    154							gp.friend[0][i1].state = 0;   // 右へ
    155						}
    156						else if (MP.map[k1+1][k2+1] > 0)
    157							gp.friend[0][i1].state = -1;   // 上へ
    158					}
    159				}
    160				if (gp.f_state[0][i1] > 0)
    161					mp.ctx.drawImage(gp.friend[0][i1].image, gp.friend[0][i1].x, gp.friend[0][i1].y, MP.block_width, MP.block_height);
    162			}
    163		}
    164								// 味方2
    165		for (let i1 = 0; i1 < gp.f_state[1].length; i1++) {
    166			if (gp.f_state[1][i1] > 0)
    167				mp.ctx.drawImage(gp.friend[1][i1].image, gp.friend[1][i1].x, gp.friend[1][i1].y, MP.block_width, MP.block_height);
    168		}
    169						// 敵の描画
    170		for (let i1 = 0; i1 < gp.e_state.length; i1++) {
    171			if (gp.e_state[i1] > 0) {
    172				let sw = 0;
    173								// 敵1
    174				if (gp.enemy[i1].type == 0) {
    175										// 右へ移動
    176					if (gp.enemy[i1].state == 0) {
    177						gp.enemy[i1].x += gp.enemy[i1].v;
    178						let k2 = Math.floor((gp.enemy[i1].x + MP.block_width) / MP.block_width);
    179						if (k2 >= MP.map_col)
    180							sw = 1;
    181						else {
    182							let k1 = Math.floor(gp.enemy[i1].y / MP.block_height);
    183							if (MP.map[k1][k2] > 0) {
    184								gp.enemy[i1].x = (k2 - 1) * MP.block_width;
    185								let r = Math.random();
    186								if (k1 == MP.map_row-1 && MP.map[k1-1][k2-1] == 0
    								    || k1 > 0 && k1 < MP.map_row-1 && (MP.map[k1+1][k2-1] > 0
    								    || r > 0.5 && MP.map[k1+1][k2-1] == 0 && MP.map[k1-1][k2-1] == 0))
    187									gp.enemy[i1].state = -1;   // 上へ
    188								else if (k1 == 0 && MP.map[k1+1][k2-1] == 0
    								    || k1 > 0 && k1 < MP.map_row-1 && (MP.map[k1-1][k2-1] > 0
    								    || r <= 0.5 && MP.map[k1+1][k2-1] == 0 && MP.map[k1-1][k2-1] == 0))
    189									gp.enemy[i1].state = 1;   // 下へ
    190							}
    191						}
    192					}
    193										// 上へ移動
    194					else if (gp.enemy[i1].state < 0) {
    195						gp.enemy[i1].y -= gp.enemy[i1].v;
    196						let k1 = Math.floor((gp.enemy[i1].y + MP.block_height) / MP.block_height);
    197						let k2 = Math.floor(gp.enemy[i1].x / MP.block_width) + 1;
    198						if (MP.map[k1][k2] == 0) {
    199							gp.enemy[i1].y = k1 * MP.block_height;
    200							gp.enemy[i1].state = 0;   // 右へ
    201						}
    202						else if (k1 == 0 || MP.map[k1-1][k2-1] > 0)
    203							gp.enemy[i1].state = 1;   // 下へ
    204					}
    205										// 下へ移動
    206					else {
    207						gp.enemy[i1].y += gp.enemy[i1].v;
    208						let k1 = Math.floor(gp.enemy[i1].y / MP.block_height);
    209						let k2 = Math.floor(gp.enemy[i1].x / MP.block_width) + 1;
    210						if (k1 >= MP.map_row-1) {
    211							gp.enemy[i1].y = k1 * MP.block_height;
    212							if (MP.map[k1][k2] == 0)
    213								gp.enemy[i1].state = 0;   // 右へ
    214							else
    215								gp.enemy[i1].state = -1;   // 上へ
    216						}
    217						else {
    218							if (MP.map[k1][k2] == 0) {
    219								gp.enemy[i1].y = k1 * MP.block_height;
    220								gp.enemy[i1].state = 0;   // 右へ
    221							}
    222							else if (MP.map[k1+1][k2-1] > 0)
    223								gp.enemy[i1].state = -1;   // 上へ
    224						}
    225					}
    226				}
    227								// 敵2
    228				else if (gp.enemy[i1].type == 1) {
    229					gp.enemy[i1].x += gp.enemy[i1].v;
    230					let k2 = Math.floor((gp.enemy[i1].x + MP.block_width) / MP.block_width);
    231					if (k2 >= MP.map_col)
    232						sw = 1;
    233				}
    234								// ゲームオーバーか否か
    235				if (sw == 0)
    236					mp.ctx.drawImage(gp.enemy[i1].image, gp.enemy[i1].x, gp.enemy[i1].y, MP.block_width, MP.block_height);
    237				else {
    238	//				clearInterval(gp.timerID);   // タイマーの停止
    239	//				gop_start();   // ゲームオーバー
    240				}
    241			}
    242		}
    243						// 次の敵
    244		if (gp.count == gp.next_time) {
    245			gp.n_e_now--;
    246			gp.count            = 0;
    247			gp.e_state[gp.next] = 1;
    248			if (gp.n_e_now > 0) {
    249				gp.next_time = Math.floor(5 * 30 - 30 * Math.random());
    250				gp.next      = -1;
    251				while (gp.next < 0) {
    252					gp.next = Math.floor(gp.e_state.length * Math.random());
    253					if (gp.next >= gp.e_state.length)
    254						gp.next = gp.e_state.length - 1;
    255					if (gp.e_state[gp.next] != 0)
    256						gp.next = -1;
    257				}
    258			}
    259			else
    260				gp.next_time = -1;
    261		}
    262	}
    263				//
    264				// Friend オブジェクト(プロパティ)
    265				//
    266	function Friend(sw)
    267	{
    268		this.image = new Image();
    269		if (sw == 0)
    270			this.image.src = "image/friend1.jpg";
    271		else
    272			this.image.src = "image/friend2.jpg";
    273	
    274		this.state = 0;   // 0:左へ移動,1:下へ移動,-1:上へ移動
    275	
    276		this.x = 0;
    277		this.y = 0;
    278		this.v = 2;   // 移動速度
    279	
    280		return this;
    281	}
    282				//
    283				// Enemy オブジェクト(プロパティ)
    284				//
    285	function Enemy(sw)
    286	{
    287		this.image = new Image();
    288		if (sw == 0)
    289			this.image.src = "image/enemy1.jpg";
    290		else
    291			this.image.src = "image/enemy2.jpg";
    292	
    293		this.type  = sw;   // 敵のタイプ
    294		this.state = 0;   // 0:右へ移動,1:下へ移動,-1:上へ移動
    295	
    296		this.x = 0;
    297		this.y = Math.floor(MP.map_row * Math.random ());
    298		if (this.y >= MP.map_row)
    299			this.y = MP.map_row - 1;
    300		this.y *= MP.block_height;
    301		this.v = 2;   // 移動速度
    302	
    303		return this;
    304	}
    305				//
    306				// GamePanel オブジェクト(メソッド onMouseDown)
    307				//
    308	GamePanel.prototype.onMouseDown = function(event)
    309	{
    310		let x_base  = mp.canvas.offsetLeft;   // キャンバスの左上のx座標
    311		let y_base  = mp.canvas.offsetTop;   // キャンバスの左上のy座標
    312		let k1      = Math.floor((event.pageY - y_base) / MP.block_height);
    313		let k2      = Math.floor((event.pageX - x_base) / MP.block_width);
    314		if (k1 >= 0 && k1 < MP.map_row && k2 >= 0 && k2 < MP.map_col && MP.map[k1][k2] == 0) {
    315			gp.mark_x = k2 * MP.block_width;
    316			gp.mark_y = k1 * MP.block_height;
    317			gp.mouse  = true;
    318		}
    319	}
    320				//
    321				// GamePanel オブジェクト(メソッド onKeyDown)
    322				//
    323	GamePanel.prototype.onKeyDown = function(event)
    324	{
    325		if(gp.mouse && event.keyCode >= 49 && event.keyCode <= 51) {
    326			if (event.keyCode == 49) {   // キー 1
    327				if (gp.n_friend[0] > 0) {
    328					gp.n_friend[0]--;
    329					gp.f_state[0][gp.n_friend[0]]  = 1;
    330					gp.friend[0][gp.n_friend[0]].x = gp.mark_x;
    331					gp.friend[0][gp.n_friend[0]].y = gp.mark_y;
    332				}
    333			}
    334			else if (event.keyCode == 50) {   // キー 2
    335				if (gp.n_friend[1] > 0) {
    336					gp.n_friend[1]--;
    337					gp.f_state[1][gp.n_friend[1]]  = 1;
    338					gp.friend[1][gp.n_friend[1]].x = gp.mark_x;
    339					gp.friend[1][gp.n_friend[1]].y = gp.mark_y;
    340				}
    341			}
    342			gp.mark_x = 0;
    343			gp.mark_y = 0;
    344			gp.mouse = false;
    345		}
    346	}
    			
    013,014 行目( gp_start 関数)

      mousedownkeydown に対するイベントリスナを追加しています.味方の配置は,味方を設置したい場所(ブロック)をクリックし,その後,そこへ設置したい味方をキーで指定することによって実行されます.そのため,これらのイベントリスナが必要になります.

    030,031 行目( GamePanel 関数)

      左上にマーカーを表示し,味方を置きたい場所をマウスでクリックするとマーカーがその位置に移動します.ここでは,マーカーの画像を設定しています.

    032 行目( GamePanel 関数)

      味方を置きたい場所をマウスでクリックすると,この値が true になります.

    033,034 行目( GamePanel 関数)

      マーカーの位置です.

    046 行目~ 048 行目( GamePanel 関数)

      配列を定義し,味方1及び味方2に対する上限数を,スタート画面のテキストフィールドに設定された値から読み込んでいます.

    050 行目~ 059 行目( GamePanel 関数)

      味方( Friend オブジェクト)を生成( 057 行目)すると共に,それらの初期設定( 056 行目)を行っています.敵の場合は,2 種類の敵をランダムに出現させたいため,1 次元配列に入れていましたが,味方の場合は,2 種類の味方を指定して処理したいため,2 次元配列で処理しています.f_state[0][i] には味方1の,また,f_state[1][i] には味方2に対する情報が入ります.friend についても同様です.

    104 行目( draw メソッド)

      マーカーを表示しています.

    107 行目~ 163 行目( draw メソッド)

      画面に表示されている味方1( f_state[0][i1] = 1 の場合)に対する処理です.左へ進む以外,基本的に,敵1に対する処理と同様です.ただし,左側のマップの外に出た場合は味方1を消滅させています( 113 行目).

    165 行目~ 168 行目( draw メソッド)

      画面に表示されている味方2( f_state[1][i1] = 1 の場合)に対する処理です.単に,その画像を表示しているだけです.

    266 行目~ 281 行目( Friend 関数)

      Friend オブジェクトのプロパティを設定する関数です.268 行目~ 272 行目では,味方のタイプによって画像を変えてると共に,左への移動を初期設定( 274 行目)しています.

    308 行目~ 319 行目( onMouseDown メソッド)

      マウスがクリックされたときの処理です.マウスがクリックされた位置をキャンバス座標に変換し,それを,マップ上の行と列に変換しています( 310 行目~ 313 行目).変数 k1,k2 は,配列 map の添え字となりますので,整数である必要があります.しかし,代入演算子の右側で計算された値は必ずしも整数とはなりません.そこで,Math オブジェクトのメソッド floor を使用して,小数点以下を切り捨てています.その後,その行と列がマップ内の値であった場合は,その値を使用してマーカーの座標を設定すると共に,変数 mouse の値を true にしています.

    323 行目~ 346 行目( onKeyDown メソッド)

      マウスがクリックされた後,数字キーが押された場合の処理です.キー 1 の場合は味方1を,キー 2 の場合は味方2を配置しています.その後,マーカーを画面左上に戻しています.

  5. ステップ5: 完成

      味方により敵を消滅させる処理を加えて,ゲームを完成させます.修正するプログラムは,GamePanel 関数と draw メソッド( GamePanel オブジェクトのメソッド)です..

    001	gp = null;   // GamePanel オブジェクト
    002	
    003				//
    004				// GamePanel の開始
    005				//
    006	function gp_start()
    007	{
    008						// GamePanel オブジェクト
    009		gp = new GamePanel();
    010						// タイマーのスタート
    011		gp.timerID = setInterval('gp.draw()', 33);
    012						// イベントリスナの追加
    013		mp.canvas.addEventListener("mousedown", gp.onMouseDown);
    014		mp.canvas.addEventListener("keydown", gp.onKeyDown, false);
    015						// ボタンの表示制御
    016		document.getElementById('method').style.display = "none";
    017		document.getElementById('map').style.display = "none";
    018		document.getElementById('start').style.display = "none";
    019		document.getElementById('first').style.display = "none";
    020		document.getElementById('finish').style.display = "none";
    021		document.getElementById('i_set').style.display = "none";
    022	}
    023				//
    024				// GamePanel オブジェクト(プロパティ)
    025				//
    026	function GamePanel()
    027	{
    028		this.timerID  = -1;   // タイマー
    029		this.count    = 0;   // カウンタ
    030		this.mark     = new Image();   // マーカー
    031		this.mark.src = "image/mark.jpg";
    032		this.mouse    = false;
    033		this.mark_x   = 0;   // マーカーのx座標
    034		this.mark_y   = 0;   // マーカーのy座標
    035						// マップの選択
    036		let k = 0;
    037		for (let i1 = 0; i1 < document.getElementById('map_sel').options.length; i1++) {
    038			if (document.getElementById('map_sel').options[i1].selected) {
    039				k = i1;
    040				break;
    041			}
    042		}
    043		MP.map = MP.map1[k];
    044						// 味方
    045								// 味方の数
    046		this.n_friend    = new Array();   // 味方の数
    047		this.n_friend[0] = parseInt(document.getElementById('fr1').value);
    048		this.n_friend[1] = parseInt(document.getElementById('fr2').value);
    049								// 味方の初期状態
    050		this.f_state = new Array();   // 0:存在,1:動作中,-1:消滅
    051		this.friend  = new Array();
    052		for (let i1 = 0; i1 < this.n_friend.length; i1++) {
    053			this.f_state[i1] = new Array();   // 0:存在,1:動作中,-1:消滅
    054			this.friend[i1] = new Array();
    055			for (let i2 = 0; i2 < this.n_friend[i1]; i2++) {
    056				this.f_state[i1][i2] = 0;
    057				this.friend[i1][i2] = new Friend(i1);
    058			}
    059		}
    060						// 敵
    061								// 敵の数
    062		this.n_enemy    = new Array();   // 敵の数
    063		this.n_enemy[0] = parseInt(document.getElementById('en1').value);
    064		this.n_enemy[1] = parseInt(document.getElementById('en2').value);
    065		this.n_e_now    = this.n_enemy[0] + this.n_enemy[1];   // 出現していない敵の数
    066		this.n_e_now_ex = this.n_e_now;   // 存在している敵の数
    067								// 敵の初期状態
    068		this.e_state = new Array();   // 0:存在,1:動作中,-1:消滅
    069		this.enemy   = new Array();
    070		let k = 0;
    071		for (let i1 = 0; i1 < this.n_enemy.length; i1++) {
    072			for (let i2 = 0; i2 < this.n_enemy[i1]; i2++) {
    073				this.e_state[k] = 0;
    074				this.enemy[k] = new Enemy(i1);
    075				k++;
    076			}
    077		}
    078								// 次の敵
    079		this.next_time = Math.floor(30 * Math.random());
    080		this.next      = Math.floor(this.e_state.length * Math.random());
    081		if (this.next >= this.e_state.length)
    082			this.next = this.e_state.length - 1;
    083	
    084		return this;
    085	}
    086				//
    087				// GamePanel オブジェクト(メソッド draw)
    088				//
    089	GamePanel.prototype.draw = function()
    090	{
    091		gp.count++;
    092						// キャンバスのクリア
    093		mp.ctx.clearRect(0, 0, mp.canvas.width, mp.canvas.height);
    094						// 背景の描画
    095		for (let i1 = 0; i1 < MP.map_col; i1++) {
    096			let x = MP.block_width * i1;
    097			for (let i2 = 0; i2 < MP.map_row; i2++) {
    098				if (MP.map[i2][i1] > 0) {
    099					let y = i2 * MP.block_height;
    100					mp.ctx.drawImage(MP.block_image[MP.map[i2][i1]-1], x, y, MP.block_width, MP.block_height);
    101				}
    102			}
    103		}
    104						// マーカーの描画
    105		mp.ctx.drawImage(gp.mark, gp.mark_x, gp.mark_y, MP.block_width, MP.block_height);
    106						// 味方の描画
    107								// 味方1
    108		for (let i1 = 0; i1 < gp.f_state[0].length; i1++) {
    109			if (gp.f_state[0][i1] > 0) {
    110										// 左へ移動
    111				if (gp.friend[0][i1].state == 0) {
    112					gp.friend[0][i1].x -= gp.friend[0][i1].v;
    113					if (gp.friend[0][i1].x < 0)
    114						gp.f_state[0][i1] = -1;
    115					else {
    116						let k1 = Math.floor(gp.friend[0][i1].y / MP.block_height);
    117						let k2 = Math.floor(gp.friend[0][i1].x / MP.block_width);
    118						if (MP.map[k1][k2] > 0) {
    119							gp.friend[0][i1].x = (k2 + 1) * MP.block_width;
    120							let r = Math.random();
    121							if (k1 == MP.map_row-1 && MP.map[k1-1][k2+1] == 0
    							    || k1 > 0 && k1 < MP.map_row-1 && (MP.map[k1+1][k2+1] > 0
    							    || r > 0.5 && MP.map[k1+1][k2+1] == 0 && MP.map[k1-1][k2+1] == 0))
    122								gp.friend[0][i1].state = -1;   // 上へ
    123							else if (k1 == 0 && MP.map[k1+1][k2+1] == 0
    							    || k1 > 0 && k1 < MP.map_row-1 && (MP.map[k1-1][k2+1] > 0
    							    || r <= 0.5 && MP.map[k1+1][k2+1] == 0 && MP.map[k1-1][k2+1] == 0))
    124								gp.friend[0][i1].state = 1;   // 下へ
    125						}
    126					}
    127				}
    128										// 上へ移動
    129				else if (gp.friend[0][i1].state < 0) {
    130					gp.friend[0][i1].y -= gp.friend[0][i1].v;
    131					let k1 = Math.floor((gp.friend[0][i1].y + MP.block_height) / MP.block_height);
    132					let k2 = Math.floor(gp.friend[0][i1].x / MP.block_width) - 1;
    133					if (MP.map[k1][k2] == 0) {
    134						gp.friend[0][i1].y = k1 * MP.block_height;
    135						gp.friend[0][i1].state = 0;   // 左へ
    136					}
    137					else if (k1 == 0 || MP.map[k1-1][k2+1] > 0)
    138						gp.friend[0][i1].state = 1;   // 下へ
    139				}
    140										// 下へ移動
    141				else {
    142					gp.friend[0][i1].y += gp.friend[0][i1].v;
    143					let k1 = Math.floor(gp.friend[0][i1].y / MP.block_height);
    144					let k2 = Math.floor(gp.friend[0][i1].x / MP.block_width) - 1;
    145					if (k1 >= MP.map_row-1) {
    146						gp.friend[0][i1].y = k1 * MP.block_height;
    147						if (MP.map[k1][k2] == 0)
    148							gp.friend[0][i1].state = 0;   // 左へ
    149						else
    150							gp.friend[0][i1].state = -1;   // 上へ
    151					}
    152					else {
    153						if (MP.map[k1][k2] == 0) {
    154							gp.friend[0][i1].y = k1 * MP.block_height;
    155							gp.friend[0][i1].state = 0;   // 右へ
    156						}
    157						else if (MP.map[k1+1][k2+1] > 0)
    158							gp.friend[0][i1].state = -1;   // 上へ
    159					}
    160				}
    161										// 衝突判定と描画
    162				if (gp.f_state[0][i1] > 0) {
    163					let k1 = Math.floor(gp.friend[0][i1].y / MP.block_height);
    164					let k2 = Math.floor(gp.friend[0][i1].x / MP.block_width);
    165					for (let i2 = 0; i2 < gp.e_state.length; i2++) {
    166						if (gp.e_state[i2] > 0) {
    167							let t1 = Math.floor(gp.enemy[i2].y / MP.block_height);
    168							let t2 = Math.floor(gp.enemy[i2].x / MP.block_width);
    169							if (k1 == t1 && k2 == t2) {
    170								gp.e_state[i2] = -1;
    171								gp.n_e_now_ex--;
    172								if (gp.n_e_now_ex == 0) {
    173									clearInterval(gp.timerID);   // タイマーの停止
    174									gcp_start();   // ゲームクリア
    175								}
    176							}
    177						}
    178					}
    179					mp.ctx.drawImage(gp.friend[0][i1].image, gp.friend[0][i1].x, gp.friend[0][i1].y, MP.block_width, MP.block_height);
    180				}
    181			}
    182		}
    183								// 味方2
    184		for (let i1 = 0; i1 < gp.f_state[1].length; i1++) {
    185			if (gp.f_state[1][i1] > 0) {
    186				let k1 = Math.floor(gp.friend[1][i1].y / MP.block_height);
    187				let k2 = Math.floor(gp.friend[1][i1].x / MP.block_width);
    188				for (let i2 = 0; i2 < gp.e_state.length; i2++) {
    189					if (gp.e_state[i2] > 0) {
    190						let t1 = Math.floor(gp.enemy[i2].y / MP.block_height);
    191						let t2 = Math.floor(gp.enemy[i2].x / MP.block_width);
    192						if (Math.abs(k1-t1) + Math.abs(k2-t2) <= 2) {
    193							gp.e_state[i2] = -1;
    194							gp.n_e_now_ex--;
    195							if (gp.n_e_now_ex == 0) {
    196								clearInterval(gp.timerID);   // タイマーの停止
    197								gcp_start();   // ゲームクリア
    198							}
    199						}
    200					}
    201				}
    202				mp.ctx.drawImage(gp.friend[1][i1].image, gp.friend[1][i1].x, gp.friend[1][i1].y, MP.block_width, MP.block_height);
    203			}
    204		}
    205						// 敵の描画
    206		for (let i1 = 0; i1 < gp.e_state.length; i1++) {
    207			if (gp.e_state[i1] > 0) {
    208				let sw = 0;
    209								// 敵1
    210				if (gp.enemy[i1].type == 0) {
    211										// 右へ移動
    212					if (gp.enemy[i1].state == 0) {
    213						gp.enemy[i1].x += gp.enemy[i1].v;
    214						let k2 = Math.floor((gp.enemy[i1].x + MP.block_width) / MP.block_width);
    215						if (k2 >= MP.map_col)
    216							sw = 1;
    217						else {
    218							let k1 = Math.floor(gp.enemy[i1].y / MP.block_height);
    219							if (MP.map[k1][k2] > 0) {
    220								gp.enemy[i1].x = (k2 - 1) * MP.block_width;
    221								let r = Math.random();
    222								if (k1 == MP.map_row-1 && MP.map[k1-1][k2-1] == 0
    								    || k1 > 0 && k1 < MP.map_row-1 && (MP.map[k1+1][k2-1] > 0
    								    || r > 0.5 && MP.map[k1+1][k2-1] == 0 && MP.map[k1-1][k2-1] == 0))
    223									gp.enemy[i1].state = -1;   // 上へ
    224								else if (k1 == 0 && MP.map[k1+1][k2-1] == 0
    								    || k1 > 0 && k1 < MP.map_row-1 && (MP.map[k1-1][k2-1] > 0
    								    || r <= 0.5 && MP.map[k1+1][k2-1] == 0 && MP.map[k1-1][k2-1] == 0))
    225									gp.enemy[i1].state = 1;   // 下へ
    226							}
    227						}
    228					}
    229										// 上へ移動
    230					else if (gp.enemy[i1].state < 0) {
    231						gp.enemy[i1].y -= gp.enemy[i1].v;
    232						let k1 = Math.floor((gp.enemy[i1].y + MP.block_height) / MP.block_height);
    233						let k2 = Math.floor(gp.enemy[i1].x / MP.block_width) + 1;
    234						if (MP.map[k1][k2] == 0) {
    235							gp.enemy[i1].y = k1 * MP.block_height;
    236							gp.enemy[i1].state = 0;   // 右へ
    237						}
    238						else if (k1 == 0 || MP.map[k1-1][k2-1] > 0)
    239							gp.enemy[i1].state = 1;   // 下へ
    240					}
    241										// 下へ移動
    242					else {
    243						gp.enemy[i1].y += gp.enemy[i1].v;
    244						let k1 = Math.floor(gp.enemy[i1].y / MP.block_height);
    245						let k2 = Math.floor(gp.enemy[i1].x / MP.block_width) + 1;
    246						if (k1 >= MP.map_row-1) {
    247							gp.enemy[i1].y = k1 * MP.block_height;
    248							if (MP.map[k1][k2] == 0)
    249								gp.enemy[i1].state = 0;   // 右へ
    250							else
    251								gp.enemy[i1].state = -1;   // 上へ
    252						}
    253						else {
    254							if (MP.map[k1][k2] == 0) {
    255								gp.enemy[i1].y = k1 * MP.block_height;
    256								gp.enemy[i1].state = 0;   // 右へ
    257							}
    258							else if (MP.map[k1+1][k2-1] > 0)
    259								gp.enemy[i1].state = -1;   // 上へ
    260						}
    261					}
    262				}
    263								// 敵2
    264				else if (gp.enemy[i1].type == 1) {
    265					gp.enemy[i1].x += gp.enemy[i1].v;
    266					let k2 = Math.floor((gp.enemy[i1].x + MP.block_width) / MP.block_width);
    267					if (k2 >= MP.map_col)
    268						sw = 1;
    269				}
    270								// ゲームオーバーか否か
    271				if (sw == 0)
    272					mp.ctx.drawImage(gp.enemy[i1].image, gp.enemy[i1].x, gp.enemy[i1].y, MP.block_width, MP.block_height);
    273				else {
    274					clearInterval(gp.timerID);   // タイマーの停止
    275					gop_start();   // ゲームオーバー
    276				}
    277			}
    278		}
    279						// 次の敵
    280		if (gp.count == gp.next_time) {
    281			gp.n_e_now--;
    282			gp.count            = 0;
    283			gp.e_state[gp.next] = 1;
    284			if (gp.n_e_now > 0) {
    285				gp.next_time = Math.floor(5 * 30 - 30 * Math.random());
    286				gp.next      = -1;
    287				while (gp.next < 0) {
    288					gp.next = Math.floor(gp.e_state.length * Math.random());
    289					if (gp.next >= gp.e_state.length)
    290						gp.next = gp.e_state.length - 1;
    291					if (gp.e_state[gp.next] != 0)
    292						gp.next = -1;
    293				}
    294			}
    295			else
    296				gp.next_time = -1;
    297		}
    298	}
    299				//
    300				// Friend オブジェクト(プロパティ)
    301				//
    302	function Friend(sw)
    303	{
    304		this.image = new Image();
    305		if (sw == 0)
    306			this.image.src = "image/friend1.jpg";
    307		else
    308			this.image.src = "image/friend2.jpg";
    309	
    310		this.state = 0;   // 0:左へ移動,1:下へ移動,-1:上へ移動
    311	
    312		this.x = 0;
    313		this.y = 0;
    314		this.v = 2;   // 移動速度
    315	
    316		return this;
    317	}
    318				//
    319				// Enemy オブジェクト(プロパティ)
    320				//
    321	function Enemy(sw)
    322	{
    323		this.image = new Image();
    324		if (sw == 0)
    325			this.image.src = "image/enemy1.jpg";
    326		else
    327			this.image.src = "image/enemy2.jpg";
    328	
    329		this.type  = sw;   // 敵のタイプ
    330		this.state = 0;   // 0:右へ移動,1:下へ移動,-1:上へ移動
    331	
    332		this.x = 0;
    333		this.y = Math.floor(MP.map_row * Math.random ());
    334		if (this.y >= MP.map_row)
    335			this.y = MP.map_row - 1;
    336		this.y *= MP.block_height;
    337		this.v  = 2;   // 移動速度
    338	
    339		return this;
    340	}
    341				//
    342				// GamePanel オブジェクト(メソッド onMouseDown)
    343				//
    344	GamePanel.prototype.onMouseDown = function(event)
    345	{
    346		let x_base  = mp.canvas.offsetLeft;   // キャンバスの左上のx座標
    347		let y_base  = mp.canvas.offsetTop;   // キャンバスの左上のy座標
    348		let k1      = Math.floor((event.pageY - y_base) / MP.block_height);
    349		let k2      = Math.floor((event.pageX - x_base) / MP.block_width);
    350		if (k1 >= 0 && k1 < MP.map_row && k2 >= 0 && k2 < MP.map_col && MP.map[k1][k2] == 0) {
    351			gp.mark_x = k2 * MP.block_width;
    352			gp.mark_y = k1 * MP.block_height;
    353			gp.mouse  = true;
    354		}
    355	}
    356				//
    357				// GamePanel オブジェクト(メソッド onKeyDown)
    358				//
    359	GamePanel.prototype.onKeyDown = function(event)
    360	{
    361		if(gp.mouse && event.keyCode >= 49 && event.keyCode <= 51) {
    362			if (event.keyCode == 49) {   // キー 1
    363				if (gp.n_friend[0] > 0) {
    364					gp.n_friend[0]--;
    365					gp.f_state[0][gp.n_friend[0]]  = 1;
    366					gp.friend[0][gp.n_friend[0]].x = gp.mark_x;
    367					gp.friend[0][gp.n_friend[0]].y = gp.mark_y;
    368				}
    369			}
    370			else if (event.keyCode == 50) {   // キー 2
    371				if (gp.n_friend[1] > 0) {
    372					gp.n_friend[1]--;
    373					gp.f_state[1][gp.n_friend[1]]  = 1;
    374					gp.friend[1][gp.n_friend[1]].x = gp.mark_x;
    375					gp.friend[1][gp.n_friend[1]].y = gp.mark_y;
    376				}
    377			}
    378			gp.mark_x = 0;
    379			gp.mark_y = 0;
    380			gp.mouse  = false;
    381		}
    382	}
    			
    066 行目( GamePanel 関数)

      存在する敵の数の初期設定です.消滅する毎に 1 ずつ減少し,0 になるとゲームクリアになります.

    163 行目~ 178 行目( draw メソッド)

      画面に表示されている敵に対して,味方1と同じブロックに入った敵を消滅させます.すべての敵を消滅させると,タイマーを停止し,ゲームクリア画面に移動します.

    186 行目~ 201 行目( draw メソッド)

      画面に表示されている敵に対して,味方2との距離(行の差の絶対値と列の差の絶対値の和,Math オブジェクトのメソッド abs の利用)が 2 以下であるブロックに入った敵を消滅させます.すべての敵を消滅させると,タイマーを停止し,ゲームクリア画面に移動します.

    274 行目~ 275 行目( draw メソッド)

      コメントを外し,ゲームオーバーに移行できるようにします.

情報学部 菅沼ホーム JavaScript 目次 索引