typescriptでenchant.jsのハローワールドやってみた

mizchi/enchant-with-typescript https://github.com/mizchi/enchant-with-typescript
coffeescriptで書いた時と同じく、interfaceを書いて継承してモジュール定義、という流れ

src/types/enchant.d.tsが定義ファイル。プロパティを網羅できてないが、typescriptでenchant.jsやりたい人には便利だと思う。

感想

HaXeでやったときよりすんなりいった印象。

ただ、割とどうしようもない部分でへんなことしないといけなくて、例えば

interface Window {
  enchant: Function;
}
window.enchant();

enchantをmoduleにしてしまったせいで、関数としてcallできない事に気づいた。
かわりにwindow:Window のenchantを借りてきてFunction型にして初期化関数の呼び出しをしている。
型のinterface書くの、脳みそ止めてもできるのでアニメみながらやるといいと思う。

上手く説明できないのでここにmain.ts置いておく。

///<reference path='types/enchant.d.ts'/>
declare var enchant : enchant;

// In this context, enchant is module so it is not callable.
// Use window.enchant instead of 'enchant'.
interface Window {
  enchant: Function;
}
window.enchant();

module App {
  export class Bear extends enchant.Sprite {
    constructor(){
      super(32, 32);
      this.x = 8;
      this.y = 8;
      this.image = Game.game.assets['images/chara1.png'];

      var self = this;
      this.on('enterframe', () => self.update());
    }

    update(): void {
      var input = Game.game.input
      if (input.right) this.x += 2;
      if (input.left)  this.x -= 2;
      if (input.up)    this.y -= 2;
      if (input.down)  this.y += 2;
    }
  }

  export class Game extends enchant.Game {
    public static game: Game;
    constructor(){
      super()
      Game.game = this;
      this.fps = 24;
      this.preload('images/chara1.png');
      this.onload = () => {
        var bear = new Bear()
        this.rootScene.addChild(bear);
        var game = this;
      };
    }
  }
}

window.onload = () => {
  var game =  new App.Game();
  game.start();
};

typescript触ってみた ついでにunderscoreのinstance定義ファイルを作ってみた

主に自分が一番使っているcoffee-scriptとの比較

underscoreのは練習がてら作ってGithubにおいた
mizchi/underscore.d.ts https://github.com/mizchi/underscore.d.ts

書き味

構文の硬さがJavaが10 Python6 Rubyが3という記事をどっかで見たけど、同じように当てはめると、JS8 typescript6 coffee2という感じ。
coffee-scriptの超ゆるふわスタイルに慣れてると結構辛い感じはあるが、自分多分Coffeeについてある程度極まってる感じなので、あんまり比較しないほうがよさそう。
高階関数(後述)が簡単に定義できるのでJS特有のパラダイムには素直に応えられる。

""" multiline text """ がない
デフォルト引数がない

最初にunderscoreの型定義ファイルを書いた理由

JSのスーパーセットなだけに、イテレーションが貧弱

Lambda

結局自分はfunctionと書きたくなくてcoffeescriptを使ってるフシがあるのだけど、どのぐらい省略できるか調べてみた。

自分自身を返す f(x) = x はこう書ける

(i) => {return i}

ブロックだと複数行書けるが、returnが必須

もしくはブロック省略して

i => i

こちらはreturnが要らない

CoffeeScriptと違って 引数なしの()は省略できない

[1,2,3].forEach((i) => {
  console.log(i);
})

こんなふうに某関数型言語っぽく書くことも

var fuga: (number) => (string) => number
  = (a) => (b) => a * b.length;
console.log(fuga(3)("dafa"))

アノテーション

クラス志向というよりかはインターフェース志向?Golangっぽさも若干感じる。とりあえずJSの邪魔をしないanyが便利。

JavaScriptのスーパーセット

CoffeeScriptの辛かった点である、「jsコピペしてすぐ動かない」問題が解決した。
とりあえずコピペしてから徐々に置き換えるという段階を踏める。

末尾セミコロン

JSと同じような扱い。classフィールドでは;なしだと構文解析されない。基本末尾セミコロン嫌いなので可能な限り省略して書いてみたが、結局必要そう

エディタ

宗教上の理由(一方が好きというかは一方が嫌い)でVSが使えないのだが、SublimeTextで書いていたが補完はなかった。
まあ簡単そうなのでそのうち誰かが作るだろう。

instance

