1. HOME
  2. »
  3. プログラミング・Web
  4. »
  5. JavaScript
  6. »
  7. 小学生からのJavaScript。マップでキャラを動かせるようにしよう!

小学生からのJavaScript。マップでキャラを動かせるようにしよう!

小学生からのプログラミング講座(こうざ)、第14弾です。

前回は、JavaScriptでのマップの作り方を紹介(しょうかい)しました。
しかし、まだマップを配置(はいち)しただけで、キャラクターの画像(がぞう)を表示(ひょうじ)させていませんでした。

今回(こんかい)はマップ上にキャラクターの画像(がぞう)を表示(ひょうじ)させ、動(うご)かせるようにしてみようと思います。
また、壁(かべ)との衝突(しょうとつ)判定(はんてい)も作り、キャラクターが壁(かべ)をすり抜(ぬ)けられないようにしてみようと思います。

アル

昨日(きのう)さ、前回(ぜんかい)教(おし)えてもらったマップチップの表示(ひょうじ)と、りこちゃんの画像(がぞう)表示(ひょうじ)を自分で組み合わせて作ってみたんだ


りこ

うまく動(うご)いた?


アル

それが全然(ぜんぜん)。一応表示(いちおうひょうじ)はされたんだけど、りこちゃんが壁(かべ)をすり抜けちゃうんだ


りこ

そうなんだ


山田

じゃあ、今日(きょう)は壁(かべ)との衝突(しょうとつ)判定(はんてい)を作っていくべ!


りこ

山田先生! わーい!


アル

はやくやろう!

マップにキャラクターを表示してみよう!

まずはマップにキャラクターを表示(ひょうじ)させるところから始めましょう!
第12回目で紹介(しょうかい)した、HTML5とCanvasでキャラクターを動(うご)かす方法(ほうほう)と、第13回目で紹介(しょうかい)した、マップの表示(ひょうじ)方法(ほうほう)を組み合わせて作ります。

まずはcanvasの設定(せってい)と、コンテキストを取得(しゅとく)です。

//canvasの設定(せってい)
var canvas = document.getElementById( 'canvas' );
canvas.width = 640;	//canvasの横幅(よこはば)
canvas.height = 640;	//canvasの縦幅(たてはば)
 
//コンテキストを取得(しゅとく)
var ctx = canvas.getContext( '2d' );

アル

ここまでで、Canvasをつかう準備(じゅんび)ができたわけだね


りこ

Canvasを設定(せってい)して、コンテキスト(プログラムを動かすのに必要な情報)を取得(しゅとく)ね

そして今回必要(ひつよう)な、オブジェクトや変数(へんすう)です。
りこちゃんのオブジェクト、マップチップのImageオブジェクト、キーボードのオブジェクト、マップ配置(はいち)の変数(へんすう)を作っておきます。

//りこちゃんのオブジェクトを作成
var rico = new Object();
rico.img = new Image();
rico.img.src = 'img/rico.png';
rico.x = 0;
rico.y = 0;
rico.move = 0;

//マップチップのImageオブジェクトを作る
var mapchip = new Image();
mapchip.src = 'img/map.png';

//キーボードのオブジェクトを作成
var key = new Object();
key.up = false;
key.down = false;
key.right = false;
key.left = false;
key.push = '';

