気鋭の新JSゲームライブラリ「phina.js」の概要を自分なりにまとめてみた

More than 3 years have passed since last update.

本記事はphina.js Advent Calendar 2015の3日目の記事です。

daishi_hmrさん 前 ← → 後 alkn203さん


phina.jsとは

 phina.js は、 @phi さんを中心として開発が行われている、JavaScript製の国産ゲームライブラリです。ライセンスはMIT Licenseです。

 前身であるゲームライブラリ tmlib.js をリファクタリングし、さらに設計を洗練させたものになっています。

 この記事は、一応phina.js(とその前身であるtmlib.js)の開発コミュニティの末席(中の末席w)にいる私emadurandalが、コミュニティでの議論及び、自分なりにコードを読んでの、phina.jsの概要について自分なりにまとめてみたものです。

 一応、開発コミュニティの皆さんによるチェックは通しましたので、明らかな間違いなどは書いていませんが、あくまで末席の人間による所感です。 メイン開発者でいらっしゃる @phiさんの設計思想等を直接書き表したわけではないことを始めにお断りしておきます。

 また、一応開発コミュニティに近い人間が書いている以上、客観的になりきれない部分があるかもしれませんが、まぁそこは差っ引いて読んでいただいて、詳しくは実際に触れてみていただければと思います。


代表的な機能

 基本的には、HTML5のCanvasの機能を活用した、2Dグラフィックスベースのゲームライブラリと考えていただいて良いです。それに画像や音声ファイルなどのアセット管理・表示・再生、そして衝突判定などの便利な機能がたくさん加わったものです。

 基本的には2Dベースなのですが、Three.jsと連携した3D描画にも対応している(ただし、Three.jsとしてのコーディングも必要)のが特徴です。

 主だった機能をリストアップすると、以下のような感じになります。


  • シーンクラスを中心としたシーン管理によるフレームワーク(枠組み)の提供

  • 画像、音声ファイルなどのゲームアセットの、一貫したインターフェイスによるロード・取得機構

  • HTML5の2D Canvasをラップした描画機能

  • 衝突判定対応

  • box2D物理エンジン対応

  • WebGLライブラリThree.jsと連携した3D描画に対応

  • WebAudioベースのサウンド機能

  • マルチタッチ対応

  • ゲームパッド(一部機種)対応

  • 各種数学クラス

  • Tween機能など、その他便利なユーティリティ


まずはどこから始めれば?

何はともあれ、phina.jsの公式サイトに行きましょう。

スクリーンショット 2015-12-02 7.18.29.jpg

可愛い鳥さんたちが出てきました。このゆるふわな雰囲気がいいですね♪ でも、そんな可愛い顔して phina.js は隠れた優等生なんです。

このトップページの中ほどに、「Getting Started」という箇所があります。基本的にはここの説明に従えば即導入完了です。

具体的には、あなたのHTMLファイルに

<script src='http://cdn.rawgit.com/phi-jp/phina.js/v0.1.0/build/phina.js'></script>

を読み込めばOK。これはいわゆるCDNでホストされているものですので、リンクが切れるなどといったことは基本的にありません。安心して使ってください。

ただし、上のCDNのphina.jsは、当然ながらインターネットに接続された環境での使用が前提です。

もし、オフライン環境でも動かしたいという場合は、phiha.jsの本体をダウンロードして、それを<script>タグで読み込む必要がありますね。

その場合は、Githubのphina.jsプロジェクトページに行きましょう。

ページの紹介(README.md)が超簡潔に英語で書かれてますね^^;

焦らない! 恐れない! 怖がらないで! ボクと一緒に手をつないで行こう!(←誰)

README.mdに書いてある、git cloneとか、npm installとか、そういうのは「phina.jsを一からビルドしちゃうよ! あわよくば改変してプルリクエスト送っちゃうよ!」というガチな人向けです。

(プルリクエストして貢献したい、という方向けには、phina.js Advent Calander 2015の24日目の @daishi_hmr さんの記事が超絶役に立つはずです。お楽しみに!)

とりあえずREADME.mdは素通りして、Githubページ右のDownload ZIPをクリックしましょう。