公式リポジトリのサンプルに型ファイル情報が少しついてる

  • express.d.ts
  • jquery.d.ts
  • jqueryui.d.ts
  • node.d.ts

todomvcにはBackboneモジュールに対して型アノテーションを追加していて参考になる。

declare module Backbone {
    export class Model {
        constructor (attr? , opts? );
        get(name: string): any;
        set(name: string, val: any): void;
        set(obj: any): void;
        save(attr? , opts? ): void;
        destroy(): void;
        bind(ev: string, f: Function, ctx?: any): void;
        toJSON(): any;
    }
    export class Collection {
        constructor (models? , opts? );
        bind(ev: string, f: Function, ctx?: any): void;
        collection: Model;
        length: number;
        create(attrs, opts? ): Collection;
        each(f: (elem: any) => void ): void;
        fetch(opts?: any): void;
        last(): any;
        last(n: number): any[];
        filter(f: (elem: any) => any): Collection;
        without(...values: any[]): Collection;
    }
    export class View {
        constructor (options? );
        $(selector: string): any;
        el: HTMLElement;
        $el: any;
        model: Model;
        remove(): void;
        delegateEvents: any;
        make(tagName: string, attrs? , opts? ): View;
        setElement(element: HTMLElement, delegate?: bool): void;
        tagName: string;
        events: any;

        static extend: any;
    }
}

curry化/ っぽくしたかったけど上手くいかなかった

var fuga: (number) => (string) => number
  = (a) => (b) => a * b.length;

// it works
console.log(fuga(3)("dafa"))

// it doesnt work
Function.prototype.proc = function() {
  var args, target, v;
  var __slice = [].slice;
  args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
  target = this;
  while (v = args.shift()) {
    target = target(v);
  }return target;
};

console.log(fuga.proc(3, "dafa"))

Function型にprocがない。prototypeを拡張したことを認識されていない。
誰か教えてください。
公式サイトのリアルタイムインタプリタなら通ったので、コンパイルオプションでどうにかなるかも

闇鍋勉強会#2いってきた + LTしてきた資料 #yaminabePG

いってきた

第2回 闇鍋プログラミング勉強会 : ATND http://atnd.org/events/29973


発表資料はgistだけどな!
JavaScriptを書きたくない話 https://gist.github.com/3726883

要は、いかにJS書かずに他の言語から生成できるか、どういうスキルの人がどの言語を選ぶかっていう話です