//マップの作成(さくせい)
var map = [
	[0, 0, 1, 0, 1, 0, 0, 0 ,0 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,0],
	[0, 1, 0, 0, 0, 1, 1, 1 ,0 ,1 ,0 ,1 ,1 ,0 ,1 ,1 ,1 ,0 ,1 ,0],
	[0, 0, 1, 1, 0, 0, 0, 1 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,0],
	[1, 0, 1, 0, 1, 1, 0, 0 ,0 ,1 ,1 ,1 ,1 ,1 ,0 ,0 ,1 ,0 ,1 ,0],
	[0, 0, 0, 0, 0, 1, 1, 1 ,0 ,1 ,0 ,0 ,0 ,0 ,1 ,1 ,0 ,1 ,1 ,0],
	[0, 1, 1, 1, 0, 0, 0, 0 ,0 ,1 ,0 ,1 ,1 ,1 ,0 ,1 ,0 ,0 ,0 ,0],
	[0, 1, 1, 1, 0, 1, 1, 1 ,1 ,1 ,0 ,1 ,0 ,0 ,0 ,0 ,1 ,1 ,1 ,0],
	[0, 0, 0, 1, 0, 0, 0, 0 ,1 ,0 ,0 ,1 ,0 ,1 ,1 ,0 ,0 ,0 ,1 ,0],
	[1, 1, 0, 1, 1, 1, 1, 1 ,1 ,0 ,1 ,1 ,0 ,0 ,1 ,1 ,1 ,0 ,1 ,1],
	[1, 0, 0, 0, 0, 0, 1, 1 ,0 ,0 ,0 ,0 ,1 ,0 ,1 ,1 ,0 ,0 ,1 ,0],
	[1, 0, 1, 1, 1, 0, 0, 0 ,1 ,0 ,1 ,0 ,0 ,0 ,0 ,0 ,1 ,1 ,0 ,0],
	[1, 0, 1, 0, 1, 1, 1, 0 ,1 ,0 ,1 ,1 ,0 ,1 ,1 ,0 ,0 ,0 ,0 ,1],
	[0, 0, 1, 0, 0, 1, 0, 0 ,1 ,0 ,0 ,1 ,0 ,1 ,0 ,1 ,1 ,1 ,0 ,0],
	[0, 1, 1, 1, 0, 1, 0, 1 ,0 ,0 ,1 ,1 ,0 ,1 ,0 ,1 ,1 ,0 ,1 ,0],
	[0, 0, 0, 1, 0, 1, 0, 0 ,1 ,0 ,1 ,1 ,0 ,1 ,0 ,0 ,0 ,0 ,0 ,0],
	[1, 1, 0, 1, 0, 1, 0, 1 ,1 ,0 ,0 ,1 ,0 ,1 ,1 ,0 ,1 ,1 ,1 ,0],
	[0, 0, 0, 1, 0, 1, 1, 1 ,1 ,1 ,0 ,1 ,0 ,1 ,1 ,0 ,0 ,0 ,1 ,0],
	[0, 1, 1, 1, 0, 1, 0, 0 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,1 ,1 ,0 ,1 ,1],
	[0, 1, 0, 0, 0, 1, 0, 1 ,1 ,1 ,0 ,0 ,1 ,1 ,0 ,1 ,0 ,0 ,0 ,0],
	[0, 0, 0, 1, 0, 0, 0, 1 ,1 ,1 ,1 ,0 ,0 ,0 ,1 ,1 ,1 ,1 ,1 ,0]
]

りこ

マップは縦(たて)20、横(よこ)20で、マップチップひとつが32pxだから、縦横640pxのマップができるのね

さらに、メインループとキー入力(にゅうりょく)があったときに呼ばれる関数(かんすう)です。
メインループでは、まず背景(はいけい)を黒く塗(ぬ)りつぶし、そこにマップチップを、そのあとにりこちゃんの画像(がぞう)を表示(ひょうじ)させます。
あとから表示(ひょうじ)した画像(がぞう)ほど、上にくるので、表示(ひょうじ)の順番(じゅんばん)には気をつけましょう。

//メインループ
function main() {
	//塗(ぬ)りつぶす色を指定(してい)
	ctx.fillStyle = "rgb( 0, 0, 0 )";
	//塗(ぬ)りつぶす
	ctx.fillRect(0, 0, 640, 640);

	for (var y=0; y<map.length; y++) {
		for (var x=0; x<map[y].length; x++) {
			if ( map[y][x] === 0 ) ctx.drawImage( mapchip, 0, 0, 32, 32, 32*x, 32*y, 32, 32 );
			if ( map[y][x] === 1 ) ctx.drawImage( mapchip, 32, 0, 32, 32, 32*x, 32*y, 32, 32 );
		}
	}

	//画像を表示
	ctx.drawImage( rico.img, rico.x, rico.y );

	addEventListener("keydown", keydownfunc, false);
	addEventListener("keyup", keyupfunc, false);

	//方向キーが押されている場合(ばあい)は、りこちゃんが移動する
	if ( rico.move === 0 ) {
		if ( key.left === true ) {
			rico.move = 32;
			key.push = 'left';
		}
		if ( key.up === true ) {
			rico.move = 32;
			key.push = 'up';
		}
		if ( key.right === true ) {
			rico.move = 32;
			key.push = 'right';
		}
		if ( key.down === true ) {
			rico.move = 32;
			key.push = 'down';
		}
	}
	//rico.moveが0より大きい場合は、4pxずつ移動(いどう)を続ける
	if (rico.move > 0) {
		rico.move -= 4;
		if ( key.push === 'left' ) rico.x -= 4;
		if ( key.push === 'up' ) rico.y -= 4;
		if ( key.push === 'right' ) rico.x += 4;
		if ( key.push === 'down' ) rico.y += 4;
	}

	requestAnimationFrame( main );
}
//ページと依存(いぞん)している全てのデータが読み込まれたら、メインループ開始
addEventListener('load', main(), false);

