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

アクションゲーム(その2)

  ここでは,画面を格子状に区切り,各格子内に小さな画像を配置し,それらの組合せによって背景や障害物を描いています.主人公の状況把握は簡単になりますが,格子の大きさによっては,画像が粗くなってしまいます.背景や障害物を 1 枚の画像で表現する方法に関しては,「アクションゲーム(その1)」を参照して下さい.

  1. ステップ1: ゲームの枠組み

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

    1. HTML ファイル

        「ゲーム枠の作成」における HTML ファイルとほとんど同じですが,「ゲームクリア」ボタンと「ゲームオーバー」ボタンは除いてあります.

      <!DOCTYPE HTML>
      <HTML>
      <HEAD>
      	<TITLE>アクションゲーム:ステップ1</TITLE>
      	<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
      	<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
      	<LINK REL="stylesheet" TYPE="text/css" HREF="../../../master.css">
      	<SCRIPT TYPE="text/javascript" SRC="main/MainPanel.js"></SCRIPT>
      	<SCRIPT TYPE="text/javascript" SRC="start/StartPanel.js"></SCRIPT>
      	<SCRIPT TYPE="text/javascript" SRC="game/GamePanel.js"></SCRIPT>
      	<SCRIPT TYPE="text/javascript" SRC="clear/GameClearPanel.js"></SCRIPT>
      	<SCRIPT TYPE="text/javascript" SRC="over/GameOverPanel.js"></SCRIPT>
      </HEAD>
      <BODY CLASS="eeffee" onLoad="mp_start()">
      	<H1>アクションゲーム:ステップ1</H1>
      	<CANVAS ID="canvas_e" STYLE="background-color: #ffffff;" WIDTH="400" HEIGHT="300"></CANVAS><BR>
      	<A HREF="method.htm" TARGET="method"><BUTTON ID="method" CLASS="std">遊び方</BUTTON></A>
      	<BUTTON ID="start" CLASS="std" onClick="gp_start()">ゲーム開始</BUTTON>
      	<BUTTON ID="first" CLASS="std" onClick="st_start()">最初から再開</BUTTON>
      	<BUTTON ID="finish" CLASS="std" onClick="mp.finish()">ゲーム終了</BUTTON>
      </BODY>
      </HTML>
      				

    2. MainPanel

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

      mp = null;   // MainPanel オブジェクト
      
      			//
      			// MainPanel の開始
      			//
      function mp_start()
      {
      					// キャンバス情報
      	let canvas = document.getElementById('canvas_e');   // キャンバス要素の取得
      	let ctx    = canvas.getContext('2d');   // キャンバスからコンテキストを取得
      					// MainPanel オブジェクト
      	mp = new MainPanel(canvas, ctx);
      					// StartPanel の表示
      	st_start();
      }
      			//
      			// MainPanel オブジェクト(プロパティ)
      			//
      function MainPanel(canvas, ctx)
      {
      	this.canvas = canvas;   // キャンバス要素
      	this.ctx    = ctx;   // キャンバスのコンテキスト
      	this.level  = 1;   // ゲームレベル
      	return this;
      }
      			//
      			// MainPanel オブジェクト(メソッド)
      			//
      MainPanel.prototype.finish = function()
      {
      					// キャンバスのクリア
      	mp.ctx.clearRect(0, 0, mp.canvas.width, mp.canvas.height);
      					// ボタンを非表示
      	document.getElementById('method').style.display = "none";
      	document.getElementById('start').style.display = "none";
      	document.getElementById('first').style.display = "none";
      	document.getElementById('finish').style.display = "none";
      }
      				

    3. StartPanel

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

      			//
      			// StartPanel の開始
      			//
      function st_start()
      {
      	mp.level = 1;   // ゲームレベルの設定
      					// キャンバスのクリア
      	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('start').style.display = "";
      	document.getElementById('first').style.display = "none";
      	document.getElementById('finish').style.display = "none";
      	document.getElementById('start').innerHTML = "ゲーム開始";
      }
      				

    4. GamePanel

        GamePanel は,実際のゲームを実現する部分です.従って,「ゲーム枠の作成」における 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()', 30);
      012						// マウスリスナの追加(マウスボタンが押された時)
      013		mp.canvas.addEventListener("mousedown", gp.onMouseDown);
      014						// ボタンの表示制御
      015		document.getElementById('method').style.display = "none";
      016		document.getElementById('start').style.display = "none";
      017		document.getElementById('first').style.display = "none";
      018		document.getElementById('finish').style.display = "none";
      019	}
      020				//
      021				// GamePanel オブジェクト(プロパティ)
      022				//
      023	function GamePanel()
      024	{
      025		this.timerID = -1;
      026		this.rd = new Road();   // Road オブジェクト
      027		this.hr = new Hero(this.rd);   // Hero オブジェクト
      028		return this;
      029	}
      030				//
      031				// GamePanel オブジェクト(メソッド draw)
      032				//
      033	GamePanel.prototype.draw = function()
      034	{
      035						// キャンバスのクリア
      036		mp.ctx.clearRect(0, 0, mp.canvas.width, mp.canvas.height);
      037						// 移動
      038		gp.rd.x += gp.rd.v_x;
      039		gp.hr.x += gp.hr.v_x;
      040						// 主人公の描画
      041		mp.ctx.drawImage(gp.hr.image, gp.hr.x, gp.hr.y);
      042						// 背景の描画
      043		for (let i1 = 0; i1 < gp.rd.col; i1++) {
      044			let x = gp.rd.x + gp.rd.width * i1;
      045			if (x + gp.rd.width >= 0 && x <= mp.canvas.width) {
      046				for (let i2 = 0; i2 < gp.rd.row; i2++) {
      047					if (gp.rd.blk[i2][i1] > 0) {
      048						let y = i2 * gp.rd.height;
      049						mp.ctx.drawImage(gp.rd.image[gp.rd.blk[i2][i1]-1], x, y);
      050					}
      051				}
      052			}
      053		}
      054	}
      055				//
      056				// GamePanel オブジェクト(メソッド onMouseDown)
      057				//
      058	GamePanel.prototype.onMouseDown = function(event)
      059	{
      060		clearInterval(gp.timerID);   // タイマーの停止
      061		gcp_start();
      062	}
      063				//
      064				// Road オブジェクト(プロパティ)
      065				//
      066	function Road()
      067	{
      068						// レベル1における画像の配置
      069		this.blk1 = new Array();
      070		this.blk1[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);
      071		this.blk1[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);
      072		this.blk1[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);
      073		this.blk1[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);
      074		this.blk1[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);
      075		this.blk1[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);
      076		this.blk1[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);
      077		this.blk1[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);
      078		this.blk1[8] = new Array(1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2);
      079		this.blk1[9] = new Array(1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2);
      080		this.blk1[10] = new Array(1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2);
      081		this.blk1[11] = new Array(1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2);
      082						// レベル2における画像の配置
      083		this.blk2 = new Array();
      084		this.blk2[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);
      085		this.blk2[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);
      086		this.blk2[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);
      087		this.blk2[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);
      088		this.blk2[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);
      089		this.blk2[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);
      090		this.blk2[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);
      091		this.blk2[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);
      092		this.blk2[8] = new Array(1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 2, 2, 2);
      093		this.blk2[9] = new Array(1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 2, 2, 2);
      094		this.blk2[10] = new Array(1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 2, 2, 2);
      095		this.blk2[11] = new Array(1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 2, 2, 2);
      096		this.blk = new Array();   // 背景を構成するブロック
      097		this.image = new Array();   // ブロック画像
      098		this.row = 12;   // ブロックの行数
      099		this.col;   // ブロックの列数
      100		this.r_no = 4;   // 道を構成する縦のブロック数
      101		this.x = 0;   // 背景の位置
      102		this.v_x = -2;   // 背景の水平方向移動速度
      103		this.width = 25;   // ブロックの幅
      104		this.height = 25;   // ブロックの高さ
      105						// ブロック画像の読み込み
      106		this.image[0] = new Image();
      107		this.image[0].src = "image/road1.jpg";
      108		this.image[1] = new Image();
      109		this.image[1].src = "image/road2.jpg";
      110						// レベルによる初期設定
      111		if (mp.level == 1) {
      112			this.col = 26;
      113			this.blk = this.blk1;
      114		}
      115		else {
      116			this.col = 23;
      117			this.blk = this.blk2;
      118		}
      119		return this;
      120	}
      121				//
      122				// Hero オブジェクト(プロパティ)
      123				//
      124	function Hero(rd)
      125	{
      126		this.image = new Image();   // 主人公
      127		this.v_x = 1.0;   // 主人公の水平方向移動速度
      128		this.width = 32;   // 主人公の幅
      129		this.height = 52;   // 主人公の高さ
      130						// 主人公の読み込み
      131		this.image.src = "image/char.jpg";
      132						// 主人公の初期位置
      133		this.x = 0;
      134		this.y = mp.canvas.height - rd.height * rd.r_no - this.height;
      135		return this;
      136	}
      				
      009 行目( gp_start 関数)

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

      013 行目( gp_start 関数)

        キャンバスにマウスが押された時に対応するマウスリスナを追加しています.mousedown を使用していますが,click でも構いません.058 行目~ 062 行目において,その具体的な処理を記述しています.ここでは,ゲームレベルが上がった時の処理を確認したいため,マウスボタンを押すことによって「ゲームクリア」画面に移動するように設定してあります.ただし,実際のゲームにおいては,このような処理を行いません.

      026,027 行目( GamePanel 関数)

        今後,その機能を拡張していく可能性がありますので,背景(道)及び主人公は,別のオブジェクト( 066 行目~ 120 行目,及び,124 行目~ 136 行目)として定義してあります.rd,hr は,それらのオブジェクトを記憶するための変数です.

      033 行目~ 054 行目( draw メソッド)

        011 行目で設定したタイマーに従って,30 ms 毎に実行される GamePanel オブジェクトのメソッド draw の定義です.draw では,領域をクリアした後( 36 行目),道及び主人公を移動させ( 38,39 行目),それらを描画しています(主人公:41 行目,背景:43 行目~ 53 行目).後に説明しますように,画面全体を格子状に区切り,各格子内(ブロック)に指定した画像を描くことによって背景を構成しています.ここでは,その指定された画像を描いています.

      069 行目~ 118 行目( Road 関数)

        画面全体を row 行 col 列の格子状に区切り,各格子内(ブロック)に画像を配置することによって背景画像を構成します.各ブロックの大きさは,幅 width = 25 ピクセル,高さ height = 25 ピクセルです.変数 blk1 及び blk2は,レベル 1 及び 2 における各ブロックの状態を表すための 2 次元配列です.2 次元配列は,まず配列を定義し( 069,083 行目),その配列の各要素を再び配列として定義する( 070 行目~ 081 行目,084 行目~ 095 行目)ことによって可能です.配列における各要素の値が 0 の場合は何も描かれず,そうでない場合は指定された画像が描かれます.

        一般に,配列の各要素を配列として定義することによって,多次元配列を定義することが可能です.以下に示すのは 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);					
        配列の項で説明していますように,配列変数 blk1,blk2,blk などは,データを記憶している領域の先頭を指すポインタとみなすことができます.例えば,113 行目において blk1 を blk に代入していますが,blk1 の全てのデータをコピーして blk に代入しているわけではなく,blk1 と blk が同じデータ領域を指すことになるだけです.従って,blk を介して各要素の値を変更すれば,blk1 の対応する要素の値も変化します(逆も同様).

      124 行目~ 136 行目( Hero 関数)

        Hero オブジェクトのプロパティを設定しています.

    5. GameClearPanel

        このプログラムに関しても,「ゲーム枠の作成」における GameClearPanel とほとんど同じです.違いは,ボタンの制御部分と,レベルが 2 までしか無い点だけです.

      			//
      			// 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";
      	if (mp.level > 1) {   // 最初からゲーム再開
      		document.getElementById('start').style.display = "none";
      		document.getElementById('first').style.display = "";
      	}
      	else {   // レベルアップ
      		mp.level++;
      		document.getElementById('start').style.display = "";
      		document.getElementById('first').style.display = "none";
      		document.getElementById('start').innerHTML = "次のレベル";
      	}
      	document.getElementById('finish').style.display = "";
      }
      				

    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('start').style.display = "";
      	document.getElementById('first').style.display = "";
      	document.getElementById('finish').style.display = "";
      	document.getElementById('start').innerHTML = "現レベルで再開";
      }
      				

  2. ステップ2: ゲームオーバー

      背景画像(道)において,道のない部分(谷)に主人公が移動したときゲームオーバーになるように,プログラムを修正します.修正するプログラムは,GamePanel の Road 関数と GamePanel オブジェクトの draw メソッドです.まず,Road 関数の変更部分から順に説明していきます.

    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()', 30);
    012						// マウスリスナの追加(マウスボタンが押された時)
    013		mp.canvas.addEventListener("mousedown", gp.onMouseDown);
    014						// ボタンの表示制御
    015		document.getElementById('method').style.display = "none";
    016		document.getElementById('start').style.display = "none";
    017		document.getElementById('first').style.display = "none";
    018		document.getElementById('finish').style.display = "none";
    019	}
    020				//
    021				// GamePanel オブジェクト(プロパティ)
    022				//
    023	function GamePanel()
    024	{
    025		this.timerID = -1;
    026		this.rd = new Road();   // Road オブジェクト
    027		this.hr = new Hero(this.rd);   // Hero オブジェクト
    028		return this;
    029	}
    030				//
    031				// GamePanel オブジェクト(メソッド draw)
    032				//
    033	GamePanel.prototype.draw = function()
    034	{
    035						// キャンバスのクリア
    036		mp.ctx.clearRect(0, 0, mp.canvas.width, mp.canvas.height);
    037						// 移動
    038		gp.rd.x += gp.rd.v_x;
    039		gp.hr.x += gp.hr.v_x;
    040						// 主人公の描画
    041		mp.ctx.drawImage(gp.hr.image, gp.hr.x, gp.hr.y);
    042						// 背景の描画
    043		for (let i1 = 0; i1 < gp.rd.col; i1++) {
    044			let x = gp.rd.x + gp.rd.width * i1;
    045			if (x + gp.rd.width >= 0 && x <= mp.canvas.width) {
    046				for (let i2 = 0; i2 < gp.rd.row; i2++) {
    047					if (gp.rd.blk[i2][i1] > 0) {
    048						let y = i2 * gp.rd.height;
    049						mp.ctx.drawImage(gp.rd.image[gp.rd.blk[i2][i1]-1], x, y);
    050					}
    051				}
    052			}
    053		}
    054						// 道の状態のチェック
    055		let x = Math.floor((gp.hr.x - gp.rd.x + Math.floor(gp.hr.width / 2)) / gp.rd.width);
    056		let y = Math.floor((gp.hr.y + gp.hr.height + Math.floor(gp.rd.height / 2)) / gp.rd.height);
    057		if (x >= gp.rd.col || gp.rd.blk[y][x] == 0) {
    058			clearInterval(gp.timerID);   // タイマーの停止
    059			gop_start();   // ゲームオーバー
    060		}
    061		else if (gp.rd.blk[y][x] == 2) {
    062			clearInterval(gp.timerID);   // タイマーの停止
    063			gcp_start();   // ゲームクリア
    064		}
    065	}
    066				//
    067				// GamePanel オブジェクト(メソッド onMouseDown)
    068				//
    069	GamePanel.prototype.onMouseDown = function(event)
    070	{
    071		clearInterval(gp.timerID);   // タイマーの停止
    072		gcp_start();
    073	}
    074				//
    075				// Road オブジェクト(プロパティ)
    076				//
    077	function Road()
    078	{
    079						// レベル1における画像の配置
    080		this.blk1 = new Array();
    081		this.blk1[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);
    082		this.blk1[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);
    083		this.blk1[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);
    084		this.blk1[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);
    085		this.blk1[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);
    086		this.blk1[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);
    087		this.blk1[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);
    088		this.blk1[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);
    089		this.blk1[8] = new Array(1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2);
    090		this.blk1[9] = new Array(1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2);
    091		this.blk1[10] = new Array(1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2);
    092		this.blk1[11] = new Array(1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2);
    093						// レベル2における画像の配置
    094		this.blk2 = new Array();
    095		this.blk2[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);
    096		this.blk2[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);
    097		this.blk2[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);
    098		this.blk2[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);
    099		this.blk2[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);
    100		this.blk2[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);
    101		this.blk2[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);
    102		this.blk2[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);
    103		this.blk2[8] = new Array(1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 2, 2, 2);
    104		this.blk2[9] = new Array(1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 2, 2, 2);
    105		this.blk2[10] = new Array(1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 2, 2, 2);
    106		this.blk2[11] = new Array(1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 2, 2, 2);
    107		this.blk = new Array();   // 背景を構成するブロック
    108		this.image = new Array();   // ブロック画像
    109		this.row = 12;   // ブロックの行数
    110		this.col;   // ブロックの列数
    111		this.r_no = 4;   // 道を構成する縦のブロック数
    112		this.x = 0;   // 背景の位置
    113		this.v_x = -2;   // 背景の水平方向移動速度
    114		this.width = 25;   // ブロックの幅
    115		this.height = 25;   // ブロックの高さ
    116						// ブロック画像の読み込み
    117		this.image[0] = new Image();
    118		this.image[0].src = "image/road1.jpg";
    119		this.image[1] = new Image();
    120		this.image[1].src = "image/road2.jpg";
    121						// レベルによる初期設定
    122		if (mp.level == 1) {
    123			this.col = 26;
    124			this.blk = this.blk1;
    125		}
    126		else {
    127			this.col = 23;
    128			this.blk = this.blk2;
    129		}
    130		return this;
    131	}
    132				//
    133				// Hero オブジェクト(プロパティ)
    134				//
    135	function Hero(rd)
    136	{
    137		this.image = new Image();   // 主人公
    138		this.v_x = 1.0;   // 主人公の水平方向移動速度
    139		this.width = 32;   // 主人公の幅
    140		this.height = 52;   // 主人公の高さ
    141						// 主人公の読み込み
    142		this.image.src = "image/char.jpg";
    143						// 主人公の初期位置
    144		this.x = 0;
    145		this.y = mp.canvas.height - rd.height * rd.r_no - this.height;
    146		return this;
    147	}
    			
    055,056 行目

      主人公の足下が配列 blk のどの位置,つまり,どのブロックにあるかを計算しています.変数 x,y は,配列 blk の添え字となりますので,整数である必要があります.しかし,代入演算子の右側で計算された値は必ずしも整数とはなりません.そこで,Math オブジェクトのメソッド floor を使用して,小数点以下を切り捨てています.

    057 行目~ 060 行目

      格子の外側,または,谷(何も描いてないブロック)である場合は,タイマーを止め,ゲームオーバーにしています,

    061 行目~ 064 行目

      ゴールにいる場合(現時点ではあり得ませんが)は,ゲームクリアにしています.

  3. ステップ3: ジャンプ

      主人公がジャンプできるようにプログラムを修正します.修正するプログラムは,GamePanel の Hero 関数,draw メソッド( GamePanel オブジェクトのメソッド),及び,gp_start 関数です.まず,Hero 関数の変更部分から順に説明していきます.

    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()', 30);
    012						// マウスリスナの追加(マウスボタンが押された時と離された時)
    013		mp.canvas.addEventListener("mousedown", gp.onMouseDown);
    014		mp.canvas.addEventListener("touchstart", gp.onMouseDown);
    015		mp.canvas.addEventListener("touchmove", gp.onMouseDown);
    016		mp.canvas.addEventListener("mouseup", gp.onMouseUp);
    017						// ボタンの表示制御
    018		document.getElementById('method').style.display = "none";
    019		document.getElementById('start').style.display = "none";
    020		document.getElementById('first').style.display = "none";
    021		document.getElementById('finish').style.display = "none";
    022	}
    023				//
    024				// GamePanel オブジェクト(プロパティ)
    025				//
    026	function GamePanel()
    027	{
    028		this.timerID = -1;
    029		this.rd = new Road();   // Road オブジェクト
    030		this.hr = new Hero(this.rd);   // Hero オブジェクト
    031		return this;
    032	}
    033				//
    034				// GamePanel オブジェクト(メソッド draw)
    035				//
    036	GamePanel.prototype.draw = function()
    037	{
    038						// キャンバスのクリア
    039		mp.ctx.clearRect(0, 0, mp.canvas.width, mp.canvas.height);
    040						// 移動
    041		gp.rd.x += gp.rd.v_x;
    042		gp.hr.v_y += (gp.hr.up - gp.hr.down);
    043		gp.hr.x += gp.hr.v_x;
    044		gp.hr.y -= gp.hr.v_y;
    045						// 主人公の描画
    046		mp.ctx.drawImage(gp.hr.image, gp.hr.x, gp.hr.y);
    047						// 背景の描画
    048		for (let i1 = 0; i1 < gp.rd.col; i1++) {
    049			let x = gp.rd.x + gp.rd.width * i1;
    050			if (x + gp.rd.width >= 0 && x <= mp.canvas.width) {
    051				for (let i2 = 0; i2 < gp.rd.row; i2++) {
    052					if (gp.rd.blk[i2][i1] > 0) {
    053						let y = i2 * gp.rd.height;
    054						mp.ctx.drawImage(gp.rd.image[gp.rd.blk[i2][i1]-1], x, y);
    055					}
    056				}
    057			}
    058		}
    059						// 道の状態のチェック
    060	/*
    061		let x = Math.floor((gp.hr.x - gp.rd.x + Math.floor(gp.hr.width / 2)) / gp.rd.width);
    062		let y = Math.floor((gp.hr.y + gp.hr.height + Math.floor(gp.rd.height / 2)) / gp.rd.height);
    063		if (x >= gp.rd.col || gp.rd.blk[y][x] == 0) {
    064			clearInterval(gp.timerID);   // タイマーの停止
    065			gop_start();   // ゲームオーバー
    066		}
    067		else if (gp.rd.blk[y][x] == 2) {
    068			clearInterval(gp.timerID);   // タイマーの停止
    069			gcp_start();   // ゲームクリア
    070		}
    071	*/
    072	}
    073				//
    074				// GamePanel オブジェクト(メソッド onMouseDown)
    075				//
    076	GamePanel.prototype.onMouseDown = function(event)
    077	{
    078		if (!gp.hr.jump) {
    079			gp.hr.up   = 1.0;
    080			gp.hr.down = 0.5;
    081			gp.hr.v_x  = 2.0;
    082			gp.hr.jump = true;
    083			gp.hr.y--;   // 着地判定のため,1 ピクセルだけジャンプさせておく
    084		}
    085	}
    086				//
    087				// GamePanel オブジェクト(メソッド onMouseUp)
    088				//
    089	GamePanel.prototype.onMouseUp = function(event)
    090	{
    091		gp.hr.up   = 0.0;
    092		gp.hr.down = 0.5;
    093	}
    094				//
    095				// Road オブジェクト(プロパティ)
    096				//
    097	function Road()
    098	{
    099						// レベル1における画像の配置
    100		this.blk1 = new Array();
    101		this.blk1[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);
    102		this.blk1[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);
    103		this.blk1[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);
    104		this.blk1[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);
    105		this.blk1[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);
    106		this.blk1[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);
    107		this.blk1[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);
    108		this.blk1[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);
    109		this.blk1[8] = new Array(1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2);
    110		this.blk1[9] = new Array(1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2);
    111		this.blk1[10] = new Array(1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2);
    112		this.blk1[11] = new Array(1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2);
    113						// レベル2における画像の配置
    114		this.blk2 = new Array();
    115		this.blk2[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);
    116		this.blk2[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);
    117		this.blk2[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);
    118		this.blk2[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);
    119		this.blk2[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);
    120		this.blk2[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);
    121		this.blk2[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);
    122		this.blk2[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);
    123		this.blk2[8] = new Array(1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 2, 2, 2);
    124		this.blk2[9] = new Array(1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 2, 2, 2);
    125		this.blk2[10] = new Array(1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 2, 2, 2);
    126		this.blk2[11] = new Array(1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 2, 2, 2);
    127		this.blk = new Array();   // 背景を構成するブロック
    128		this.image = new Array();   // ブロック画像
    129		this.row = 12;   // ブロックの行数
    130		this.col;   // ブロックの列数
    131		this.r_no = 4;   // 道を構成する縦のブロック数
    132		this.x = 0;   // 背景の位置
    133		this.v_x = -2;   // 背景の水平方向移動速度
    134		this.width = 25;   // ブロックの幅
    135		this.height = 25;   // ブロックの高さ
    136						// ブロック画像の読み込み
    137		this.image[0] = new Image();
    138		this.image[0].src = "image/road1.jpg";
    139		this.image[1] = new Image();
    140		this.image[1].src = "image/road2.jpg";
    141						// レベルによる初期設定
    142		if (mp.level == 1) {
    143			this.col = 26;
    144			this.blk = this.blk1;
    145		}
    146		else {
    147			this.col = 23;
    148			this.blk = this.blk2;
    149		}
    150		return this;
    152	}
    152				//
    153				// Hero オブジェクト(プロパティ)
    154				//
    155	function Hero(rd)
    156	{
    157		this.image = new Image();   // 主人公
    158		this.v_y = 0.0;   // 主人公の垂直方向移動速度
    159		this.v_x = 1.0;   // 主人公の水平方向移動速度
    160		this.up = 0.0;   // 主人公の上向き加速度
    161		this.down = 0;   // 主人公の下向き加速度
    162		this.jump = false;   // 主人公がジャンプ中か?
    163		this.width = 32;   // 主人公の幅
    164		this.height = 52;   // 主人公の高さ
    165						// 主人公の読み込み
    166		this.image.src = "image/char.jpg";
    167						// 主人公の初期位置
    168		this.x = 0;
    169		this.y = mp.canvas.height - rd.height * rd.r_no - this.height;
    170		return this;
    171	}
    			
    158 行目( Hero 関数)

      主人公の垂直方向の移動速度を保存するためのプロパティを定義しています.

    160,161 行目( Hero 関数)

      主人公に対する上向きの加速度と下向きの加速度です.

    162 行目( Hero 関数)

      ジャンプ中に,さらにジャンプすることを防ぐためのプロパティです.

    042,044 行目( draw メソッド)

      設定された加速度から,現在の速度を計算しています.一般に,現在の速度を v / t,加速度を a / t2 とすると,t 時間後の速度は v + at となります.この速度を使用して,044 行目において,主人公の垂直位置を計算しています.いずれの式においても,t = 1 とみなしています.

    061 行目~ 070 行目( draw メソッド)

      この部分をそのまま残しておくと,横方向の座標が谷の部分になるとゲームオーバーになってしまうため,一時的にコメントアウトしています.

    014 行目~ 016 行目( gp_start 関数)

      マウスボタンを離した時に対応するマウスリスナを追加しています( 016 行目).イベントに対する処理は,GamePanel オブジェクトの onMouseUp メソッド( 089 行目~ 093 行目)で実行されます.なお,マウスボタンを押したときの処理は,ステップ1において暫定的に利用していましたが,その内容( 078 行目~ 084 行目)も修正してやる必要があります.なお,014,015 行目は,スマホ等に対応するための記述です.

    078 行目~ 084 行目( onMouseDown メソッド)

      マウスボタンが押された時の処理であり,Hero オブジェクトのプロパティを設定します.マウスボタンを押すと,垂直方向の加速度が設定されます( 079,080 行目).また,水平方向の速度も変化させています( 081 行目).この結果,主人公は,垂直方向は上方向に速度を増しながら,水平方向は一定速度で移動します.また,プロパティ jump を true に設定し,ジャンプ中であることを設定します.なお,後ほど行う処理ですが,着地した場合はこの値を再び false にします.

    089 行目~ 093 行目( onMouseUp 関数)

      マウスボタンが離された時の処理であり,Hero オブジェクトのプロパティを設定します.マウスボタンを離すと,上向きの加速度が 0 に設定されます( 091 行目).この結果,最終的に,主人公は,下方向に速度を増しながら落下することになります.

  4. ステップ4: 完成

      ジャンプした後,着地,ゲームクリア,ゲームオーバーなのど判定を行い,ゲームを完成します.修正するプログラムは,GamePanel の draw メソッド( GamePanel オブジェクトのメソッド)だけです.ステップ3においてコメントとした部分の追加・修正です.

    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()', 30);
    012						// マウスリスナの追加(マウスボタンが押された時と離された時)
    013		mp.canvas.addEventListener("mousedown", gp.onMouseDown);
    014		mp.canvas.addEventListener("touchstart", gp.onMouseDown);
    015		mp.canvas.addEventListener("touchmove", gp.onMouseDown);
    016		mp.canvas.addEventListener("mouseup", gp.onMouseUp);
    017						// ボタンの表示制御
    018		document.getElementById('method').style.display = "none";
    019		document.getElementById('start').style.display = "none";
    020		document.getElementById('first').style.display = "none";
    021		document.getElementById('finish').style.display = "none";
    022	}
    023				//
    024				// GamePanel オブジェクト(プロパティ)
    025				//
    026	function GamePanel()
    027	{
    028		this.timerID = -1;
    029		this.rd = new Road();   // Road オブジェクト
    030		this.hr = new Hero(this.rd);   // Hero オブジェクト
    031		return this;
    032	}
    033				//
    034				// GamePanel オブジェクト(メソッド draw)
    035				//
    036	GamePanel.prototype.draw = function()
    037	{
    038						// キャンバスのクリア
    039		mp.ctx.clearRect(0, 0, mp.canvas.width, mp.canvas.height);
    040						// 移動
    041		gp.rd.x += gp.rd.v_x;
    042		gp.hr.v_y += (gp.hr.up - gp.hr.down);
    043		gp.hr.x += gp.hr.v_x;
    044		gp.hr.y -= gp.hr.v_y;
    045						// 主人公の描画
    046		mp.ctx.drawImage(gp.hr.image, gp.hr.x, gp.hr.y);
    047						// 背景の描画
    048		for (let i1 = 0; i1 < gp.rd.col; i1++) {
    049			let x = gp.rd.x + gp.rd.width * i1;
    050			if (x + gp.rd.width >= 0 && x <= mp.canvas.width) {
    051				for (let i2 = 0; i2 < gp.rd.row; i2++) {
    052					if (gp.rd.blk[i2][i1] > 0) {
    053						let y = i2 * gp.rd.height;
    054						mp.ctx.drawImage(gp.rd.image[gp.rd.blk[i2][i1]-1], x, y);
    055					}
    056				}
    057			}
    058		}
    059						// 道の状態のチェック
    060		let x = Math.floor((gp.hr.x - gp.rd.x + Math.floor(gp.hr.width / 2)) / gp.rd.width);
    061								// ジャンプ中
    062		if (gp.hr.jump) {
    063			if (x >= gp.rd.col) {
    064				clearInterval(gp.timerID);   // タイマーの停止
    065				gop_start();   // ゲームオーバー
    066			}
    067			else {
    068				let y = Math.floor((gp.hr.y + gp.hr.height) / gp.rd.height);
    069				if (y >= 0) {
    070					if (y < gp.rd.row && gp.rd.blk[y][x] > 0) {
    071						gp.hr.jump = false;
    072						gp.hr.down = 0.0;
    073						gp.hr.v_x  = 1.0;
    074						gp.hr.v_y  = 0.0;
    075						gp.hr.y    = mp.canvas.height - gp.rd.height * gp.rd.r_no - gp.hr.height;
    076						if (gp.rd.blk[y][x] == 2) {
    077							clearInterval(gp.timerID);   // タイマーの停止
    078							gcp_start();   // ゲームクリア
    079						}
    080					}
    081					else if (y >= gp.rd.row - gp.rd.r_no) {
    082						clearInterval(gp.timerID);   // タイマーの停止
    083						gop_start();   // ゲームオーバー
    084					}
    085				}
    086			}
    087		}
    088								// ジャンプ中でない
    089		else {
    090			let y = Math.floor((gp.hr.y + gp.hr.height + Math.floor(gp.rd.height / 2)) / gp.rd.height);
    091			if (x >= gp.rd.col || gp.rd.blk[y][x] == 0) {
    092				clearInterval(gp.timerID);   // タイマーの停止
    093				gop_start();   // ゲームオーバー
    094			}
    095			else if (gp.rd.blk[y][x] == 2) {
    096				clearInterval(gp.timerID);   // タイマーの停止
    097				gcp_start();   // ゲームクリア
    098			}
    099		}
    100	}
    101				//
    102				// GamePanel オブジェクト(メソッド onMouseDown)
    103				//
    104	GamePanel.prototype.onMouseDown = function(event)
    105	{
    106		if (!gp.hr.jump) {
    107			gp.hr.up   = 1.0;
    108			gp.hr.down = 0.5;
    109			gp.hr.v_x  = 2.0;
    110			gp.hr.jump = true;
    111			gp.hr.y--;   // 着地判定のため,1 ピクセルだけジャンプさせておく
    112		}
    113	}
    114				//
    115				// GamePanel オブジェクト(メソッド onMouseUp)
    116				//
    117	GamePanel.prototype.onMouseUp = function(event)
    118	{
    119		gp.hr.up   = 0.0;
    120		gp.hr.down = 0.5;
    121	}
    122				//
    123				// Road オブジェクト(プロパティ)
    124				//
    125	function Road()
    126	{
    127						// レベル1における画像の配置
    128		this.blk1 = new Array();
    129		this.blk1[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);
    130		this.blk1[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);
    131		this.blk1[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);
    132		this.blk1[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);
    133		this.blk1[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);
    134		this.blk1[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);
    135		this.blk1[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);
    136		this.blk1[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);
    137		this.blk1[8] = new Array(1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2);
    138		this.blk1[9] = new Array(1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2);
    139		this.blk1[10] = new Array(1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2);
    140		this.blk1[11] = new Array(1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2);
    141						// レベル2における画像の配置
    142		this.blk2 = new Array();
    143		this.blk2[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);
    144		this.blk2[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);
    145		this.blk2[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);
    146		this.blk2[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);
    147		this.blk2[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);
    148		this.blk2[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);
    149		this.blk2[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);
    150		this.blk2[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);
    151		this.blk2[8] = new Array(1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 2, 2, 2);
    152		this.blk2[9] = new Array(1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 2, 2, 2);
    153		this.blk2[10] = new Array(1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 2, 2, 2);
    154		this.blk2[11] = new Array(1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 2, 2, 2);
    155		this.blk = new Array();   // 背景を構成するブロック
    156		this.image = new Array();   // ブロック画像
    157		this.row = 12;   // ブロックの行数
    158		this.col;   // ブロックの列数
    159		this.r_no = 4;   // 道を構成する縦のブロック数
    160		this.x = 0;   // 背景の位置
    161		this.v_x = -2;   // 背景の水平方向移動速度
    162		this.width = 25;   // ブロックの幅
    163		this.height = 25;   // ブロックの高さ
    164						// ブロック画像の読み込み
    165		this.image[0] = new Image();
    166		this.image[0].src = "image/road1.jpg";
    167		this.image[1] = new Image();
    168		this.image[1].src = "image/road2.jpg";
    169						// レベルによる初期設定
    170		if (mp.level == 1) {
    171			this.col = 26;
    172			this.blk = this.blk1;
    173		}
    174		else {
    175			this.col = 23;
    176			this.blk = this.blk2;
    177		}
    178		return this;
    179	}
    180				//
    181				// Hero オブジェクト(プロパティ)
    182				//
    183	function Hero(rd)
    184	{
    185		this.image = new Image();   // 主人公
    186		this.v_y = 0.0;   // 主人公の垂直方向移動速度
    187		this.v_x = 1.0;   // 主人公の水平方向移動速度
    188		this.up = 0.0;   // 主人公の上向き加速度
    189		this.down = 0;   // 主人公の下向き加速度
    190		this.jump = false;   // 主人公がジャンプ中か?
    191		this.width = 32;   // 主人公の幅
    192		this.height = 52;   // 主人公の高さ
    193						// 主人公の読み込み
    194		this.image.src = "image/char.jpg";
    195						// 主人公の初期位置
    196		this.x = 0;
    197		this.y = mp.canvas.height - rd.height * rd.r_no - this.height;
    198		return this;
    199	}
    			
    060 行目

      主人公の足下が配列 blk のどの位置(何列目)にあるかを計算しています.縦方向の位置(何行目)は,ジャンプしている場合( 062 行目~ 087 行目 )とそうでない場合( 089 行目~ 099 行目 )によって,対応する処理が異なります.なお,ジャンプしていない場合は,今まで行ってきた処理と同じです.

    063 行目~ 066 行目

      横方向が,格子の外側に出た場合は,タイマーを止め,ゲームオーバー状態にします.

    068 行目

      主人公の足下が配列 blk のどの位置(何行目)にあるかを計算しています.0 より小さい場合(画面の上側の外に出ている)は何もしません( 069 行目に対応する else 文はない).

    070 行目~ 080 行目

      主人公がジャンプ中であり,足下が地面(何かが描かれたブロック)であった場合の処理です.ジャンプを止め,足下の座標を地面になるように調整しています.また,地面がゴールであった場合は,タイマーを止め,ゲームクリア状態にします.

    081 行目~ 084 行目

      主人公がジャンプ中であり,足下が谷(何も描かれていないブロック)であった場合の処理です.タイマーを止め,ゲームオーバー状態にします.

  5. ステップ4: 完成( BGM 付き)

      参考のため,BGM を付加した例を示しておきます.追加・修正した部分は,以下の通りです.なお,BGM は,平成 25 年度に本学を卒業した斉藤亮太さんに作成してもらいました.

    • HTML ファイル: 20 行目
    • GamePanel: 9 ~ 11 行目,68 ~ 69 行目,83 ~ 84 行目,90 ~ 91 行目,102 ~ 103 行目,108 ~ 109 行目

    01	<!DOCTYPE HTML>
    02	<HTML>
    03	<HEAD>
    04		<TITLE>アクションゲーム:BGM 付き(完成)</TITLE>
    05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
    06		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../master.css">
    07		<SCRIPT TYPE="text/javascript" SRC="main/MainPanel.js"></SCRIPT>
    08		<SCRIPT TYPE="text/javascript" SRC="start/StartPanel.js"></SCRIPT>
    09		<SCRIPT TYPE="text/javascript" SRC="game/GamePanel.js"></SCRIPT>
    10		<SCRIPT TYPE="text/javascript" SRC="clear/GameClearPanel.js"></SCRIPT>
    11		<SCRIPT TYPE="text/javascript" SRC="over/GameOverPanel.js"></SCRIPT>
    12	</HEAD>
    13	<BODY CLASS="eeffee" onLoad="mp_start()">
    14		<H1>アクションゲーム:BGM 付き(完成)</H1>
    15		<CANVAS ID="canvas_e" STYLE="background-color: #ffffff;" WIDTH="400" HEIGHT="300"></CANVAS><BR>
    16		<A HREF="method.htm" TARGET="method"><BUTTON ID="method" CLASS="std">遊び方</BUTTON></A>
    17		<BUTTON ID="start" CLASS="std" onClick="gp_start()">ゲーム開始</BUTTON>
    18		<BUTTON ID="first" CLASS="std" onClick="st_start()">最初から再開</BUTTON>
    19		<BUTTON ID="finish" CLASS="std" onClick="mp.finish()">ゲーム終了</BUTTON>
    20		<AUDIO ID="BGM" LOOP SRC="Action_BGM.mp3"></AUDIO>  <!-- BGMのために追加 -->
    21	</BODY>
    22	</HTML>
    			
    001	gp = null;   // GamePanel オブジェクト
    002	
    003				//
    004				// GamePanel の開始
    005				//
    006	function gp_start()
    007	{
    008						// BGM の再生
    009		document.getElementById('BGM').volume = 0.5;
    010		document.getElementById('BGM').play();
    011		document.getElementById('BGM').currentTime = 0.5;   // 約0.5秒の空白をスキップ
    012						// GamePanel オブジェクト
    013		gp = new GamePanel();
    014						// タイマーのスタート
    015		gp.timerID = setInterval('gp.draw()', 30);
    016						// マウスリスナの追加(マウスボタンが押された時と離された時)
    017		mp.canvas.addEventListener("mousedown", gp.onMouseDown);
    018		mp.canvas.addEventListener("touchstart", gp.onMouseDown);
    019		mp.canvas.addEventListener("touchmove", gp.onMouseDown);
    020		mp.canvas.addEventListener("mouseup", gp.onMouseUp);
    021						// ボタンの表示制御
    022		document.getElementById('method').style.display = "none";
    023		document.getElementById('start').style.display = "none";
    024		document.getElementById('first').style.display = "none";
    025		document.getElementById('finish').style.display = "none";
    026	}
    027				//
    028				// GamePanel オブジェクト(プロパティ)
    029				//
    030	function GamePanel()
    031	{
    032		this.timerID = -1;
    033		this.rd = new Road();   // Road オブジェクト
    034		this.hr = new Hero(this.rd);   // Hero オブジェクト
    035		return this;
    036	}
    037				//
    038				// GamePanel オブジェクト(メソッド draw)
    039				//
    040	GamePanel.prototype.draw = function()
    041	{
    042						// キャンバスのクリア
    043		mp.ctx.clearRect(0, 0, mp.canvas.width, mp.canvas.height);
    044						// 移動
    045		gp.rd.x += gp.rd.v_x;
    046		gp.hr.v_y += (gp.hr.up - gp.hr.down);
    047		gp.hr.x += gp.hr.v_x;
    048		gp.hr.y -= gp.hr.v_y;
    049						// 主人公の描画
    050		mp.ctx.drawImage(gp.hr.image, gp.hr.x, gp.hr.y);
    051						// 背景の描画
    052		for (let i1 = 0; i1 < gp.rd.col; i1++) {
    053			let x = gp.rd.x + gp.rd.width * i1;
    054			if (x + gp.rd.width >= 0 && x <= mp.canvas.width) {
    055				for (let i2 = 0; i2 < gp.rd.row; i2++) {
    056					if (gp.rd.blk[i2][i1] > 0) {
    057						let y = i2 * gp.rd.height;
    058						mp.ctx.drawImage(gp.rd.image[gp.rd.blk[i2][i1]-1], x, y);
    059					}
    060				}
    061			}
    062		}
    063						// 道の状態のチェック
    064		let x = Math.floor((gp.hr.x - gp.rd.x + Math.floor(gp.hr.width / 2)) / gp.rd.width);
    065								// ジャンプ中
    066		if (gp.hr.jump) {
    067			if (x >= gp.rd.col) {
    068				document.getElementById('BGM').pause();   // BGMのために追加
    069				document.getElementById('BGM').load();   // BGMのために追加
    070				clearInterval(gp.timerID);   // タイマーの停止
    071				gop_start();   // ゲームオーバー
    072			}
    073			else {
    074				let y = Math.floor((gp.hr.y + gp.hr.height) / gp.rd.height);
    075				if (y >= 0) {
    076					if (y < gp.rd.row && gp.rd.blk[y][x] > 0) {
    077						gp.hr.jump = false;
    078						gp.hr.down = 0.0;
    079						gp.hr.v_x  = 1.0;
    080						gp.hr.v_y  = 0.0;
    081						gp.hr.y    = mp.canvas.height - gp.rd.height * gp.rd.r_no - gp.hr.height;
    082						if (gp.rd.blk[y][x] == 2) {
    083							document.getElementById('BGM').pause();   // BGMのために追加
    084							document.getElementById('BGM').load();   // BGMのために追加
    085							clearInterval(gp.timerID);   // タイマーの停止
    086							gcp_start();   // ゲームクリア
    087						}
    088					}
    089					else if (y >= gp.rd.row - gp.rd.r_no) {
    090						document.getElementById('BGM').pause();   // BGMのために追加
    091						document.getElementById('BGM').load();   // BGMのために追加
    092						clearInterval(gp.timerID);   // タイマーの停止
    093						gop_start();   // ゲームオーバー
    094					}
    095				}
    096			}
    097		}
    098								// ジャンプ中でない
    099		else {
    100			let y = Math.floor((gp.hr.y + gp.hr.height + Math.floor(gp.rd.height / 2)) / gp.rd.height);
    101			if (x >= gp.rd.col || gp.rd.blk[y][x] == 0) {
    102				document.getElementById('BGM').pause();   // BGMのために追加
    103				document.getElementById('BGM').load();   // BGMのために追加
    104				clearInterval(gp.timerID);   // タイマーの停止
    105				gop_start();   // ゲームオーバー
    106			}
    107			else if (gp.rd.blk[y][x] == 2) {
    108				document.getElementById('BGM').pause();   // BGMのために追加
    109				document.getElementById('BGM').load();   // BGMのために追加
    110				clearInterval(gp.timerID);   // タイマーの停止
    111				gcp_start();   // ゲームクリア
    112			}
    113		}
    114	}
    115				//
    116				// GamePanel オブジェクト(メソッド onMouseDown)
    117				//
    118	GamePanel.prototype.onMouseDown = function(event)
    119	{
    120		if (!gp.hr.jump) {
    121			gp.hr.up   = 1.0;
    122			gp.hr.down = 0.5;
    123			gp.hr.v_x  = 2.0;
    124			gp.hr.jump = true;
    125			gp.hr.y--;   // 着地判定のため,1 ピクセルだけジャンプさせておく
    126		}
    127	}
    128				//
    129				// GamePanel オブジェクト(メソッド onMouseUp)
    130				//
    131	GamePanel.prototype.onMouseUp = function(event)
    132	{
    133		gp.hr.up   = 0.0;
    134		gp.hr.down = 0.5;
    135	}
    136				//
    137				// Road オブジェクト(プロパティ)
    138				//
    139	function Road()
    140	{
    141						// レベル1における画像の配置
    142		this.blk1 = new Array();
    143		this.blk1[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);
    144		this.blk1[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);
    145		this.blk1[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);
    146		this.blk1[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);
    147		this.blk1[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);
    148		this.blk1[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);
    149		this.blk1[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);
    150		this.blk1[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);
    151		this.blk1[8] = new Array(1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2);
    152		this.blk1[9] = new Array(1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2);
    153		this.blk1[10] = new Array(1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2);
    154		this.blk1[11] = new Array(1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2);
    155						// レベル2における画像の配置
    156		this.blk2 = new Array();
    157		this.blk2[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);
    158		this.blk2[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);
    159		this.blk2[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);
    160		this.blk2[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);
    161		this.blk2[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);
    162		this.blk2[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);
    163		this.blk2[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);
    164		this.blk2[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);
    165		this.blk2[8] = new Array(1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 2, 2, 2);
    166		this.blk2[9] = new Array(1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 2, 2, 2);
    167		this.blk2[10] = new Array(1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 2, 2, 2);
    168		this.blk2[11] = new Array(1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 2, 2, 2);
    169		this.blk = new Array();   // 背景を構成するブロック
    170		this.image = new Array();   // ブロック画像
    171		this.row = 12;   // ブロックの行数
    172		this.col;   // ブロックの列数
    173		this.r_no = 4;   // 道を構成する縦のブロック数
    174		this.x = 0;   // 背景の位置
    175		this.v_x = -2;   // 背景の水平方向移動速度
    176		this.width = 25;   // ブロックの幅
    177		this.height = 25;   // ブロックの高さ
    178						// ブロック画像の読み込み
    179		this.image[0] = new Image();
    180		this.image[0].src = "image/road1.jpg";
    181		this.image[1] = new Image();
    182		this.image[1].src = "image/road2.jpg";
    183						// レベルによる初期設定
    184		if (mp.level == 1) {
    185			this.col = 26;
    186			this.blk = this.blk1;
    187		}
    188		else {
    189			this.col = 23;
    190			this.blk = this.blk2;
    191		}
    192		return this;
    193	}
    194				//
    195				// Hero オブジェクト(プロパティ)
    196				//
    197	function Hero(rd)
    198	{
    199		this.image = new Image();   // 主人公
    200		this.v_y = 0.0;   // 主人公の垂直方向移動速度
    201		this.v_x = 1.0;   // 主人公の水平方向移動速度
    202		this.up = 0.0;   // 主人公の上向き加速度
    203		this.down = 0;   // 主人公の下向き加速度
    204		this.jump = false;   // 主人公がジャンプ中か?
    205		this.width = 32;   // 主人公の幅
    206		this.height = 52;   // 主人公の高さ
    207						// 主人公の読み込み
    208		this.image.src = "image/char.jpg";
    209						// 主人公の初期位置
    210		this.x = 0;
    211		this.y = mp.canvas.height - rd.height * rd.r_no - this.height;
    212		return this;
    213	}
    			

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