二日酔いでくたばってて遅れていったので、その場で作りました(サーセン


あと家に帰ったら
https://github.com/manuel/wat-js
とかいう言語がまた増えてました。いまからいじる。

Backbone.Model の かっこいい使い方

IE8は死に、get, set 使わずに値を出し入れできて、ちゃんとchangeイベント発火します。

こういうのかっこいいしプロダクトで使おうよと言ったんですが、@SubaruG に大反対されて悔しいのでブログに載せておきます!!!!!!!!!!!
使っていいよ!!!!

HaXeで関数型っぽくクイックソートするとこうなった

using Lambda; したかっただけとも言える。
switchが値を返す。switch文の中では一番最後に評価された値が変える。
Lambda使うと各種アルゴリズムを適用しやすいように二分木なList型に変換して、List#array()を呼ぶと普通の配列で返すっぽい。

HaXe触ってみた

適当に書いた奴をGithubにあげておいた。
mizchi/haxe-try https://github.com/mizchi/haxe-try

enchant.jsもHaXeから触ってみた。nodeとenchant.js、enchantの型アノテーション
haXeでenchant.jsする利点 - mitamex4uの日記 http://d.hatena.ne.jp/mitamex4u/20111230/1325248577
を使わせていただきました。

とりあえずクイックソート

配列操作系のユーティリティはあんまりなさそう。
undescore.jsクローンのUndescore.hxってのはあった。が、名前空間がほんとにUnderscore.mapとかで冗長な気が…

HaXeを使う指針

何よりも気に入ったのが型がオプショナルであるという点。Dynamic型にすればそれ以下のプロパティに対して型チェックを行わない。
JSから触る場合、元が型がない言語なので、絶対な型安全はありえない以上ある程度ラップして妥協することになる。

と同時に、それ以外のロジックはHaXeのピュアなロジックで吸収する。型安全な世界は絶対に崩れないように書くことで堅牢なコードにすることが可能。
外部に依存しないようなコードは、他の言語にもコンパイルが可能なのでコードの再利用性は高い。(つってもやっぱ独特なコードなんだが…

HaskellがIOモナドで純粋でないものを切り離すように、安全な部分と危険でない部分を分離する方向で、JSをラップして、できるだけ純粋なHaXeのロジックで、という指針がよさそう。

実際にコーディングする際、ライブラリのコードを触る部分より、自分で書いたほうが多くなるとは思うので、必要な物だけtypedefなりして型アノテーションをつけるといい。補完がきくようになるし。

HaXeの駄目な点

Coffee書き慣れた身からすると記述はやっぱり冗長。高階関数のためにLambdaはなにかしらの略記がほしい。
Function型がない?。コールバックの記述に不安が残る。サンプルコード見てもDynamic型を渡していた。Int -> Void みたいな書き方はできるみたいだが。
コンパイルされたコードはやっぱり読みづらい。

HaXeとSublimeText2

補完はそこそこ効く。そもそもIDEあんまりすきじゃないのでこれぐらいで十分。
InteliJとMonoDevelop版もあるらしいので、本格的なのはそっちに期待しておく。

ベンチマークとってみた

cppとjavaとjsで吐いてみた。UnityのためにC#も吐いてみたかったが、MacなのでMono環境の整え方あんま知らず断念。
mizchi/haxe-benchmark https://github.com/mizchi/haxe-benchmark

Nodeが一番早くなったが、たぶん書き方悪い。どっちかっていうbuild.hxmlの書き方のサンプルになる程度だと思う。


さて、原稿書かねば…

HTML5でロードオブナイツとかいうゲームを作った

陣取り戦争ゲーで、iPhoneのUnity版からの移植です。

ロードオブナイツ - Yahoo!モバゲー http://yahoo-mbga.jp/game/12011436/detail

http://aiming-inc.com/wp-content/uploads/1208240040201.jpg
http://aiming-inc.com/wp-content/uploads/screenshot.jpg

PC(Chrome/Firefox/IE9以上)とスマホ(Webkit)で同じ物が動きます。ヤバゲーとモバゲーでアカウントは共有してるので、どっちからでも入れます。
HTML版としては既存コードとか一切なかったんで、JSに関してはフルスクラッチです。というか全部CoffeeScriptです。


ある日会社で楽しくHaskellでKPI計算モジュール書いてたら、
「UnityのネイティブのゲームをHTML5に移植したい」
みたいな話が降ってきたので、移植しました。3ヶ月ぐらいで。

プラットフォームはモバゲー(スマホ) + ヤバゲーです。HTML5なのは、スマホとブラウザゲーで開発リソースを共通化したかったから。
ヤバゲーのゲーム、ほとんどFlashで、JSでゴリゴリ動いてるのは割と異彩はなっている感じがありましたね。作ってから気づいた。

個人的なテーマ

一応趣味でHTML5っぽいゲーム作ってた身としては、Unityで書かれた本家を再現することを目標としていて
クオータービューのマップとか実装したんですが結構うまくやれた気がしてます。
もちろん僕一人で作ったわけじゃないですが、はじめて大人数開発を経験して、しかも技術的に超エッジなことをやらせてくれたので、作っててすごく楽しかったですね。Android標準ブラウザへの殺意を除けば。

分量

HTML 3000行
CSS(SCSS) 8000行
CoffeeScript 21000行

サーバーに関しては、元あるものを使ったので、基本クライアントコードの実装でした。
開発時はRailsのsprocketに頼りまくりました。デプロイされるときはindex.htmlとall.cssとall.jsだけ吐いて、Railsに依存しない謎構成でした。
Railsコンパイラ。これについてはあとで何かしらの連載が上司のブログで展開されるんじゃないかなー(チラッ

使ったもの

割と普通の技術を使って、フルスクラッチガリガリ書きました。

Backbone
underscore
jQuery
iScroll(若干の改造を要した)
Mustache

iScrollをAndroidIEで同じように動かすの超辛い…

テスト環境

nodeで無理矢理読み込んでJSDOM使ってテスト。
ってのはピュアJSのロジックが多かったからです。

nodeのライブラリで使ったのはこんな感じ。

  • mocha
  • jsdom
  • should
  • sinon

JSなんでほとんど対象はビューになるんですが、テストコードは6000行ぐらいあります。足りないので足さねば。

これからの実装

PC版専用ビューつくるらしいですね(って書いてある


オマケ