//キーボードが押されたときに呼び出される関数(かんすう)
function keydownfunc( event ) {
	var key_code = event.keyCode;
	if( key_code === 37 ) key.left = true;
	if( key_code === 38 ) key.up = true;
	if( key_code === 39 ) key.right = true;
	if( key_code === 40 ) key.down = true;
	event.preventDefault();
}

//キーボードが放(はな)されたときに呼び出される関数
function keyupfunc( event ) {
	var key_code = event.keyCode;
	if( key_code === 37 ) key.left = false;
	if( key_code === 38 ) key.up = false;
	if( key_code === 39 ) key.right = false;
	if( key_code === 40 ) key.down = false;
}

アル

りこちゃんが移動(いどう)するためのプログラムだね

少々長いですが、全体(ぜんたい)はこのようになっています。

//canvasの設定(せってい)
var canvas = document.getElementById( 'canvas' );
canvas.width = 640;	//canvasの横幅(よこはば)
canvas.height = 640;	//canvasの縦幅(たてはば)
 
//コンテキストを取得(しゅとく)
var ctx = canvas.getContext( '2d' );

//りこちゃんのオブジェクトを作成
var rico = new Object();
rico.img = new Image();
rico.img.src = 'img/rico.png';
rico.x = 0;
rico.y = 0;
rico.move = 0;

//マップチップのImageオブジェクトを作る
var mapchip = new Image();
mapchip.src = 'img/map.png';

//キーボードのオブジェクトを作成
var key = new Object();
key.up = false;
key.down = false;
key.right = false;
key.left = false;
key.push = '';

//マップの作成(さくせい)
var map = [
	[0, 0, 1, 0, 1, 0, 0, 0 ,0 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,0],
	[0, 1, 0, 0, 0, 1, 1, 1 ,0 ,1 ,0 ,1 ,1 ,0 ,1 ,1 ,1 ,0 ,1 ,0],
	[0, 0, 1, 1, 0, 0, 0, 1 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,0],
	[1, 0, 1, 0, 1, 1, 0, 0 ,0 ,1 ,1 ,1 ,1 ,1 ,0 ,0 ,1 ,0 ,1 ,0],
	[0, 0, 0, 0, 0, 1, 1, 1 ,0 ,1 ,0 ,0 ,0 ,0 ,1 ,1 ,0 ,1 ,1 ,0],
	[0, 1, 1, 1, 0, 0, 0, 0 ,0 ,1 ,0 ,1 ,1 ,1 ,0 ,1 ,0 ,0 ,0 ,0],
	[0, 1, 1, 1, 0, 1, 1, 1 ,1 ,1 ,0 ,1 ,0 ,0 ,0 ,0 ,1 ,1 ,1 ,0],
	[0, 0, 0, 1, 0, 0, 0, 0 ,1 ,0 ,0 ,1 ,0 ,1 ,1 ,0 ,0 ,0 ,1 ,0],
	[1, 1, 0, 1, 1, 1, 1, 1 ,1 ,0 ,1 ,1 ,0 ,0 ,1 ,1 ,1 ,0 ,1 ,1],
	[1, 0, 0, 0, 0, 0, 1, 1 ,0 ,0 ,0 ,0 ,1 ,0 ,1 ,1 ,0 ,0 ,1 ,0],
	[1, 0, 1, 1, 1, 0, 0, 0 ,1 ,0 ,1 ,0 ,0 ,0 ,0 ,0 ,1 ,1 ,0 ,0],
	[1, 0, 1, 0, 1, 1, 1, 0 ,1 ,0 ,1 ,1 ,0 ,1 ,1 ,0 ,0 ,0 ,0 ,1],
	[0, 0, 1, 0, 0, 1, 0, 0 ,1 ,0 ,0 ,1 ,0 ,1 ,0 ,1 ,1 ,1 ,0 ,0],
	[0, 1, 1, 1, 0, 1, 0, 1 ,0 ,0 ,1 ,1 ,0 ,1 ,0 ,1 ,1 ,0 ,1 ,0],
	[0, 0, 0, 1, 0, 1, 0, 0 ,1 ,0 ,1 ,1 ,0 ,1 ,0 ,0 ,0 ,0 ,0 ,0],
	[1, 1, 0, 1, 0, 1, 0, 1 ,1 ,0 ,0 ,1 ,0 ,1 ,1 ,0 ,1 ,1 ,1 ,0],
	[0, 0, 0, 1, 0, 1, 1, 1 ,1 ,1 ,0 ,1 ,0 ,1 ,1 ,0 ,0 ,0 ,1 ,0],
	[0, 1, 1, 1, 0, 1, 0, 0 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,1 ,1 ,0 ,1 ,1],
	[0, 1, 0, 0, 0, 1, 0, 1 ,1 ,1 ,0 ,0 ,1 ,1 ,0 ,1 ,0 ,0 ,0 ,0],
	[0, 0, 0, 1, 0, 0, 0, 1 ,1 ,1 ,1 ,0 ,0 ,0 ,1 ,1 ,1 ,1 ,1 ,0]
]

