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

【JavaScript】マップでキャラを動かせるようにしよう! 小学生からのプログラミング入門

小学生からのプログラミング講座こうざ、今回もはじめていきましょう!

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

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

アル

昨日きのうさ、前回おしえてもらったマップチップの表示と、りこちゃんの画像表示を自分で組み合わせて作ってみたんだ

りこ

うまくうごいた?

アル

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

りこ

そうなんだ

山田

それが全然(ぜんぜん)。一応表示(いちおうひょうじ)はされたんだけど、りこちゃんが壁(かべ)をすり抜けちゃうんだじゃあ、今日きょうかべとの衝突しょうとつ判定はんていを作っていくべ!

りこ

山田先生! わーい!

アル

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

目次
  1. マップにキャラクターを表示してみよう!
  2. 壁の座標とりこちゃんの座標を比べて、壁との当たり判定をする
  3. まとめ

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

まずはマップにキャラクターを表示ひょうじさせるところから始めましょう!
第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<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;
}

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

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

りこ

きゃー、私がかべをすりけてる

アル

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

山田

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

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

当たり判定はんていといえば、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. Scratchでシューティングゲームを作ろう! 小学生からのプログラミング入門
  5. Scratchでピアノ鍵盤を作って音を鳴らそう! 小学生からのプログラミング入門
  6. JavaScriptでおみくじを作ろう! 小学生からのプログラミング入門
  7. JavaScriptで今月の残り日数を計算してみよう! 小学生からのプログラミング入門
  8. JavaScriptで画像を表示してみよう! 小学生からのプログラミング入門
  9. JavaScriptで画像を移動してみよう! 小学生からのプログラミング入門
  10. 【JavaScript】キー入力でキャラを動かしてみよう! 小学生からのプログラミング入門
  11. 【JavaScript】ファイルを分けて管理してみよう! 小学生からのプログラミング入門
  12. 【JavaScript】オブジェクトを使ってみよう! 小学生からのプログラミング入門
  13. 【JavaScript】ゲームのメインループを作ってみよう! 小学生からのプログラミング入門
  14. 【JavaScript】キャラを決まった間隔ずつ動かす! 小学生からのプログラミング入門
  15. HTML5とCanvasを使ってみよう! 小学生からのプログラミング入門
  16. 【JavaScript】迷路やRPGで使えるマップを作ってみよう! 小学生からのプログラミング入門
  17. 【JavaScript】マップでキャラを動かせるようにしよう! 小学生からのプログラミング入門
  18. 【JavaScript】クラスの概念をしっかりと理解しよう! 小学生からのプログラミング入門
  19. 【JavaScript】プログラム全体をクラスを使って作ってみよう! 小学生からのプログラミング入門
  20. 【JavaScript】文字を表示するクラスを作ってみよう! 小学生からのプログラミング入門
  21. 【JavaScript】改行と一文字ずつ画面に表示する方法! 小学生からのプログラミング入門
  22. 【JavaScript】ノベルゲーム風にキー入力で文字を切り替える方法! 小学生からのプログラミング入門
  23. JavaScriptでRPGを作ろう!スマホにも対応したゲームの作り方
  24. webpackを使ってゲームエンジンを作ろう!(JSライブラリの作り方)

スポンサードリンク

関連コンテンツ

オススメ記事

FC2 blog customize

FC2ブログ ”最強” カスタマイズ入門講座。文字の大きさを設定する。

こんにちわ。美しいものほど濁って見える@It_is_Rです。 今回もFC2ブログの最強カスタマイズを始めていこうと思います。 今回は文字の大きさや色など、ブログ内の文字の設定をしていきます。初

【Bootstrap 4】記事一覧ページなどで使える「カード」の使い方

Bootstrap4の使い方、第7回目です。 トップページなどを見ると、記事の一部が抜粋された記事一覧が表示されているサイトをよく見かけます。 今回はそんな記事一覧ページを作るのに便利な「カー

ファイルを分けるべよ!

【JavaScript】ファイルを分けて管理してみよう! 小学生からのプログラミング入門

小学生からのJavaScript《ジャバスクリプト》入門講座《にゅうもんこうざ》、今回もはじめていきましょう! 前回はりこちゃんを方向キーで操作《そうさ》することができるようになりました。しか

小学校プログラミング必修化。どんなことを学べばいいの?

