こんにちは。
ECF Techブログ
担当 Michiharu.Tです。
JavaScriptゲームフレームワーク、Phaserを使ったプログラミングの第3回です。今回は、前回作ったプログラムをオブジェクト指向プログラミングっぽくリメイクしていきます。
本記事は前回の続編の位置づけとなります。前回の記事は下記からご確認ください。
また、使用している魔法使いの画像はぴぽや倉庫さんの素材を利用しています。素晴らしい2D向け素材が満載です。
JavaScriptはOOPに特化した言語ではないのでやや工夫が必要になりますが、JavaScriptでのオブジェクト指向的プログラミングの手法も併せて解説できればと思っています。よろしくお願いします。
対象読者
- JavaScriptの基本的なプログラミング経験者
- オブジェクト指向プログラミングの基本を知っている方
- Webの2Dゲームフレームワークを使ってみたい方
JavaScriptによるオブジェクト指向プログラミング
まずは簡単な例で、JavaScriptによるオブジェクト指向プログラミングを見ていきたいと思います。
下はクラス(もどき)の定義例です。
Player = function(name){ this.name = name; this.hp = 10; } Player.prototype.sayName = function(){ console.log( 'こんにちは' + this.name + 'です。'); }
name
やhp
がフィールド、sayName
がメソッドとなります。
下のようなコードを実行することで、インスタンスの生成とそれぞれのインスタンスでのメソッド実行ができます。
var taro = new Player('タロウ'); var hanako = new Player('ハナコ'); //メソッドの実行 taro.sayName(); hanako.sayName();
実行結果
こんにちはタロウです。 こんにちはハナコです。
この実装方法が基本になります。
このオブジェクト指向プログラミングの実装方法は、MDN Web Docs(下記リンク)でご覧いただけます。Web技術の入門として大変オススメです。ぜひご覧ください。
アクションゲームの作成
クラスの作成
それではまず、プレイヤーのクラスを作成します。クラス名はPlayerとします。コードは次のとおりです。
/*--------------------------------------------*/ // Playerクラス /*--------------------------------------------*/ Player = function (phaser) { //アニメーションの構築 phaser.anims.create({ //左移動 key: 'witch_left', frames: phaser.anims.generateFrameNumbers('witch', { start: 3, end: 5}), frameRate: 5, repeat: -1 }); phaser.anims.create({ //右移動 key: 'witch_right', frames: phaser.anims.generateFrameNumbers('witch', { start: 6, end: 8 }), frameRate: 5, repeat: -1 }); //Phaserスプライトの設定 this.pSprite = phaser.physics.add.sprite(400, 300, 'witch'); //画面の端を壁と判断する設定 this.pSprite.setCollideWorldBounds(true); }
- 引数
phaser
は、Phaserフレームワークの機能を利用するためのオブジェクトです。 phaser
のメソッドを利用し、アニメーションの設定を行なっています。phaser
のメソッドを利用し、スプライトの作成とスプライトへの物理演算情報の設定を行なっています。
つづいてPlayerのメソッドを追加します。
/** * 左移動 */ Player.prototype.goLeft = function () { this.pSprite.setVelocityX(-100); this.pSprite.anims.play('witch_left',true); } /** * 右移動 */ Player.prototype.goRight = function () { this.pSprite.setVelocityX(100); this.pSprite.anims.play('witch_right',true); } /** * 停止 */ Player.prototype.stand = function () { this.pSprite.setVelocityX(0); } /** * ジャンプ */ Player.prototype.jump = function () { this.pSprite.setVelocityY(-300); }
- 左右移動、停止、ジャンプの4つのメソッドを作成しています。
this.pSprite
はphaserのスプライトですので、各メソッドが利用できます。setVelocityX
とsetVelocityY
はそれぞれの方向へ働く力です。- 左右移動ではアニメーションを開始します。
シーンの作成
シーン(scene)は、ゲームにおける各画面を定義するオブジェクトです。タイトル画面、プレイ画面、キャラクター選択画面などはすべて1つ1つのシーンとなります。
今回のプレイ画面となるシーンは次のようになります。
class Playing extends Phaser.Scene { constructor() { super('Playing'); } preload() { //背景の画像 this.load.image('back', 'assets/back.png'); //魔法使い this.load.spritesheet('witch', 'assets/witch.png', { frameWidth: 32, frameHeight: 32 } ); } create = function () { //背景の設定 this.add.image(400, 300, 'back'); //プレイヤースプライトの作成 MyObj.player = new Player(this,400,300); } update = function () { //左キーが押された時 if (MyObj.cursor.left.isDown) { MyObj.player.goLeft(); player.anims.play('left', true); } //右キーが押された時 else if (MyObj.cursor.right.isDown) { MyObj.player.goRight(); player.anims.play('right', true); } } }
- JavaScriptのクラス構文を用いています。
Phaser.Scene
を継承して作成する必要があります。 preload
、create
、update
の3つの関数を実装します。preload
関数では必要な画像を読み込みます。プレイヤーとなる魔法使いと背景の画像を読み込んでいます。- createは、ゲーム内のオブジェクトを生成・登場させる部分です。phaserのメソッドを利用し、背景と魔法つかいを登場させています。new演算でPlayerオブジェクトを生成している点に注目です。
class
やextends
というオブジェクト指向らしいキーワードが登場していますが、最初に述べたとおりJavaScriptに明確にクラスという概念は存在しません。これらは糖衣構文(Sugar Syntax)と呼ばれるものです。こちらも詳細はMDN Web Docsなどをご覧ください。ゲームの準備
次に起動の準備をしましょう。ゲームで扱うオブジェクトを入れておく変数とphaserのゲーム起動のプログラムを追加します。
//ゲーム内で取り扱うグローバルなオブジェクト入れ物 var MyObj = {} //phaserゲームの起動 var GameMain = new Phaser.Game({ type: Phaser.AUTO, width: 800, height: 600, //物理エンジンの設定 physics: { default: 'arcade', arcade: { gravity: { y: 200 }, debug: false } }, scene:[Playing] });
MyObj
はゲームに使うオブジェクトをまとめて入れておく入れ物です。new Phaser.Game(
以降の記述については、前回の記事にまとめておりますのでご覧ください。scene:[Playing]
は、実行するシーンを指定しています。
ソースコード全文
では、ここまでのソースコード全文を示します。動作確認用のHTMLもありますので、ぜひ動作させてみてください。
(classes.js)
/*--------------------------------------------*/ // Playerクラス /*--------------------------------------------*/ Player = function (phaser) { //アニメーションの構築 phaser.anims.create({ //左移動 key: 'witch_left', frames: phaser.anims.generateFrameNumbers('witch', { start: 3, end: 5}), frameRate: 5, repeat: -1 }); phaser.anims.create({ //右移動 key: 'witch_right', frames: phaser.anims.generateFrameNumbers('witch', { start: 6, end: 8 }), frameRate: 5, repeat: -1 }); //Phaserスプライトの設定 this.pSprite = phaser.physics.add.sprite(400, 300, 'witch'); //画面の端を壁と判断する設定 this.pSprite.setCollideWorldBounds(true); } /** * 左移動 */ Player.prototype.goLeft = function () { this.pSprite.setVelocityX(-100); this.pSprite.anims.play('witch_left',true); } /** * 右移動 */ Player.prototype.goRight = function () { this.pSprite.setVelocityX(100); this.pSprite.anims.play('witch_right',true); } /** * 停止 */ Player.prototype.stand = function () { this.pSprite.setVelocityX(0); } /** * ジャンプ */ Player.prototype.jump = function () { this.pSprite.setVelocityY(-300); }
(game.js)
class Playing extends Phaser.Scene { constructor() { super('Playing'); } preload() { //背景の画像 this.load.image('back', 'assets/back.png'); //魔法使い this.load.spritesheet('witch', 'assets/witch.png', { frameWidth: 32, frameHeight: 32 } ); } create = function () { //背景の設定 this.add.image(400, 300, 'back'); //プレイヤースプライトの作成 MyObj.player = new Player(this, 400, 300); //キーボードイベント取得オブジェクト MyObj.cursor = this.input.keyboard.createCursorKeys(); } update = function () { //左キーが押された時 if (MyObj.cursor.left.isDown) { MyObj.player.goLeft(); } //右キーが押された時 else if (MyObj.cursor.right.isDown) { MyObj.player.goRight(); } } } //ゲーム内で取り扱うグローバルなオブジェクト入れ物 var MyObj = {} //phaserゲームの起動 var GameMain = new Phaser.Game({ type: Phaser.AUTO, width: 800, height: 600, //物理エンジンの設定 physics: { default: 'arcade', arcade: { gravity: { y: 200 }, debug: false } }, scene:[Playing] });
(index.html)