//メインループ
function main() {
	//塗(ぬ)りつぶす色を指定(してい)
	ctx.fillStyle = "rgb( 0, 0, 0 )";
	//塗(ぬ)りつぶす
	ctx.fillRect(0, 0, 640, 640);

	for (var y=0; y 0) {
		rico.move -= 4;
		if ( key.push === 'left' ) rico.x -= 4;
		if ( key.push === 'up' ) rico.y -= 4;
		if ( key.push === 'right' ) rico.x += 4;
		if ( key.push === 'down' ) rico.y += 4;
	}

	requestAnimationFrame( main );
}
//ページと依存(いぞん)している全てのデータが読み込まれたら、メインループ開始
addEventListener('load', main(), false);

//キーボードが押されたときに呼び出される関数(かんすう)
function keydownfunc( event ) {
	var key_code = event.keyCode;
	if( key_code === 37 ) key.left = true;
	if( key_code === 38 ) key.up = true;
	if( key_code === 39 ) key.right = true;
	if( key_code === 40 ) key.down = true;
	event.preventDefault();
}

//キーボードが放(はな)されたときに呼び出される関数
function keyupfunc( event ) {
	var key_code = event.keyCode;
	if( key_code === 37 ) key.left = false;
	if( key_code === 38 ) key.up = false;
	if( key_code === 39 ) key.right = false;
	if( key_code === 40 ) key.down = false;
}

しかしこのプログラムでは、りこちゃんが壁(かべ)をすり抜(ぬ)けてしまいます。

下の枠内(わくない)をクリックして、方向(ほうこう)キーで操作(そうさ)してみてね!

りこ

きゃー、私が壁(かべ)をすり抜(ぬ)けてる


アル

これじゃあ迷路(めいろ)にならないね


山田

そこで今回(こんかい)は、壁(かべ)にぶつからないように、プログラムをつくっていくべ!

壁の座標とりこちゃんの座標を比べて、壁との当たり判定をする

当たり判定(はんてい)といえば、Scratch(スクラッチ)でシューティングゲームを作った時も敵とぶつかっているかとか、弾(たま)が当たっているかとか、やりましたね。

しかし今回の場合(ばあい)、「壁(かべ)に当たっているか」ではなく、「壁(かべ)に当たってしまうか」という判定(はんてい)になります。
どちらにしろ実際(じっさい)には当たっていないので、「この先、衝突(しょうとつ)するかも」という予測(よそく)の判定(はんてい)です。

アル

予測(よそく)って……まほうでもつかうのかな?


りこ

そんなわけないでしょ! でも、どうやるんだろう


山田

座標(ざひょう)で考えればいんだべ


アル

座標(ざひょう)、りこちゃんの座標(ざひょう)と、壁(かべ)の座標(ざひょう)を比べるってこと? でもどうやって……