phi-jp_phina_js.png

落としたZipを解凍して、buildフォルダにあるphina.jsまたはphina.min.jsどちらか(デバッグしてコードを追いかけたい人は、phina.jsの方にすると良いでしょう)を、scriptタグであなたのHTMLファイルに読み込めば、オフライン環境対応のphina.js導入完了です。


サンプルを確認しよう

解凍したZipのフォルダの中には、examplesというフォルダがあると思います。2015/10/26現在、そこには3つのサンプルゲームが入っています。


  • flappy.html : 自機の鳥を画面マウスクリックで操作して、飛来してくる敵機を避けるゲーム。

  • touchgame.html : 数字ボタンを小さいものから順にクリックして、すべて押す速さを競うゲーム。

  • typing.html : 上から降ってくる文字をひたすらタイピングするゲーム。

どれもそれなりに遊べるゲームですが、なんと3つともどれもhtmlファイル1個のワンソースで成り立っています。それほど簡単に作れてしまうのがphina.jsです。まずはこの3つのソースコードを読んでみて、その作法を学ぶのが、出発点となりましょう。


大まかなコードの形

phina.jsでゲームを作る時のコードは、だいたい以下のようなイメージになります。

var SCREEN_WIDTH = 960;

var SCREEN_HEIGHT = 640;

phina.globalize(); // 階層的に定義されているクラスをグローバル空間にコピーする便利機能
// phina.game.GameApp -> GameApp
// 記述を楽にするためのおまじないで、別に使わなくても可

// 読み込むアセットの定義
var ASSETS = {
sound: {
'correct': '../assets/sounds/correct.mp3'
}
};

// MainSceneは(phina.jsが用意している)タイトルシーンの次に自動的に呼ばれるシーン
// phina.game.GameApp内部でMainSceneが指定されているので、ユーザーは
// MainSceneクラスを定義するだけでよく、ユーザーコードの別の場所でMainSceneを
// 明示的に指定する必要がありません。
phina.define("MainScene", {
superClass: 'CanvasScene',

init: function() {
this.superInit({
width: SCREEN_WIDTH,
height: SCREEN_HEIGHT,
});
// 初期化
},

onkeydown: function(e) {
// キーイベントハンドリング
},

update: function(app) {
// 毎フレーム処理
}

});

phina.main(function() {
var app = GameApp({
title: 'typing game',
width: SCREEN_WIDTH,
height: SCREEN_HEIGHT,
assets: ASSETS, // 読み込むアセットを指定
startLabel: 'title' // phina.jsが用意しているタイトルシーンからゲームをスタートする
});
app.enableStats(); // FPS表示を有効にする
app.run(); // メインループ開始
});

phina.jsではHTML5のCanvasに描画が行われるわけですが、Canvasタグはphina.jsが自動的に生成してくれます(もちろん、自前で用意したCanvasタグを指定することもできます)。


