JSXでアクションゲームを作ってみた

JSXが面白そうだったのでゲームを作ってみた。

jsx action
napthats / jsx_action (github)

書いてみた感想は、JavaScriptにクラスベースの静的型付けを追加したような感じ。静的型付けだけど、型推論も付いてるのでさくさく書ける。ただしOCamlHaskellみたいな関数型言語ほど型推論が賢くないので、型を明示しなきゃいけないことが結構ある(多分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書こう。