さて、壁(かべ)の座標(ざひょう)はもうすでに取得(しゅとく)できています。
なぜなら、mapという配列(はいれつ)にマップを作って、そこに合わせて壁(かべ)を配置(はいち)しているからです。

さらに、りこちゃんの座標(ざひょう)も取得(しゅとく)できますね。
オブジェクトのrico.xとrico.yです。

じつはこの2つ、座標(ざひょう)の表し方が違(ちが)います。
りこちゃんは実際(じっさい)に動かすため、正確(せいかく)な座標(ざひょう)をrico.xとrico.yが覚えてくれています。
しかしmapは正確(せいかく)な座標(ざひょう)を覚えているわけではなく、マップチップの場所(ばしょ)を覚えているだけなんです。

左から0番目、上から0番目の数字は0、
左から1番目、上から0番目の数字は0、
左から2番目、上から0番目の数字は1、
左から3番目、上から0番目の数字は0、

といった具合(ぐあい)です。

だけど心配(しんぱい)する必要(ひつよう)はありません。
りこちゃんの座標(ざひょう)は、マップチップのサイズである32でわることで、mapと同じことになります。

りこ

なんで!? よく分からない!


アル

僕もさっぱり!


山田

じゃあ、例(れい)を見るべよ!

では、例(れい)で見ていきましょう。
りこちゃんのいる場所(ばしょ)は、0から数えて、左から何番目の、上から何番目でしょうか?

答えは、左から3番目の、上から6番目です。

では、x座標(ざひょう)とy座標を正確(せいかく)にいうとどうなるでしょうか?
簡単(かんたん)です。1マス32pxなので、32をかけ算すれば、答えがでますね。
つまりxは96px, yは192pxです。

りこ

逆にいえば、わり算すれば正確な座標から、何番目のところにいるかが出せるってことね!


山田

そうなんだべよ!

もしも右矢印が押されて、右方向に壁(かべ)がある場合は進(すす)むことができません。
壁があるということは、りこちゃんの右側が「1」になっているということです。

まず、変数xとyに、りこちゃんの座標(ざひょう)を32でわった数を代入(だいにゅう)します。
右矢印が押されたとき、x座標(ざひょう)に1プラスしたいので、x++とすることでxに1足すことができます。

そのあと、map[y][x]とすることで、キャラが右方向へ1移動(いどう)したあとのマップ上の座標(ざひょう)を示(しめ)すことができます。
その座標(ざひょう)が0の場合(ばあい)のときのみ移動(いどう)できるようにします。

これをプログラムにしてみると、このようになります。

if ( key.right === true ) {
	var x = rico.x/32;
	var y = rico.y/32;
	x++;
	if ( map[y][x] === 0 ) {
		rico.move = 32;
		key.push = 'right';
	}
}

他(ほか)のキーのときも同じです。

しかし、このプログラムでは、y座標(ざひょう)の場合(ばあい)、上や下にマップからはみ出てしまうとエラーがおきてしまいます。
上下の矢印キーが押されたときのみ、移動(いどう)を制限(せいげん)します。
例えば、上キーが押されたときは、このように4行目で移動(いどう)を制限(せいげん)しています。

if ( key.up === true ) {
	var x = rico.x/32;
	var y = rico.y/32;
	if ( y > 0) {
		y--;
		if ( map[y][x] === 0 ) {
			rico.move = 32;
			key.push = 'up';
		}
	}
}

全体(ぜんたい)ではこのようになります。

//canvasの設定(せってい)
var canvas = document.getElementById( 'canvas' );
canvas.width = 640;		//canvasの横幅(よこはば)
canvas.height = 640;	//canvasの縦幅(たてはば)
 
//コンテキストを取得(しゅとく)
var ctx = canvas.getContext( '2d' );
 
//りこちゃんのオブジェクトを作成
var rico = new Object();
rico.img = new Image();
rico.img.src = 'img/rico.png';
rico.x = 0;
rico.y = 0;
rico.move = 0;

//マップチップのImageオブジェクトを作る
var mapchip = new Image();
mapchip.src = 'img/map.png';

//キーボードのオブジェクトを作成
var key = new Object();
key.up = false;
key.down = false;
key.right = false;
key.left = false;
key.push = '';