ライブラリ? フレームワーク?

 「ライブラリの定義とは、フレームワークの定義とは」と細かいところを突き詰めると、なんかいろいろ言説ありそうですが、私のゆるい理解では:


  • ライブラリ:プログラムの大まかな枠組みは自分で設計できて、その枠組みから適時好きな時に利用できるもの

  • フレームワーク:プログラムの大まかな枠組みはフレームワーク側が用意しており、プログラマはその枠組みに沿う形で開発を行う。自由度はある程度制限されるが、その作法に従えば高い開発効率が期待できる。

 というものであり、ここら辺はおそらく、みなさんの認識とそう変わらないのではないかと思います。

 そういう意味では、独自のメインループ処理や、phina.main()やシーンクラスを提供し、そのシーンクラスのupdateメソッドやonkeydownメソッドなどを実装していく作法を取るphina.jsは、フレームワークに近いと言ってよいでしょう。

 (その後、チームに意見を聞いてみましたが、ManagerSceneクラスなどを使い、プログラム構造はかなりカスタマイズできるようです。さらには、やや不便になりますが、シーンクラスなどを全く使わないプログラムアプローチも可能とのことで、「phina.jsはライブラリ・フレームワーク両方の特性を持っている」と訂正した方が良さそうです。ManagerSceneの詳細についてはアドベントカレンダー2日目のdaishi_hmrさんの記事で詳しく解説されています。)

 phina.jsはゲーム開発/JavaScriptの初心者の方でも簡単に扱えるように、ということも主眼において作られていますので、フレームワークとしての環境も整備しているのは正しい方向性と言えるのではないかと私は思います。

 反面、フレームワークというものは、ライブラリ系に比べて、その作法にロックインされてしまう面があることも確かです。

 しかし、phina.jsの仕様を見てみると、シーンクラスによる管理やupdateコールバックなどによる更新処理など、ゲームフレームワーク/エンジンとしては割と素直なもので、そんな風変わりなものではありません(アセットの読み込みなどの仕組みは、さすがにどのようなエンジンでも独自なもので、phinaに限らず共通でないケースが多いですが)。

 仮にゲームフレームワークを自作するとしても、おそらく(大まかには)似たような設計にたどり着くケースが多いのではないでしょうか。

 そういう意味では、「将来的に他のゲームライブラリ/フレームワークに乗り換える時に支障ないだろうか」という心配は、そんなに必要ないのではないかと思います。

 (もちろん、ソースコードレベルでは書き換えはたくさん起こると思いますが、作ったゲームが設計的に他ライブラリ/フレームワークに移植が不可能になる、というケースは少なかろう、という意味で、です)

 また、先ほども説明した通り、phina.js(前身であるtmlib.jsもですが)はライブラリ的に使うことも可能です(もちろん、効率は幾分落ちますが)。

 (私事で恐縮ですが)実際私は、現在独自にJS製のゲームエンジン・サービスを開発中で、その中でphina.jsをライブラリ的に使おうとしています。

 

 それどころか、ゲーム制作でなく、より一般的な用途として、単純なサウンド再生、Canvasの高級ラッパーとしてのみ、phina.jsを使うという限定的な使用法も十分にありえます。いろいろな使い方をしてみると良いのではないでしょうか。


その他FAQ


Q: ライブラリの設計として、ECMAScript2015 (ES6)の機能は使っている?


A: 使われていません(それなりの理由があります)

 ソースコードを読めばすぐにわかりますが、ECMAScript2015のクラス構文をはじめとした、ECMAScript2015の機能は使われていません。

 理由は幾つか、


  • 各現行ブラウザのECMAScript2015サポート状況がまだ十分とは言えず、ECMAScript2015を設計に取り入れるのは、まだ時期尚早という判断であった。

  • メソッドチェーンを多用できることが(tmlib.jsから続く)phina.jsの特長のひとつ。new構文を使うECMAScript2015のクラスのインスタンス化の書き方は、そうしたメソッドチェーン志向とは相性が良くない。

 といったことがあるようです。

 ブラウザサポートという点では、Babelを使えばいいのでは? という案も当初ありましたが、Babelで現行JavaScriptにトランスパイルするアプローチでは、その実行パフォーマンスに悪影響が出てしまうという懸念などから、こうしたトランスパイラは使わず、ECMAScript5で実装する、という判断になったようです。(実行パフォーマンスの高さにかなり配慮して実装されているのも、phina.jsの特長です)

 とはいえ、phina.jsはECMAScript2015の採用は見送ったものの、(前身のtmlib.jsからそうでしたが)ECMAScript5(ECMA-262 5th edition)の機能はふんだんに活用しています。

 Object.defineProperty()を駆使して設計された、独自のクラス構文、Array、String、Numberなどの基本オブジェクトの安全かつ便利な拡張メソッド群などがそうです。

 (個人が中心となって創られたライブラリとしては珍しいくらい、細かい部分、「あ、これあると便利なんだけどな」というかゆい部分にまで応えてくれるところがあります)

 ECMAScript2015を完全に設計に取り入れたライブラリは、ゲームに限らずまだ少ないものです。

 Three.jsなどをはじめとして、ほとんどのライブラリは独自のクラス構文を持っています。phina.jsは様々なライブラリの特徴を十分吟味・参考にした上で、良いとこ取りで作られていますので、 

 ECMAScript2015を取り入れていないからといって、設計に遅れがあるものではありません。

 ちなみに、TypeScriptなどのAltJSを実装に取り入れるライブラリも増えつつありますが、それらも「scriptタグでライブラリを読み込んだら、すぐにさっと使える」というphina.jsの志向とそぐわないため、不採用となりました。あくまで、初心者の人でも楽に始められる、というのがphina.jsの良さのひとつです。

 

 また、ライブラリとしてはECMAScirpt2015は使われていませんが、phina.jsを利用する側のみなさんのコードに関しては、もちろんECMAScript2015で書いていただいて全く問題ありません。


