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ライブラリの作り方)

スポンサードリンク

関連コンテンツ

オススメ記事

【Git】リモートリポジトリへPushする方法

こんにちは、@It_is_Rです。 前回「【Git】ブランチを使って履歴を分岐させる方法」では、ブランチを使うことの便利さを学びました。第五回目の今回は、GitHubのリモートリポジトリを作成

【Bootstrap 4】badgeを使ってテキスト横に小さな文字を入れる方法

前にBootStrap4の記事を書いていましたが、日にちが空いてしまいましたね。@It_is_Rです。 前回は全体的な機能とアラートの使い方を紹介しました。 今回はバッジの使い方を紹介していき

npm-scriptsの使い方。自作のコマンドによるタスク実行方法

畳んだ布団が飼い猫のお気に入りの場所になってます。@It_is_Rです。 npm-scriptsを使うことで、あらかじめタスクをかんたんな名前で指定しておき、そのタスクを素早く実行できるように

java

Javaでじゃんけんゲームを作ろう。サンプルコードあり!

※追記(2018/8/29) より分かりやすい記事になるよう修正しました。 今回はJavaを使って、じゃんけんゲームを作る方法を紹介します。 eclipseがインストールされており、Java

【解決!】Macで「デフォルトシェルはzshになった」と表示されるときの対処法

MacOSをアップデートしてから、ターミナルを開くたびに、「The default interactive shell is now zsh.」というメッセージが表示されるようになりました。 これは

とってもかんたん!iPhoneアプリ開発

SwiftUIでじゃんけんゲームを作ろう。かんたんiPhoneアプリ開発入門

SwiftUIは、2019年にアップルが発表したフレームワークです。 SwiftUIを使って、iPhoneで遊べるじゃんけんゲームを作成してみましょう。 この入門ではXcodeを使いますので、

ショートコード

BEMによるCSS設計の方法を解説。命名規則から使い方まで。

完璧を求めすぎて、平均以下な@It_is_Rです。 CSSは比較的簡単なものですが、CSS設計をしっかりしておかなければ、余分なコードが多くなったり、後から修正が大変になったりしてこまることにな

【Android Studio】Button(ボタン)を作る基本中の基本。

ボタンを作る基本中の基本ですが、ボタンを作ること自体が基本中の基本です。@It_is_Rです。 タイトルなんてどうだっていいんです。肝心のなのは真心です。 Androidアプリ開発、7回目とな

WordPressのテーマを自作してみよう。テーマ開発の方法を徹底解説!

WordPressテーマの自作方法を紹介していきます。 今回はテーマ作成における知識や、ツール、ファイル構成、実際の作り方などを書いていきます。 WordPressのテーマを自作する上

キー入力で文字を切り替えるべ

【JavaScript】ノベルゲーム風にキー入力で文字を切り替える方法! 小学生からのプログラミング入門

小学生からのJavaScript講座です。 前回、文字を一文字づつ表示させる方法と改行の方法を紹介しました。今回はこのプログラムに、キー入力によって文字を切り替えられる機能をつけてみましょう。

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

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

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

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

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

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

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

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

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

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

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

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

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

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