//マップの作成(さくせい)
var map = [
	[0, 0, 1, 0, 1, 0, 0, 0 ,0 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,0],
	[0, 1, 0, 0, 0, 1, 1, 1 ,0 ,1 ,0 ,1 ,1 ,0 ,1 ,1 ,1 ,0 ,1 ,0],
	[0, 0, 1, 1, 0, 0, 0, 1 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,0],
	[1, 0, 1, 0, 1, 1, 0, 0 ,0 ,1 ,1 ,1 ,1 ,1 ,0 ,0 ,1 ,0 ,1 ,0],
	[0, 0, 0, 0, 0, 1, 1, 1 ,0 ,1 ,0 ,0 ,0 ,0 ,1 ,1 ,0 ,1 ,1 ,0],
	[0, 1, 1, 1, 0, 0, 0, 0 ,0 ,1 ,0 ,1 ,1 ,1 ,0 ,1 ,0 ,0 ,0 ,0],
	[0, 1, 1, 1, 0, 1, 1, 1 ,1 ,1 ,0 ,1 ,0 ,0 ,0 ,0 ,1 ,1 ,1 ,0],
	[0, 0, 0, 1, 0, 0, 0, 0 ,1 ,0 ,0 ,1 ,0 ,1 ,1 ,0 ,0 ,0 ,1 ,0],
	[1, 1, 0, 1, 1, 1, 1, 1 ,1 ,0 ,1 ,1 ,0 ,0 ,1 ,1 ,1 ,0 ,1 ,1],
	[1, 0, 0, 0, 0, 0, 1, 1 ,0 ,0 ,0 ,0 ,1 ,0 ,1 ,1 ,0 ,0 ,1 ,0],
	[1, 0, 1, 1, 1, 0, 0, 0 ,1 ,0 ,1 ,0 ,0 ,0 ,0 ,0 ,1 ,1 ,0 ,0],
	[1, 0, 1, 0, 1, 1, 1, 0 ,1 ,0 ,1 ,1 ,0 ,1 ,1 ,0 ,0 ,0 ,0 ,1],
	[0, 0, 1, 0, 0, 1, 0, 0 ,1 ,0 ,0 ,1 ,0 ,1 ,0 ,1 ,1 ,1 ,0 ,0],
	[0, 1, 1, 1, 0, 1, 0, 1 ,0 ,0 ,1 ,1 ,0 ,1 ,0 ,1 ,1 ,0 ,1 ,0],
	[0, 0, 0, 1, 0, 1, 0, 0 ,1 ,0 ,1 ,1 ,0 ,1 ,0 ,0 ,0 ,0 ,0 ,0],
	[1, 1, 0, 1, 0, 1, 0, 1 ,1 ,0 ,0 ,1 ,0 ,1 ,1 ,0 ,1 ,1 ,1 ,0],
	[0, 0, 0, 1, 0, 1, 1, 1 ,1 ,1 ,0 ,1 ,0 ,1 ,1 ,0 ,0 ,0 ,1 ,0],
	[0, 1, 1, 1, 0, 1, 0, 0 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,1 ,1 ,0 ,1 ,1],
	[0, 1, 0, 0, 0, 1, 0, 1 ,1 ,1 ,0 ,0 ,1 ,1 ,0 ,1 ,0 ,0 ,0 ,0],
	[0, 0, 0, 1, 0, 0, 0, 1 ,1 ,1 ,1 ,0 ,0 ,0 ,1 ,1 ,1 ,1 ,1 ,0]
]

