あ、先生。蝶ネクタイが曲がってるよ
お、そうだべか? すまんがちょっとなおしてくれないべか?
うん! あれ……ねじっちゃってるな……いったん取り外そう
ふぅ……教室にリコーダー忘れちゃったから持ってきた。あれ? りこちゃん。その猫、どうしたの?
……
山田先生、いないのか……また校長先生に怒られてるんじゃないの?
(……と、とにかく蝶ネクタイをつけてあげなくちゃ)
山田先生って、けっこうドジなところがあるからなぁ
アルくん……
ひぃっ……あぁっ、や……山田先生だったの!? ごごご、ごめんなさーい!
タイルマップを作ってみよう!
つづいて、タイルマップを作っていきます。
つぎはタイルマップの機能を作っていくべよ
タイルマップは、タイルを組み合わせるようにして作られるマップのことだべ
ひと昔まえの、ポケモンやドラクエのマップみないなのだね
rpg/
|-- img (省略)/
|-- index.html
|-- js/
| |-- engine/
| | |-- game.js
| | |-- scene.js
| | |-- sprite.js
| | `-- tilemap.js (追加)
| `-- main.js
`-- sound (省略)/
ファイルを追加したあとは、index.htmlから読み込むのね
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>くろねこラビリンス</title>
<style>
* {
padding: 0;
margin: 0;
}
canvas {
display: block;
}
</style>
</head>
<body>
<script src="js/engine/scene.js"></script>
<script src="js/engine/sprite.js"></script>
<script src="js/engine/tilemap.js"></script>
<script src="js/engine/game.js"></script>
<script src="js/main.js"></script>
</body>
</html>
そして、tilemap.jsはこのようにして欲しいんだべ
js/engine/tilemap.js
'use strict'
/**
* タイルマップに関するクラス
*/
class Tilemap {
/**
* 引数
* img : 画像ファイルまでのパス
* size : タイルひとつの大きさ(一辺の長さ)
*
* タイルひとつは正方形にする
*/
constructor( img, size ) {
//Imageのインスタンスを作成
this.img = new Image();
//this.img.srcに画像ファイルまでのパスを代入
this.img.src = img;
//画像の初期位置
this.x = this.y = 0;
//引数sizeが指定されていない場合、this.sizeに32を代入
this.size = size || 32;
//二次元配列で数値を入力すると、マップをつくることができる
this.data = [];
} //constructor() 終了
/**Gameクラスのメインループからずっと呼び出され続ける
*
* 引数
* canvas : 紙(キャンバス)
*/
update( canvas ) {
//画像などを画面に表示するためのメソッドを呼び出す
this.render( canvas );
//常に呼び出される、オーバーライド用のメソッドを呼び出す
this.onenterframe();
} //update() 終了
/**
* Gameクラスのメインループからずっと呼び出され続ける。画像を表示したりするためのメソッド
*
* 引数
* canvas : 紙(キャンバス)
*/
render( canvas ) {
//マップの縦方向の数だけ繰り返す
for (let y=0; y<this.data.length; y++) {
//タイルの縦の位置
const _tileY = this.size * y + this.y;
//タイルが、画面から縦にはみ出しているとき、この下をスキップして、次から繰り返し
if ( _tileY < -1 * this.size || _tileY > canvas.height ) continue;
//マップの横方向の数だけ繰り返す
for (let x=0; x<this.data[y].length; x++) {
//タイルの横の位置
const _tileX = this.size * x + this.x
//タイルが、画面から横にはみ出しているとき、この下をスキップして、次から繰り返し
if ( _tileX < -1 * this.size || _tileX > canvas.width ) continue;
//X方向に、何番目の画像か
const _frameX = this.data[y][x] % ( this.img.width / this.size );
//Y方向に、何番目の画像か
const _frameY = ~~( this.data[y][x] / ( this.img.width / this.size ) );
//画家さん(コンテキスト)を呼ぶ
const _ctx = canvas.getContext( '2d' );
//タイルを表示
_ctx.drawImage(
this.img,
this.size * _frameX,
this.size * _frameY,
this.size,
this.size,
_tileX,
_tileY,
this.size,
this.size
);
}
}
} //render() 終了
/**
* 常に呼び出されるメソッド。空なのはオーバーライド(上書き)して使うため
*/
onenterframe() {}
}
内容はだいたいsprite.jsと同じだべけど、タイルは正方形のものを使うべから、constructorの引数にwidthやheightじゃなくて、sizeを使っているべ
そして、46〜83行目のrenderメソッドは、Spriteクラスよりも複雑になっているべよ
あ、48行目と55行目に、2度もforが使われてる!
そうなんだべ。ふつうのスプライトとの違いとして、タイルマップはタイルを大量に表示する必要があるべ。そこで、縦方向と横方向に、forで繰り返しをしながら、タイルを配置しているんだべ
さらに61〜64行目で、どのタイルを使うのかを計算しているんだべよ
このthis.data[y][x]っていうのは?
マップは数字でつくるから、その場所の数字を取得するんだべよ
どういうこと?
うーむ。まずは実際に使ってみるべ
では、このTilemapクラスを使って、タイルマップを表示してみるべよ!
js/main.js
'use strict'
//ブラウザがページを完全に読みこむまで待つ
addEventListener( 'load', () => {
//変数gameに、あなたはゲームですよ、と教える
const game = new Game();
//マップの作成
const map = [
[11,11,11,11,11,11,11,11,11,11],
[11,10,10,10,10,10,10,10,10,11],
[11, 4, 4, 4, 4, 4, 4, 4, 4,11],
[11, 4,11, 4, 4,11,11,11, 4,11],
[11, 4,11,11,11,11,10,10, 4,11],
[11, 4,11,10,10,11, 4, 4, 4,11],
[11, 4,11, 4, 4,11,11,11, 4,11],
[11, 4, 9, 4, 4, 9,10,11, 4,11],
[11, 4, 4, 4, 4, 4, 4,11, 4,11],
[11,11,11,11,11,11,11,11,11,11]
];
//歩く速さ
const WALKING_SPEED = 4;
//変数sceneに、あなたはシーンですよ、と教える
const scene = new Scene();
//変数tilemapに、あなたはタイルマップですよ、と教える
const tilemap = new Tilemap( 'img/tile.png' );
//tilemap.dataに、どんなマップなのか教える
tilemap.data = map;
//マップを登録する
scene.add( tilemap );
//変数yamadaに、あなたは山田先生のスプライト画像ですよ、と教える
const yamada = new Sprite( 'img/yamada.png' );
//sceneに、山田先生のスプライト画像を追加して、とお願いする
scene.add( yamada );
//ループから常に呼び出される
scene.onenterframe = () => {
//キーが押されたとき、山田先生が移動する
if ( game.input.left ) yamada.x -= WALKING_SPEED;
if ( game.input.right ) yamada.x += WALKING_SPEED;
if ( game.input.up ) yamada.y -= WALKING_SPEED;
if ( game.input.down ) yamada.y += WALKING_SPEED;
} //scene.onenterframe 終了
//gameに、シーンを追加して、とお願いする
game.add( scene );
//gameに、ゲームをスタートして、とお願いする
game.start();
} );
まず、9〜21行目で、マップを作成しているべよ
数字がたくさんで、むずかしそう……
むずかしくはないべ
この数字は、どのタイルを配置するかをあらわしているんだべ
こんなふうに、タイルには0〜11の数字が割り当てられていると考えればいいんだべ
さきほどアルくんが悩んでいた、this.data[y][x]の部分は、この数字を取得しているんだべよ
なるほど! これだったのか
そして、28〜33行目で、タイルマップをシーンに作っているんだべよ
タイルマップって、こうやって作ればいいのね!
ブラウザで確認すると、こうなるべ
やった。もうRPGっぽいね!
やったぁ!
キャラクターをタイルとしてあつかってみよう!
つづいて、キャラクターをタイルとしてあつかってみます。
さて……これまでわたすのスプライトは、Spriteクラスを使ってきたべよ
うん、そうだね
なにかダメなの?
うむ……いまのところ、Spriteクラスはただスプライトを表示するだけの機能しかないべ
じゃあ、タイルマップ上の壁にぶつかったときに移動できなくしたり、ゴールしたときに「ゴールだべ!」と表示するお願いはどうするべ?
あ、スプライトを表示しただけじゃ、タイルマップ上のどこにいるのかも分からないんだ……
でもどうすればいいの?
やっぱりタイルマップ上にあるものは、タイルでなくちゃいけないべ
うん、たしかにそうだよね
じゃあ、山田先生のスプライトをタイルにしちゃえばいいのね
rpg/
|-- img (省略)/
|-- index.html
|-- js/
| |-- engine/
| | |-- game.js
| | |-- scene.js
| | |-- sprite.js
| | |-- tile.js (追加)
| | `-- tilemap.js
| `-- main.js
`-- sound (省略)/
もちろん、作ったファイルはindex.htmlから読み込むべよ
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>くろねこラビリンス</title>
<style>
* {
padding: 0;
margin: 0;
}
canvas {
display: block;
}
</style>
</head>
<body>
<script src="js/engine/scene.js"></script>
<script src="js/engine/sprite.js"></script>
<script src="js/engine/tile.js"></script>
<script src="js/engine/tilemap.js"></script>
<script src="js/engine/game.js"></script>
<script src="js/main.js"></script>
</body>
</html>
さらに、tile.jsはこのようにして欲しいんだべ
js/engine/tile.js
'use strict'
/**
* タイルに関してのクラス
*/
class Tile extends Sprite {
/**
* 引数
* img : 画像ファイルまでのパス
* size : タイルの大きさ
*/
constructor( img, size ) {
//親クラスのコンストラクタを呼び出す
super( img, size, size );
//引数sizeが指定されていない場合、this.sizeに32を代入
this.size = size || 32;
} //constructor() 終了
}
あれ? 6行目にextends Spriteって書いてある……
これはどういうこと?
これは継承というものだべ
そんなむずかしい字、読めないよ……
ええっ、なんで字が分かったの!?
「けいしょう」と読むんだべ。継承……とても便利な機能だから、覚えておいて欲しいんだべ
今回の場合、Tileクラスは、Spriteクラスを継承しているんだべ
えーっと、それで、継承ってどんな機能なの?
パワーアップだべよ
ポケモンでいう、進化みたいなものだべ
進化!?
うむ。つまりTileクラスは、Spriteクラスが進化したものだべよ
では、さきほどのtile.jsの、15行目を見て欲しいべ
superって?
親クラスのコンストラクタを呼び出しているんだべ
親クラスというのは、継承元の方のクラス……今回ならば、Spriteクラスが親クラスだべ
この親クラスのことを、スーパークラスともいうから、覚えておいて欲しいべ
superには、括弧のなかにimgと、sizeってのが2つ入ってるよ
ふっふっふ。親クラスであるSpriteクラスのコンストラクタには、img、width、heightの、3つの引数があったべな?
それにたいして、Tileクラスのコンストラクタには、img、sizeの2つの引数しかないべ
これは、スプライトが長方形でも表示できるのにたいして、タイルは正方形のみを表示できるようにしているからだべ
正方形だけを表示できるように、進化してるのね!
それって退化じゃ……
てやんでぇ、べらぼうめだべ!
タイルとして使いやすいように進化してるんだべ!
じゃあ、このTileクラス、さっそく使ってみましょ
js/main.js
'use strict'
//ブラウザがページを完全に読みこむまで待つ
addEventListener( 'load', () => {
//変数gameに、あなたはゲームですよ、と教える
const game = new Game();
//マップの作成
const map = [
[11,11,11,11,11,11,11,11,11,11],
[11,10,10,10,10,10,10,10,10,11],
[11, 4, 4, 4, 4, 4, 4, 4, 4,11],
[11, 4,11, 4, 4,11,11,11, 4,11],
[11, 4,11,11,11,11,10,10, 4,11],
[11, 4,11,10,10,11, 4, 4, 4,11],
[11, 4,11, 4, 4,11,11,11, 4,11],
[11, 4, 9, 4, 4, 9,10,11, 4,11],
[11, 4, 4, 4, 4, 4, 4,11, 4,11],
[11,11,11,11,11,11,11,11,11,11]
];
//歩く速さ
const WALKING_SPEED = 4;
//変数sceneに、あなたはシーンですよ、と教える
const scene = new Scene();
//変数tilemapに、あなたはタイルマップですよ、と教える
const tilemap = new Tilemap( 'img/tile.png' );
//tilemap.dataに、どんなマップなのか教える
tilemap.data = map;
//マップを登録する
scene.add( tilemap );
//変数yamadaに、あなたは山田先生のタイルですよ、と教える
const yamada = new Tile( 'img/yamada.png' );
//sceneに、山田先生のタイルを追加して、とお願いする
scene.add( yamada );
//ループから常に呼び出される
scene.onenterframe = () => {
//キーが押されたとき、山田先生が移動する
if ( game.input.left ) yamada.x -= WALKING_SPEED;
if ( game.input.right ) yamada.x += WALKING_SPEED;
if ( game.input.up ) yamada.y -= WALKING_SPEED;
if ( game.input.down ) yamada.y += WALKING_SPEED;
} //scene.onenterframe 終了
//gameに、シーンを追加して、とお願いする
game.add( scene );
//gameに、ゲームをスタートして、とお願いする
game.start();
} );
実行結果はさきほどと変わりませんが、ブラウザで確認すると、このようになります。
36行目のSpriteをTileに変更したべ
あれ、Tileクラスには、updateメソッドも、renderメソッドもなかったような……
どうして山田先生のタイルが表示されるの?
ふっふっふ。TileクラスはSpriteクラスが進化したものだからだべ
もしかして、Spriteクラスのupdateメソッドやrenderメソッドが、Tileクラスでも使えるってこと!?
そうだべ。TileクラスにはSpriteクラスの能力がそのまま引き継がれているんだべよ
そうなんだ、継承ってすごい!
しかし……main.jsの38行目を見て欲しいべ
タイルをシーンに追加してるところだ
でも、なにかダメなの?
タイルはタイルマップ上に存在するものだべ
タイルと一緒に移動したり、タイルマップ上の何番目のタイルに、そのタイルがあるのかを取得したり……
タイルとタイルマップを、別々にシーンに追加していては、いろいろと不便だべよ
そっかぁ。でもどうすればいいの?
これから教えるべよ!
タイルマップにタイルを追加できるようにしてみよう!
つづいて、タイルをシーンではなく、タイルマップに追加できるようにしてみましょう!
さて、さきほどはわたすのスプライトを、タイルとしてあつかってみたべ
継承のやり方も覚えたね
しかしだべ……タイルはシーンよりも、タイルマップに追加したほうが便利になるべな
そっか、タイルマップに追加すればよかったのね!
では、Tilemapクラスに、タイルを追加するためのメソッドを作っていくべ!
js/engine/tilemap.js
'use strict'
/**
* タイルマップに関するクラス
*/
class Tilemap {
/**
* 引数
* img : 画像ファイルまでのパス
* size : タイルひとつの大きさ(一辺の長さ)
*
* タイルひとつは正方形にする
*/
constructor( img, size ) {
//Imageのインスタンスを作成
this.img = new Image();
//this.img.srcに画像ファイルまでのパスを代入
this.img.src = img;
//画像の初期位置
this.x = this.y = 0;
//引数sizeが指定されていない場合、this.sizeに32を代入
this.size = size || 32;
//二次元配列で数値を入力すると、マップをつくることができる
this.data = [];
//タイルマップに重ねるように置きたいタイルを追加できる
this.tiles = [];
} //constructor() 終了
/**
* タイルマップの上にタイルを重ねるように追加できるメソッド
*
* 引数
* tile : 追加したいタイル
*/
add( tile ) {
//引数がTileのとき、this.tilesの末尾にtileを追加
if ( tile instanceof Tile ) this.tiles.push( tile );
//引数がTileでなければ、コンソールにエラーを表示
else console.error( 'Tilemapに追加できるのはTileだけだよ!' );
} //add() 終了
/**Gameクラスのメインループからずっと呼び出され続ける
*
* 引数
* canvas : 紙(キャンバス)
*/
update( canvas ) {
//画像などを画面に表示するためのメソッドを呼び出す
this.render( canvas );
//常に呼び出される、オーバーライド用のメソッドを呼び出す
this.onenterframe();
//タイルの数だけ繰り返す
for ( let i=0; i<this.tiles.length; i++ ) {
//それぞれのタイルのupdateメソッドを呼び出す
this.tiles[i].update( canvas );
}
} //update() 終了
/**
* Gameクラスのメインループからずっと呼び出され続ける。画像を表示したりするためのメソッド
*
* 引数
* canvas : 紙(キャンバス)
*/
render( canvas ) {
//マップの縦方向の数だけ繰り返す
for (let y=0; y<this.data.length; y++) {
//タイルの縦の位置
const _tileY = this.size * y + this.y;
//タイルが、画面から縦にはみ出しているとき、この下をスキップして、次から繰り返し
if ( _tileY < -1 * this.size || _tileY > canvas.height ) continue;
//マップの横方向の数だけ繰り返す
for (let x=0; x<this.data[y].length; x++) {
//タイルの横の位置
const _tileX = this.size * x + this.x
//タイルが、画面から横にはみ出しているとき、この下をスキップして、次から繰り返し
if ( _tileX < -1 * this.size || _tileX > canvas.width ) continue;
//X方向に、何番目の画像か
const _frameX = this.data[y][x] % ( this.img.width / this.size );
//Y方向に、何番目の画像か
const _frameY = ~~( this.data[y][x] / ( this.img.width / this.size ) );
//画家さん(コンテキスト)を呼ぶ
const _ctx = canvas.getContext( '2d' );
//タイルを表示
_ctx.drawImage(
this.img,
this.size * _frameX,
this.size * _frameY,
this.size,
this.size,
_tileX,
_tileY,
this.size,
this.size
);
}
}
} //render() 終了
/**
* 常に呼び出されるメソッド。空なのはオーバーライド(上書き)して使うため
*/
onenterframe() {}
}
まず27行目で、タイルマップに重ねて配置したいタイルを入れておくためのものを、準備しているんだべ
ふむふむ
そして36〜41行目が、そのタイルを追加するためのメソッドだべ
addメソッドを呼び出すことで、タイルを追加できるのね!
あ、追加できるのはTileだけに制限されてる!
そうだべよ
そして追加したタイルのそれぞれのupdateメソッドを、55〜58行目で呼び出しているんだべ
そっか。このおかげで、追加したタイルを重ねて表示できるんだ
じゃあ、実際にタイルマップにタイルを追加してみるべよ
js/main.js
'use strict'
//ブラウザがページを完全に読みこむまで待つ
addEventListener( 'load', () => {
//変数gameに、あなたはゲームですよ、と教える
const game = new Game();
//マップの作成
const map = [
[11,11,11,11,11,11,11,11,11,11],
[11,10,10,10,10,10,10,10,10,11],
[11, 4, 4, 4, 4, 4, 4, 4, 4,11],
[11, 4,11, 4, 4,11,11,11, 4,11],
[11, 4,11,11,11,11,10,10, 4,11],
[11, 4,11,10,10,11, 4, 4, 4,11],
[11, 4,11, 4, 4,11,11,11, 4,11],
[11, 4, 9, 4, 4, 9,10,11, 4,11],
[11, 4, 4, 4, 4, 4, 4,11, 4,11],
[11,11,11,11,11,11,11,11,11,11]
];
//歩く速さ
const WALKING_SPEED = 4;
//変数sceneに、あなたはシーンですよ、と教える
const scene = new Scene();
//変数tilemapに、あなたはタイルマップですよ、と教える
const tilemap = new Tilemap( 'img/tile.png' );
//tilemap.dataに、どんなマップなのか教える
tilemap.data = map;
//マップを登録する
scene.add( tilemap );
//変数yamadaに、あなたは山田先生のタイルですよ、と教える
const yamada = new Tile( 'img/yamada.png' );
//tilemapに、山田先生のタイルを追加して、とお願いする
tilemap.add( yamada );
//ループから常に呼び出される
scene.onenterframe = () => {
//キーが押されたとき、山田先生が移動する
if ( game.input.left ) yamada.x -= WALKING_SPEED;
if ( game.input.right ) yamada.x += WALKING_SPEED;
if ( game.input.up ) yamada.y -= WALKING_SPEED;
if ( game.input.down ) yamada.y += WALKING_SPEED;
} //scene.onenterframe 終了
//gameに、シーンを追加して、とお願いする
game.add( scene );
//gameに、ゲームをスタートして、とお願いする
game.start();
} );
38行目の、タイルの追加部分を、タイルマップに追加するように変更してみたべ
実行結果に変わりはないだべけど、ブラウザで確認するとこうなるべ
移動のとき、キャラクターではなく、マップがスクロールするようにしてみよう!
つづいて、移動のとき、キャラクターではなくマップが移動するようにしてみたいと思います。
さてアルくん……
は、はいっ
もしもっと大きいマップにしたいとき、どうすればいいと思うべ?
うーん、キャンバスからはみ出ちゃうよね……そうだ、キャンバスを大きくする!
てやんでぇ、べらぼうめだべ!
こんどはキャンバスが画面からはみ出るべ
はっ……たしかに
ふふっ、アルったらまだまだね
むむ……じゃあ、りこちゃんならどうするのさ
マップの方を動かせばいいんじゃない?
あ、よく考えたら、ポケモンもドラクエも、マップの方が動いてる!
りこちゃん、正解だべ
では、方向キーが押されたときは、キャラクターじゃなくてマップの方が動くように、プログラムを作りかえていくべ
js/main.js
'use strict'
//ブラウザがページを完全に読みこむまで待つ
addEventListener( 'load', () => {
//変数gameに、あなたはゲームですよ、と教える
const game = new Game();
//マップの作成
const map = [
[11,11,11,11,11,11,11,11,11,11],
[11,10,10,10,10,10,10,10,10,11],
[11, 4, 4, 4, 4, 4, 4, 4, 4,11],
[11, 4,11, 4, 4,11,11,11, 4,11],
[11, 4,11,11,11,11,10,10, 4,11],
[11, 4,11,10,10,11, 4, 4, 4,11],
[11, 4,11, 4, 4,11,11,11, 4,11],
[11, 4, 9, 4, 4, 9,10,11, 4,11],
[11, 4, 4, 4, 4, 4, 4,11, 4,11],
[11,11,11,11,11,11,11,11,11,11]
];
//歩く速さ
const WALKING_SPEED = 4;
//変数sceneに、あなたはシーンですよ、と教える
const scene = new Scene();
//変数tilemapに、あなたはタイルマップですよ、と教える
const tilemap = new Tilemap( 'img/tile.png' );
//tilemap.dataに、どんなマップなのか教える
tilemap.data = map;
//マップを登録する
scene.add( tilemap );
//変数yamadaに、あなたは山田先生のタイルですよ、と教える
const yamada = new Tile( 'img/yamada.png' );
//tilemapに、山田先生のタイルを追加して、とお願いする
tilemap.add( yamada );
//ループから常に呼び出される
scene.onenterframe = () => {
//キーが押されたとき、山田先生(マップ)が移動する
if ( game.input.left ) tilemap.x += WALKING_SPEED;
if ( game.input.right ) tilemap.x -= WALKING_SPEED;
if ( game.input.up ) tilemap.y += WALKING_SPEED;
if ( game.input.down ) tilemap.y -= WALKING_SPEED;
} //scene.onenterframe 終了
//gameに、シーンを追加して、とお願いする
game.add( scene );
//gameに、ゲームをスタートして、とお願いする
game.start();
} );
42〜46行目で、わたすのタイルではなく、タイルマップが動くようにを変更したべよ
ブラウザで確認すると、こうなるべ
わぁ、山田先生が動いてるように見える!
うーん、でも先生の位置がすみっこだから、見た目がよくないね
そうだべな
では、その位置をなおしていくべよ!
キャラクターとマップの初期位置を調節しよう!
つづいて、キャラクターとマップの最初の位置を、調節してみましょう!
今の状態では、わたすのタイルが左上にあり、しかもゲームがはじまったときは壁の上に乗ってしまってる状態だべ
いきなり壁の上からはじまったら、どうすればいいのか分からないよね
そこで、キャラクターとマップの初期位置をなおしていくべ!
js/main.js
'use strict'
//ブラウザがページを完全に読みこむまで待つ
addEventListener( 'load', () => {
//変数gameに、あなたはゲームですよ、と教える
const game = new Game();
//マップの作成
const map = [
[11,11,11,11,11,11,11,11,11,11],
[11,10,10,10,10,10,10,10,10,11],
[11, 4, 4, 4, 4, 4, 4, 4, 4,11],
[11, 4,11, 4, 4,11,11,11, 4,11],
[11, 4,11,11,11,11,10,10, 4,11],
[11, 4,11,10,10,11, 4, 4, 4,11],
[11, 4,11, 4, 4,11,11,11, 4,11],
[11, 4, 9, 4, 4, 9,10,11, 4,11],
[11, 4, 4, 4, 4, 4, 4,11, 4,11],
[11,11,11,11,11,11,11,11,11,11]
];
//タイルのサイズ
const TILE_SIZE = 32;
//歩く速さ
const WALKING_SPEED = 4;
//変数sceneに、あなたはシーンですよ、と教える
const scene = new Scene();
//変数tilemapに、あなたはタイルマップですよ、と教える
const tilemap = new Tilemap( 'img/tile.png' );
//tilemap.dataに、どんなマップなのか教える
tilemap.data = map;
//マップ全体の位置をずらす
tilemap.x = TILE_SIZE*4 - TILE_SIZE/2;
tilemap.y = TILE_SIZE*3 - TILE_SIZE/2;
//マップを登録する
scene.add( tilemap );
//変数yamadaに、あなたは山田先生のタイルですよ、と教える
const yamada = new Tile( 'img/yamada.png' );
//山田先生を画面の中央に配置
yamada.x = yamada.y = TILE_SIZE*5 - TILE_SIZE/2;
//tilemapに、山田先生のタイルを追加して、とお願いする
tilemap.add( yamada );
//ループから常に呼び出される
scene.onenterframe = () => {
//キーが押されたとき、山田先生(マップ)が移動する
if ( game.input.left ) tilemap.x += WALKING_SPEED;
if ( game.input.right ) tilemap.x -= WALKING_SPEED;
if ( game.input.up ) tilemap.y += WALKING_SPEED;
if ( game.input.down ) tilemap.y -= WALKING_SPEED;
} //scene.onenterframe 終了
//gameに、シーンを追加して、とお願いする
game.add( scene );
//gameに、ゲームをスタートして、とお願いする
game.start();
} );
まず23行目で、TILE_SIZEに32を代入してるのね
うむ。タイルのサイズは一辺32pxに固定だべから、定数に代入しておくと、プログラムが分かりやすくなるべな
さらに35行目では、タイル4つ分から半分を引いた分、マップを右にずらしてるんだべ
そして36行目では、タイル3つ分から半分を引いた分、マップを下にずらしてるんだべよ
これでタイルマップの位置を調節してるんだ
そして43行目で、わたすのタイルを、キャンバスの中心になるように設定してるんだべ
キャンバス全体に表示できるタイルの数は、縦横10まいだべから、タイル5つ分から半分を引いた位置が、ちょうどキャンバスの中心になるべよ
ブラウザで確認すると、こうなるべ!
つぎのページでは、キャラクターを移動させるための機能をつくったり、タイルの間隔ずつ移動させられるようにしていきます。
このシリーズの一覧はこちら
- 小学生からのプログラミング入門。プログラミングってなぁに?
- Scratchの使い方と、ゲーム作りの基礎知識を学ぼう! 小学生からのプログラミング入門
- Scratchでじゃんけんゲームを作ろう! 小学生からのプログラミング入門
- Scratchでシューティングゲームを作ろう! 小学生からのプログラミング入門
- Scratchでピアノ鍵盤を作って音を鳴らそう! 小学生からのプログラミング入門
- テキストエディタ(Visual Studio Code)をインストールしてみよう! 小学生からのプログラミング入門
- Visual Studio Codeを日本語化してみよう! 小学生からのプログラミング入門
- JavaScriptでおみくじを作ろう! 小学生からのプログラミング入門
- JavaScriptで今月の残り日数を計算してみよう! 小学生からのプログラミング入門
- JavaScriptで画像を表示してみよう! 小学生からのプログラミング入門
- JavaScriptで画像を移動してみよう! 小学生からのプログラミング入門
- 【JavaScript】キー入力でキャラを動かしてみよう! 小学生からのプログラミング入門
- 【JavaScript】ファイルを分けて管理してみよう! 小学生からのプログラミング入門
- 【JavaScript】オブジェクトを使ってみよう! 小学生からのプログラミング入門
- 【JavaScript】ゲームのメインループを作ってみよう! 小学生からのプログラミング入門
- 【JavaScript】キャラを決まった間隔ずつ動かす! 小学生からのプログラミング入門
- HTML5とCanvasを使ってみよう! 小学生からのプログラミング入門
- 【JavaScript】迷路やRPGで使えるマップを作ってみよう! 小学生からのプログラミング入門
- 【JavaScript】マップでキャラを動かせるようにしよう! 小学生からのプログラミング入門
- 【JavaScript】クラスの概念をしっかりと理解しよう! 小学生からのプログラミング入門
- 【JavaScript】プログラム全体をクラスを使って作ってみよう! 小学生からのプログラミング入門
- 【JavaScript】文字を表示するクラスを作ってみよう! 小学生からのプログラミング入門
- 【JavaScript】改行と一文字ずつ画面に表示する方法! 小学生からのプログラミング入門
- 【JavaScript】ノベルゲーム風にキー入力で文字を切り替える方法! 小学生からのプログラミング入門
- JavaScriptでRPGを作ろう!スマホにも対応したゲームの作り方
- webpackを使ってゲームエンジンを作ろう!(JSライブラリの作り方)
- WindowsにPythonをインストールしてみよう!小学生からのPython入門
- MacにPythonをインストールしてみよう!小学生からのPython入門
- Pythonでじゃんけんゲームを作ってみよう!小学生からのPython入門
- Pythonのtkinterを使って、ウィンドウを表示してみよう!
- Pythonのtkinterで、画像つきのおみくじゲームを作ろう!