Q: ブラウザの対応度合いは?


A: Chrome、Firefox、Safariといったモダンブラウザは問題なし。IEは…(黙って目を逸らす)

 これは嘘をついてもしょうがないのでw IEについては、 @phi さんがMS大嫌い未来志向でいらっしゃるので、あまり動作確認が取られていません。HTML5の標準機能のみを使い、ブラウザ依存の機能は避けて設計されているので、 MSの新ブラウザEdgeなら大丈夫と思われますが、こちらも、Chrome、Firefox、Safariに比べるとチェック体制はまだ十分とは言い難いかもしれません。この点に関しては、逆に皆様のご助力を頂けると嬉しいところです。

 IEは、どうなんでしょうね。消えゆくブラウザですが、IE9以降なら多分大丈夫と思いますが…うん(再び目を逸らす)

 モバイルブラウザについては、iOS 8以降のSafariならOK。Androidも4以降ならOKだと思います。え? Windows Phone?(立ち眩み)

 


Q: Array、String、Numberなどが拡張されているってことだけど、同様のことをしている他のライブラリと併用した場合はどうなるの?


A: メソッド名ができるだけバッティングしないように配慮していますが、バッティングするケースもあるかも(汗)

 まぁ、そうですね。実際、tmlib.js時代、私もEmber.jsと併用した時に双方の拡張メソッドがバッティングしてちょっと手こずったことがあります。Ember.jsにはそうした拡張メソッド・プロパティを無効にするオプションがあったんですが、tmlib.js/phina.jsにはそうした切り替えオプションはありません。

 無効にできるオプションもあったらいいかもしれませんね。ただ、そうするとphina.jsの内部設計はそうした拡張に頼らずに実装しなければならず、それはなかなか中の人的に辛いものがあるので、実現の可能性は今のところ低いかもしれません^^;

 

 ただ、「メソッド名ができるだけバッティングしないように配慮している」と書いた通りですし、また、バッティングしたとしても、双方のライブラリで挙動はだいたい同じだったりすると思うので、問題になるケースはそんな多くないと思います。もし、この手のトラブルで困ったという方は、Githubでイシュー上げるなり、 @phi さんにツイートで知らせてもらえれば、何かしらの助言・対応はしてくれると思います。

 

 なお、当然のことですが、Object.definePropertyで拡張しているため、拡張したメソッドプロパティがenumerableで、in構文でそれが拾われてしまうような、まずい設計にはなっていませんので、その点は問題ありません。

 


Q: 3Dのゲーム作れる?


A: (現在のところは)Three.jsと連携して作ることになります

 phina.jsにはphina.display.CanvasElementを拡張したphina.display.ThreeLayerというものがありまして、それを通すことで、現在最もメジャーなWebGLライブラリであるThree.jsと連携して3D描画をすることが可能です(別途、Three.jsの読み込みが必要です)。

 ただ、現在のところThree.jsとの連携は最低限のものなので、Three.jsの機能の多くをより使いやすいAPIでラップしてくれるわけではありません。つまり、3D処理を記述する上では、別途Three.jsの使い方を学ぶ必要があります。