2020年からのプログラミング必修化において、お子さんのいる方は、「いったいどんなことを学べばいいんだろう?」、「プログラミングなんてまったく分からないのに、どうやって教えてあげればいいんだろう……

wordpress

【WordPress】パンくずリストをプラグイン無しで自作する方法

※追記(2018/2/12) もっと高機能になるように、改良修正しました。 人生で3回ほど死にそうになったことがある@It_is_Rです。 WordPressのパンくずリストを作

JavaScriptでRPGを作ろう!スマホにも対応したゲームの作り方

みなさんこんにちは。今日も楽しくプログラミングを学んでいきましょう! これまでの講座《こうざ》で、JavaScript《ジャバスクリプト》によるゲーム開発《かいはつ》の方法が、なんとなくでも分

Android Studio

【Android Studio】新規プロジェクトを作成する方法

前回、 Android Studio のインストールが完了しました。 その続きから始めていきましょう。 今回は新規プロジェクトを作成する方法です。 新規プロジェクトの作成 それ

PythonでUSBメモリのパスワードを解析。総当たりでロック解除してみよう!

みなさんこんにちは。@It_is_Rです。今回はPythonを使って、総当たりでUSBメモリのパスワードを解析する方法を紹介します。(※このストーリーはフィクションです) Rりこ師匠、

Homebrew

Homebrewのインストールと使い方。よく使うコマンド一覧と詳しい解説まとめ

人生をもう一度やり直したいとつくづく思う@It_is_Rです。 今回はHomebrewについての記事を書いてみようと思います。Homebrewをインストールすると、ターミナルから便利なコマンド

FC2 blog customize

FC2ブログ ”最強” カスタマイズ入門講座。背景を変更する。

三度の飯よりも好きなものが多すぎて比較にならない@It_is_Rです。 FC2ブログ"最強"カスタマイズ入門講座の続きですね。最強にカスタマイズしていきましょう。 今回は背景色の変更をメインに

2件のコメント “【JavaScript】マップでキャラを動かせるようにしよう! 小学生からのプログラミング入門

  1. 最近このサイトを見て勉強を始めた者です。
    このページのプログラムをvisual studio codeに書き、実行したのですかが、動きませんでした。
    変数の名前などを自分の分かりやすいように変更しつつほぼ丸写しのような状態で実行したのですが、動かなかったため、失礼ながらこのページのソースコードを一度コピペして実行してみました。しかし、マップも表示されずキャラクターも動きませんでした。
    前々回まで(マップを表示させる前)までは行う事が出来たのですがマップの表示が出来ません。
    どうすれば表示させられるでしょうか。つたない文章ですがよろしくおねがします。

    1. >ゆりかさん
      はじめまして。コメントありがとうございます。

      まず、この記事でミスがあったことに、たった今、気がつきました。「マップにキャラクターを表示してみよう!」の項目、キャラが壁をすり抜けてしまう部分の、全体のソースコードです。
      どうやら、貼り付けのときの私のミスで、改行が削除されてしまっていたようです。
      この部分は修正させていただきました。
      もし、ここが原因で、プログラムが動かなかったのでしたら、大変申し訳ありません。

      ただ、前々回までは動かせた、とのことですので、原因は前回の記事での過程のどこかにあるのかな、と思います。

      原因を探るために、ひとつずつ確認させてください。

      このページのソースコードをコピペした、というのは、一番最後の全体のソースコードでしょうか?
      もしそうでしたら、私ももう一度試してみましたが、動かすことができましたので、コピペでも問題ないと思います。

      となると原因は、index.htmlファイルか、画像ファイルの場所かな、と思いますが、もしindex.htmlファイルにミスがあれば、前々回のプログラムも動かないはずなので、こちらは問題なさそうな気がします。

      画像ファイルの場所ですが、マップの画像ファイル(map.png)は、imgフォルダの中に入っているでしょうか? こちらの確認をお願いします。

      ちゃんとimgフォルダのなかにmap.pngファイルが入っているのでしたら、可能性は低い気もしますが、ブラウザのキャッシュが原因かもしれません。
      ブラウザのキャッシュの削除を試してみてください。

      今のところ、私に考えられる原因は以上ですが、もしそれでも動かない場合は、ブラウザのコンソールを確認してみてください。
      なにかエラーメッセージが表示されていれば、そこから原因を探ることができるかもしれません。

      お役に立てると幸いです。

コメントをどうぞ!(コメントは承認後に反映されます)

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です