JSXでアクションゲームを作ってみた
JSXが面白そうだったのでゲームを作ってみた。
jsx action
napthats / jsx_action (github)
書いてみた感想は、JavaScriptにクラスベースの静的型付けを追加したような感じ。静的型付けだけど、型推論も付いてるのでさくさく書ける。ただしOCamlやHaskellみたいな関数型言語ほど型推論が賢くないので、型を明示しなきゃいけないことが結構ある(多分Scalaより多いぐらい?)。
例えば、
var inout = Stage.checkInner(this.pc.x, this.pc.y);
こういうのは関数の返り値の型を見てくれるのでvarで済む(変数の型は書かなくていい)けど、
static function checkInner(x : number, y : number) : Region { ... }
関数(メソッド?)の定義では引数も返り値も型を書く必要があるし、
var newEnemies = [] : Array.<Enemy>;
空配列は型が解らないので明示しなきゃいけなかったりする(関数型言語だとnewEnemiesがこの後どう使われてるかを見て推論してくれたりするけど……)。
mixinもある(多重継承できる)し実装の継承は楽にできる。作ったゲームでもキャラの特徴ごとにmixinや抽象クラス作ったりして書きやすかった。ただあんまり多用するとカオスになるかも。
mixin Obj { ... } abstract class WalkingObj implements Obj { ... } class WalkingEnemy extends WalkingObj implements Enemy { ... }
こんな感じ。ふつう。
JavaScriptベースなので関数はfirst-class objectで、そのまま変数に代入したり、関数の引数として受け取ったりできる。ちゃんと型も付くし安心。ゲーム中では敵キャラ(FlyingEnemy)の移動アルゴリズムを受け取るのに使ってる。
class FlyingEnemy implements Obj, Enemy { ... function constructor( _x : number, _y : number, _get_delta : function(:number) : Map.<number> ) { this.x = _x; this.y = _y; this.character = "F"; this.get_delta = _get_delta; this.tick_count = 0; this.hp = 3; } override function tick() : void { var delta = this.get_delta(this.tick_count); assert(delta["dx"] != null); assert(delta["dy"] != null); if (!this.hitGround(delta["dx"], delta["dy"])) { this.x += delta["dx"]; this.y += delta["dy"]; } ++this.tick_count; } ... }
こんな感じ(constructorはそのまんまコンストラクタ)。関数の型の書き方がちょっと気持ち悪い……かも(と思ったら -> を使った記法にも対応してるらしい?)。
JavaScriptとの連携、例えば既存のJavaScriptライブラリをどの程度再利用できるのかはよく知らないけど、asで後から型付けできたり、variantという色んな型の値を保持できる型があるし、多分いけそう?
というわけで、全体的に使いやすく纏まってる印象。今後はJavaScriptの代わりにJSX書こう。