phina.js Advent Calendar 2015の19日目の私の記事で、そこらへんもう少し詳しくやる予定です。お楽しみに!)

 

 なお、これは余談なのですが、phina.jsでは当初3D機能も独自に開発予定でした。それは私が開発することになっており、というか開発しているのですが、諸般の事情(便利な言葉だよなこれw)で開発が遅れに遅れ、まだphina.jsに統合できていません(泣)

 

 将来的には、Three.jsと連携してやるより、よりスマートな形で3D処理ができるようになるかもしれません。生暖かく経過を見守ってください(震え声)


Q: phina.jsの開発スピードは? 付け足して欲しい機能があるんだけど


A: 期待して良さげ!?

 期待して良さそう、というか期待していいと思うんですが、煮え切らない答えになっているのは、メイン開発者でもない末席の私がそんな勝手にあれこれ約束できない、というだけです^^;

現在、Gitterを中心に複数人のメンバーで活発に開発が続いています。今の所、この勢いは増すことはあっても減じる傾向は一切ありません。

 また、この手のライブラリは、メイン開発者の気力や事情によってその将来が大きく左右されますが、メイン開発者の@phiさんは(私が勝手に詳細言えませんが)、今後(tmlib.js時代以上に)かなり本腰を入れてphina.jsへのコミットを続けられることをコメントしておられます。

 以前のtmlib.js時代にしても、Twitterでの機能要望やらバグ報告、プルリクエストへの対応も貪欲にされておりましたし、phina.jsに関しても、期待して良いのではないでしょうか!


Q: 他にドキュメントないの? つか、公式ドキュメントは?


A: 公式APIドキュメントとphina.js Advent Calendar 2015 の各記事がキミの味方だ!

 まず、APIドキュメントはこちらです。公式のチュートリアル記事とかはまだそんなにありません。

 現在はこのphina.js Advent Calendar 2015、及びそのリンク先から辿れる、各有志の方が書かれたチュートリアル記事を頼りに使い方を学んでいく形になります。

 

 ただ、tmlib.js時代がそうでしたが、何しろライブラリの開発スピードが速いので、ネットを検索して出てくるチュートリアルなどの情報がすでに古くなっていて、最新バージョンでは一部通用しないケースが多々ありました(公式APIドキュメントなどはさすがに最新を維持すると思いますが)。

 これは、今後のphina.js時代ではなんとか改善したいところではありますね。

 (ちょうど今、phina.jsについてコアメンバーが書いたチュートリアル記事は長期的にメンテナンスして、さらにそれらを公式サイトで常に学習に最適な順序に並べて紹介しよう、という案が出ています)


Q: 早速phina.jsを使ってみたいんだけど、自分でHTMLファイルをローカルで書くのもめんどくさい。


A: Runstantを使いましょう

Runstantとは、 phina.jsのメイン開発者 @phiさんが開発した、JavaScript実験環境です。いわゆるjsdoとかjsFiddleとかjsBinみたいなサービスですね。それらよりもずっとシンプルで便利だと思います。

で、そのRunstantのphina.jsテンプレート版を使えばいいのです。

これで、いろいろ気軽にコードを組んでいじってみて、わからなくなったらシェアボタンでURLをphina.jsに詳しい人に送ってお願いして、質問してみましょう。あとは実践あるのみ!


まとめ

以上、phina.jsの特徴を良い面も懸念点も含め、割と正直にご紹介したつもりです。

総合的に見れば、HTML5の今後の潮流をしっかり見極めたハイスキルな方々が開発されており、その開発スピード・活気ともに安心して今後を見守ることができるゲームライブラリです。

(ちなみに私は以前はenchant.jsを使っていたのですが、enchant.jsの開発スピードが鈍化したり、tmlib.jsの方がパフォーマンスが良かったり、といった理由からtmlibjsに乗り換えて、現在はphina.jsへ移行中です)

国産ゲームライブラリは幾つかありますが、その中でもかなりオススメですので、皆さんもぜひ今からphina.jsに触れてみてください。


参考リンク


チュートリアル

 @alkn203 さんによるとても丁寧なチュートリアルです。これを通せばphina.jsをかなり使いこなせるようになります。


アドベントカレンダー

リリース早々、12月ということでアドベントカレンダー期間に突入しました! 2015年のphina.jsの情報の全てがここに!

phina.js Advent Calendar 2015