小学生からのプログラミング講座、第13弾です。
前回はプログラミングにおける、クラスの使い方を学びました。
しかし、まだクラスをどうやって使えばいいのか、ピンときていないかもしれません。
そこで今回は、これまで作成してきたゲームを、クラスを使ったものに書き換えていきたいと思います。

クラスを使うと、プログラムがとても見やすいものになるんだべ

どうプログラムが変わっていくんだろう? 楽しみ!
スプライトクラスを作ろう!
スプライトは「動かしたい画像」のことです。
Scratchにもあったスプライトと同じです。ではスプライトのためのクラスを作ってみましょう。
class Sprite { constructor( img, left, top ) { this.left = left || 0; this.top = top || 0; this.img = new Image(); this.img.src = img; this.width = 32; this.height = 32; } }
2行目、コンストラクタの部分に、img、left、topというふうに書かれています。
これは「どの画像」の「左から何px」「上から何px」の部分かを指定するものです。
では次の画像を使うとします。

りこちゃん、山田先生、アル君が、1つの画像のなかにあります。
この中から、アル君のスプライトを作りたいとします。
するとアル君は左から65px、上から0pxの場所にありますので、その場所を指定してあげます。

スプライトを作りたいと思ったら、さっき作ったスプライトクラスのメンバーに入れてあげれば、スプライトになるんだべ

どうやってやるんだっけ?

こんなふうにすればいいべ!
let aru = new Sprite( 'img/character.png', 65, 0 );
let
というのは ES6から使えるようになった、変数を使うよと宣言するためのコマンドです。
使い方はvar
と同じですが、変数の有効範囲が異なります。
let
でaruを宣言し、aruをSpriteクラスのメンバーに入れてあげます。
Spriteの後ろには、()をつけて、画像のパスと画像のどの部分をスプライトにするかを指定します。
そうすることで、アル君のスプライトが作られるのです。
今回は1つの画像を縦横32pxの大きさにあらかじめ決めてあるので、左と上のpx数だけ指定すればその画像が表示されます。

でもこれだとまだスプライトは表示されないよ