//メインループ
function main() {
	//塗(ぬ)りつぶす色を指定(してい)
	ctx.fillStyle = "rgb( 0, 0, 0 )";
	//塗(ぬ)りつぶす
	ctx.fillRect(0, 0, 640, 640);

	for (var y=0; y<map.length; y++) {
		for (var x=0; x<map[y].length; x++) {
			if ( map[y][x] === 0 ) ctx.drawImage( mapchip, 0, 0, 32, 32, 32*x, 32*y, 32, 32 );
			if ( map[y][x] === 1 ) ctx.drawImage( mapchip, 32, 0, 32, 32, 32*x, 32*y, 32, 32 );
		}
	}

	//画像を表示
	ctx.drawImage( rico.img, rico.x, rico.y );

	addEventListener("keydown", keydownfunc, false);
	addEventListener("keyup", keyupfunc, false);

	//方向キーが押されている場合(ばあい)は、りこちゃんが移動する
	if ( rico.move === 0 ) {
		if ( key.left === true ) {
			var x = rico.x/32;
			var y = rico.y/32;
			x--;
			if ( map[y][x] === 0 ) {
				rico.move = 32;
				key.push = 'left';
			}
		}
		if ( key.up === true ) {
			var x = rico.x/32;
			var y = rico.y/32;
			if ( y > 0) {
				y--;
				if ( map[y][x] === 0 ) {
					rico.move = 32;
					key.push = 'up';
				}
			}
		}
		if ( key.right === true ) {
			var x = rico.x/32;
			var y = rico.y/32;
			x++;
			if ( map[y][x] === 0 ) {
				rico.move = 32;
				key.push = 'right';
			}
		}
		if ( key.down === true ) {
			var x = rico.x/32;
			var y = rico.y/32;
			if ( y < 19 ) {
				y++;
				if ( map[y][x] === 0 ) {
					rico.move = 32;
					key.push = 'down';
				}
			}
		}
	}

	//rico.moveが0より大きい場合は、4pxずつ移動(いどう)を続ける
	if (rico.move > 0) {
		rico.move -= 4;
		if ( key.push === 'left' ) rico.x -= 4;
		if ( key.push === 'up' ) rico.y -= 4;
		if ( key.push === 'right' ) rico.x += 4;
		if ( key.push === 'down' ) rico.y += 4;
	}

	requestAnimationFrame( main );
}
//ページと依存(いぞん)している全てのデータが読み込まれたら、メインループ開始
addEventListener('load', main(), false);

//キーボードが押されたときに呼び出される関数(かんすう)
function keydownfunc( event ) {
	var key_code = event.keyCode;
	if( key_code === 37 ) key.left = true;
	if( key_code === 38 ) key.up = true;
	if( key_code === 39 ) key.right = true;
	if( key_code === 40 ) key.down = true;
	event.preventDefault();		//方向キーでブラウザがスクロールしないようにする
}

//キーボードが放(はな)されたときに呼び出される関数
function keyupfunc( event ) {
	var key_code = event.keyCode;
	if( key_code === 37 ) key.left = false;
	if( key_code === 38 ) key.up = false;
	if( key_code === 39 ) key.right = false;
	if( key_code === 40 ) key.down = false;
}

下の枠内(わくない)をクリックして、方向(ほうこう)キーで操作(そうさ)してみてね!

りこ

きゃー、迷路、まよっちゃう!


アル

すごい! ちゃんと壁で止まってるよ!

まとめ

今回は、マップ上をキャラクターが移動(いどう)し、壁(かべ)をすり抜(ぬ)けられないように作りました。
大切なのはりこちゃんの座標(ざひょう)と、マップチップの座標(ざひょう)を照(て)らし合わせることです。そのためには、りこちゃんの座標(ざひょう)を1つのマップチップのサイズで割るというのも1つの方法です。

山田

ここまででも、一応遊べるべよ


アル

まだスタートもゴールもないけどね


りこ

でもスタートとゴールだけなら簡単(かんたん)につくれそうだね


山田

ふたりとも、よくここまで頑張ったべ


りこ

へへへっ


アル

いやいや。でも、もっと頑張ればポケモンみたいなゲームだって夢(ゆめ)じゃないなって思えてきたよ


山田

それは良かったべ。ところでわだず、昨日ザギンで、こんなのかってきたべ


アル

ザギン……?


りこ

銀座(ぎんざ)のことじゃない? どうやって行ったんだろう


山田

サングラスと、ジーパンだべ。どうだべ、似合(にあ)うべか? これで人間になりすますんだべ


アル

ゴーグルと海パンだよ


りこ

ははは、海でも行くのー?


山田

あ……


山田

て……てやんでぇ、べらぼうめだべさ! 海に行ってこそ、真の男だべさ!
次回はもっと難(むずか)しいこと教えてやるべ! 覚悟(かくご)するべ!


りこ

ひぃ、う……うん。先生、こわい


アル

ゆるしてー