じつはそうなんだべ。そこでゲームクラスを作って、スプライトをゲーム上に表示できるようにするべ
ゲームクラスを作ろう!
さて、スプライトクラスには、ゲーム上にスプライトを表示させる機能をつけていません。
スプライトの表示はゲームクラスに作っていきます。
class Game { constructor( width, height ) { this.width = width || 320; this.height = height || 320; canvas = document.getElementById( 'canvas' ); canvas.width = this.width; //canvasの横幅(よこはば) canvas.height = this.height; //canvasの縦幅(たてはば ctx = canvas.getContext( '2d' ); } add( sprite, x, y ) { if ( typeof x === "undefined" ) sprite.x = 0; else sprite.x = x; if ( typeof y === "undefined" ) sprite.y = 0; else sprite.y = y; ctx.drawImage( sprite.img, sprite.left, sprite.top, sprite.width, sprite.height, sprite.x, sprite.y ,sprite.width, sprite.height ); } }
ゲームクラスでは、実際のゲームで使うcanvasの表示や設定などを行います。
また、14〜20行目で、add()を使ってスプライトをゲーム上に表示できるようにしています。
以下のようにすると縦横640pxのゲームの画面をつくることができます。
let game = new Game( 640, 640 );
りこちゃん、山田先生、アル君のオブジェクトを作成し、さきほどゲームクラスで作成したadd()
を使って、メインループ内でスプライトを呼び出します。
〜省略(さきほど作ったクラスや、グローバル変数)〜 let game = new Game( 640, 640 ); let rico = new Sprite( 'img/character.png' ); let yamada = new Sprite( 'img/character.png', 33, 0 ); let aru = new Sprite( 'img/character.png', 65, 0 ); function main() { //キャラクターのスプライトを表示 game.add( rico, 0, 0 ); game.add( aru, 32, 64 ) game.add( yamada, 96, 96 ); requestAnimationFrame( main ); } addEventListener('load', main(), false);

あらかじめクラスを作っておけば、こんなに簡単にゲームの画面やスプライトを表示できるようになるのね!

ブラウザで確認すると、こんなふうになるべ


わー、僕たち3人が表示されてる!
入力(Input)クラスを作ろう!
続いて、Inputクラスを作ってみます。
Inputは「入力する」という意味で、キー入力のためのクラスとします。
class Input { constructor() { this.up = false; this.left = false; this.down = false; this.right = false; } push_key() { addEventListener( "keydown", () => { const key_code = event.keyCode; if( key_code === 37 ) this.left = true; if( key_code === 38 ) this.up = true; if( key_code === 39 ) this.right = true; if( key_code === 40 ) this.down = true; event.preventDefault(); //方向キーでブラウザがスクロールしないようにする }, false); addEventListener( "keyup", () => { const key_code = event.keyCode; if( key_code === 37 ) this.left = false; if( key_code === 38 ) this.up = false; if( key_code === 39 ) this.right = false; if( key_code === 40 ) this.down = false; }, false); } }
このInputクラスは、あらかじめよく使うと思うボタンを設定しておいて、そのボタンが押されているかどうかを判断するものです。
今回はそれぞれの方向キーが押されているかどうかを判断できるようにしました。
inputオブジェクトを作ります。
let input = new Input();
あとは、push_key()を呼び出し、条件分岐でキーが入力されたときにどうしたいのかを書いていきます。
例えばこのようにすると、左キーが押されている間xから6ずつ引いていくというプログラムになります。
function main() { input.push_key(); if ( input.left === true ) x-=6; requestAnimationFrame( main ); } addEventListener('load', main(), false);

これでキャラ移動もつくれそうだね!
プログラム全体をクラスを使って書いてみよう!
では、プログラム全体をクラスを使って書いてみます。
'use strict'; //グローバル変数の定義 let canvas; let ctx; //マップの作成(さくせい) let 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] ] //スプライトクラス //img : スプライトに使う画像 //left : 画像の左から何ピクセルの部分を使うか //top : 画像の上から何ピクセルの部分を使うか class Sprite { constructor( img, left, top ) { this.left = left || 0; this.top = top || 0; this.img = new Image(); this.img.src = img; this.width = 32; this.height = 32; } } //ゲームクラス //width : ゲーム全体の横幅 //height : ゲーム全体の縦幅 // //add() : ゲームにスプライトを表示 class Game { constructor( width, height ) { this.width = width || 320; this.height = height || 320; canvas = document.getElementById( 'canvas' ); canvas.width = this.width; //canvasの横幅(よこはば) canvas.height = this.height; //canvasの縦幅(たてはば ctx = canvas.getContext( '2d' ); } add( sprite, x, y ) { if ( typeof x === "undefined" ) sprite.x = 0; else sprite.x = x; if ( typeof y === "undefined" ) sprite.y = 0; else sprite.y = y; ctx.drawImage( sprite.img, sprite.left, sprite.top, sprite.width, sprite.height, sprite.x, sprite.y ,sprite.width, sprite.height ); } } //入力(Input)クラス //up : 上キー //left : 左キー //down : 下キー //right : 右キー class Input { constructor() { this.up = false; this.left = false; this.down = false; this.right = false; } push_key() { addEventListener( "keydown", () => { const key_code = event.keyCode; if( key_code === 37 ) this.left = true; if( key_code === 38 ) this.up = true; if( key_code === 39 ) this.right = true; if( key_code === 40 ) this.down = true; event.preventDefault(); //方向キーでブラウザがスクロールしないようにする }, false); addEventListener( "keyup", () => { const key_code = event.keyCode; if( key_code === 37 ) this.left = false; if( key_code === 38 ) this.up = false; if( key_code === 39 ) this.right = false; if( key_code === 40 ) this.down = false; }, false); } } //inputオブジェクトの作成 let input = new Input(); //プレイヤークラス //x : プレイヤーのx座標 //y : プレイヤーのy座標 //move : プレイヤーをうまく動かすためのもの // //move_sp() : プレイヤーのスプライトを動かす class Player { constructor(x, y) { this.sprite = new Sprite( 'img/character.png' ); this.x = x; this.y = y; this.move = 0; } move_sp() { input.push_key(); game.add( this.sprite, this.x, this.y ); if ( this.move === 0 ) { if ( input.left === true ) { var x = this.x/32; var y = this.y/32; x--; if ( map[y][x] === 0 ) { this.move = 32; input.push = 'left'; } } if ( input.up === true ) { var x = this.x/32; var y = this.y/32; if ( y > 0) { y--; if ( map[y][x] === 0 ) { this.move = 32; input.push = 'up'; } } } if ( input.right === true ) { var x = this.x/32; var y = this.y/32; x++; if ( map[y][x] === 0 ) { this.move = 32; input.push = 'right'; } } if ( input.down === true ) { var x = this.x/32; var y = this.y/32; if ( y < 19 ) { y++; if ( map[y][x] === 0 ) { this.move = 32; input.push = 'down'; } } } } //this.moveが0より大きい場合は、4pxずつ移動(いどう)を続ける if (this.move > 0) { this.move -= 4; if ( input.push === 'left' ) this.x -= 4; if ( input.push === 'up' ) this.y -= 4; if ( input.push === 'right' ) this.x += 4; if ( input.push === 'down' ) this.y += 4; } } } //ゲームオブジェクトの作成 let game = new Game( 640, 640 ); //プレイヤーのオブジェクトを作成 let player = new Player( 0, 0 ); //キャラクターのオブジェクトを作成 let yamada = new Sprite( 'img/character.png', 33, 0 ); let aru = new Sprite( 'img/character.png', 65, 0 ); //床、壁のマップチップのオブジェクトを作成 let floor = new Sprite( 'img/map.png', 0, 0 ); let wall = new Sprite( 'img/map.png', 33, 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 ) game.add( floor, 32*x, 32*y ); if ( map[y][x] === 1 ) game.add( wall, 32*x, 32*y ); } } //キャラクターのスプライトを表示 player.move_sp(); game.add( aru, 32, 64 ); game.add( yamada, 96, 96 ); requestAnimationFrame( main ); } addEventListener('load', main(), false);

まとめ
今回はプログラム全体を、クラスを使ったものに書き換えてみました。
クラスを使うことで、ソースコードが綺麗に整理され、後からみたときも分かりやすくなります。
ぜひクラス使い方をマスターしましょう!

スプライトクラスを作っておくと、簡単にスプライトをつくることができるべ。 クラスの便利さはわかってもらえたべか?

うん、クラスって便利なんだね

どこに何が書いてあったか悩むのも少なくなるね

今回はわだずやアル君のスプライトも表示したべけど、まだ突っ立っているだけなんだべよ

なにか喋ったりとかさせたいよね

みんなで一緒に冒険にでかけるのもいいべ。 どんどんゲームらしくなるから、今後の記事を楽しみにするべよ

はーい!

はーい!
この企画の一覧はこちら
- 小学生からのプログラミング入門。プログラミングってなぁに?
- Scratchの使い方と、ゲーム作りの基礎知識を学ぼう! 小学生からのプログラミング入門
- Scratchでじゃんけんゲームを作ろう! 小学生からのプログラミング入門
- Scratchでシューティングゲームを作ろう! 小学生からのプログラミング入門
- Scratchでピアノ鍵盤を作って音を鳴らそう! 小学生からのプログラミング入門
- JavaScriptでおみくじを作ろう! 小学生からのプログラミング入門
- JavaScriptで今月の残り日数を計算してみよう! 小学生からのプログラミング入門
- JavaScriptで画像を表示してみよう! 小学生からのプログラミング入門
- JavaScriptで画像を移動してみよう! 小学生からのプログラミング入門
- 【JavaScript】キー入力でキャラを動かしてみよう! 小学生からのプログラミング入門
- 【JavaScript】ファイルを分けて管理してみよう! 小学生からのプログラミング入門
- 【JavaScript】オブジェクトを使ってみよう! 小学生からのプログラミング入門
- 【JavaScript】ゲームのメインループを作ってみよう! 小学生からのプログラミング入門
- 【JavaScript】キャラを決まった間隔ずつ動かす! 小学生からのプログラミング入門
- HTML5とCanvasを使ってみよう! 小学生からのプログラミング入門
- 【JavaScript】迷路やRPGで使えるマップを作ってみよう! 小学生からのプログラミング入門
- 【JavaScript】マップでキャラを動かせるようにしよう! 小学生からのプログラミング入門
- 【JavaScript】クラスの概念をしっかりと理解しよう! 小学生からのプログラミング入門
- 【JavaScript】プログラム全体をクラスを使って作ってみよう! 小学生からのプログラミング入門
- 【JavaScript】文字を表示するクラスを作ってみよう! 小学生からのプログラミング入門
- 【JavaScript】改行と一文字ずつ画面に表示する方法! 小学生からのプログラミング入門
- 【JavaScript】ノベルゲーム風にキー入力で文字を切り替える方法! 小学生からのプログラミング入門
- JavaScriptでRPGを作ろう!スマホにも対応したゲームの作り方