この企画の一覧はこちら

  1. 小学生から始めるプログラミング入門。プログラミングってなぁに?
  2. 小学生から始めるScratch入門。使い方とゲーム開発の基礎知識
  3. 小学生から始めるScratch入門。シューティングゲームを作ろう!
  4. 小学生からのプログラミング入門。JavaScriptでおみくじを作ろう!
  5. 小学生からのJavaScript入門。今月の残り日数を計算してみよう!
  6. 小学生からのJavaScript入門。画像の表示と移動をしてみよう!
  7. 小学生からのJavaScript入門。キー入力でキャラを動かしてみよう!
  8. 小学生からのJavaScript入門。ファイルを分けて管理してみよう!
  9. 小学生からのJavaScript入門。オブジェクトを使ってみよう!
  10. 小学生からのJavaScript入門。ゲームのメインループを作ってみよう!
  11. 小学生からのJavaScript入門。キャラを決まった間隔ずつ動かす!
  12. 小学生からのJavaScript。HTML5とCanvasを使ってみよう!
  13. 小学生からのJavaScript。迷路やRPGで使えるマップを作ってみよう!
  14. 小学生からのJavaScript。マップでキャラを動かせるようにしよう!

スポンサードリンク

関連コンテンツ

オススメ記事

【Android Studio】TextView を使ってテキストを変更、追加する方法。

TextViewの文字列を変更するより、これまでの人生を変更したい@It_is_Rです。 Android Studioを使ったアプリ開発講座6回目です。 今回はアプリに表示されたテキストを変更

FC2 blog customize

FC2ブログ ”最強” カスタマイズ入門講座。ブログ全体の幅を変更。

現実社会では殆ど言葉を発しない@It_is_Rです。だって、厄介なことになりたくないじゃん。 今回も前回に引き続き、FC2ブログカスタマイズの記事です。前回、ヘッダーのサイズを変更しましたが、ブ

Dockerでよく使うコマンドとオプション、その使い方を徹底解説!

人生に意味は求めない。それよりもDockerのコマンドの意味を理解する方が重要です。@It_is_Rです。 Dockerにはたくさんのコマンドがありますが、まずはよく使うコマンドを覚えていきまし

java

【Java】スーパクラス、サブクラスとは?継承について。

猿も木から落ちますが、Rは木から落ちません。だって登らないから。 @It_is_R です。いや、登ろうと思っても登れません。 Javaを使っていると継承という言葉をよく耳にしますよね。どういうも

【Gitの使い方 – その1】GitHubのアカウントを取得する方法!

Gitを使うとバージョン管理が簡単になりますが、それ以前に自分の頭の中を管理するのが大変な@It_is_Rです。 Gitの使い方をいくつかの記事に分けて紹介していきたいと思います。 まず今回は

【初心者向け】webpack 4入門。一番簡単で詳しい使い方

風邪をひいてぼんやりしている@It_is_Rです。どちらにしろいつもぼんやりしてますが。 さて、今回はWebpack4について紹介していきたいと思います。 この記事では、jsファイルをビルドす

【Android Studio】 GridLayout の使い方。複雑なレイアウトを表現する方法

スマホの充電がいつの間にか無くなっている@It_is_Rです。 Androidアプリ開発、10回目となりました。 前回、様々なレイアウトの使い方を紹介しましたが、今回はその中でもちょっと難しい

【Android Studio】TextView 文字の色やサイズ、書体を変更する方法。

サイズは大きいほど、押しがいがあります。@It_is_Rです。 スマホのボタンの話ですよ。何を考えてたんですか? Androidアプリ開発、8回目となりました。 今回はこれまでに学習した T

【Gitの使い方 – その4】ブランチを使って履歴を分岐させる方法

エビの殻や、ポテチ、煮干しなどを食べると、必ずと言っていいほど口が血だらけになります。@It_is_Rです。 さて、Gitの使い方4回目の今回は、ブランチについてです。 ブランチは作業を枝分か

迷路やRPGで使えるマップを作ってみよ!

小学生からのJavaScript。迷路やRPGで使えるマップを作ってみよう!

小学生からのプログラミング講座(こうざ)、第13弾です。 前回はHTML5とCanvasを使って、キャラクターがキーボードの入力(にゅうりょく)で移動(いどう)するところまで、紹介(しょうかい)

コメントをどうぞ!

メールアドレスが公開されることはありません。