とりあえずHaxeを使ってみるには
Haxeをサポートしているエディタ、IDEはいくつもあります。
http://haxe.org/com/ide
私のおすすめの環境はWindows + FlashDevelopです。
FlashDevelopはHaxeの型情報をちゃんと理解していて、正確なコード補完をしてくれます。
これがあるのと無いのじゃ大違い。Haxeを使うならとにかくFlashDevelopを使いましょう。
Macでは、JetBrain WebStormにHaxeのプラグインを入れて使ってますが、FlashDevelopほど賢くないです。素直にVMWareFusionでWindowsを動かしてFlashDevelopしてください。
http://haxe.org/download?lang=jp
からHaxeを
http://www.flashdevelop.org/wikidocs/index.php?title=Main_Page
の右上からFlashDevelopをダウンロードしてください。
どちらも実行するだけでインストールできるはずです。
FlashDevelopを起動したら、New ProjectでHaXe / JS Projectを選んで開発を始めてください。
F5キー一発でコンパイル後にWebBrowserが起動してJavaScriptにコンパイルされた結果を試すことができます。
ブラウザのコンソールに出力するには trace("ほげ");
これだけ覚えておけば、言語の挙動を知るためにいろいろいじくり回すことができるんじゃないでしょうか。
よーし、パパ酔った勢いでJSXに盛り上がっている連中をdisっちゃうよ〜
念のため書いておくけど、俺はJSXの開発者をdisったりはしない。
俺は車輪の再発明が好きだし、何よりモノを作る人間は素晴らしい。
しかし俺は今JSXに盛り上がっている連中にとてつもなく違和感を感じている。
JSXが登場した時にはすでにHaxeがあった。
JSXは開発途上だから今後に期待するが、現時点ではHaxeの方がはるかに洗練された言語であることは間違いない。
もう一度言うぞ。現時点ではHaxeはJSXより間違いなく優れている。
俺は静的型付け言語が好きだと言った。だがな、型はプログラミングを楽にするためのものであって、型のためにプログラミングするのは嫌なんだよ。
大人が誰も言わないなら俺が言ってやる。
型推論の無い静的型付け言語はクソだ。
型推論の無い静的型付け言語をありがたがって使う奴はドMだ。
JSXは現状では型のためにプログラミングする言語だ。
でもいいんだよ。JSXはまだ出てきたばかりだから。
これからきっとどんどん良くなっていくよ。
でもな、俺はこんな現状のJSXに盛り上がっている連中に途方も無い違和感を感じるのだよ。
すでにもっと洗練されていて、同じ用途に使えるHaxeという言語がるのに、なんでそっちでは盛り上がらなかったのよ?
JSXを作ったのがDeNAだからか?
なになに? 大企業が作ったから使うのかよ?
なによその日和見主義。長いものには巻かれろってか?
いや、俺もよく分かるよ。その気持。
でもな、なんか、それって俺的には本当は受け入れられないわけ。
なんかプログラミングの本質から外れてないか?
コンピューターの世界はプログラムさえ書けば自分が神になれるんだよ。
なんの力もない子供でも、プログラミングさえ出来ればそこでは絶対的な権力者になれるんだよ。
プログラミングって途方もなく自由なものじゃないのか?
Haxeみたいなどマイナー言語、作者が放り出したらどうすんのかって?
俺が引き継ぐよ。
ただそれだけの話しじゃん。
実際問題できるかどうかはわかんないよ?
でもさ、プログラムの世界って、そういう単純なものじゃん。
なければ作る。
そういう自由な世界じゃなかったのか?
いや、わかってるんだよ。俺も。
俺もプログラムを書いて飯を食ってるわけだから、生きるためには妥協もするさ。
「生きる為に挙手っ・・・・!」
そうさ、生きるためならPHPだって書くよ。
それが”大人”ってもんなんだろ。
ポール・グレアムが言語のパワーについて書いていたな。
グレアム御大は触れていなかったと思うが、言語のパワーにはユーザー数は間違いなく含まれる。
ユーザーが多ければライブラリも増える。
ユーザーが多ければ開発環境も充実する。
IDEが良い、デバッガーが良い、これはすごいパワーだ。
プロジェクトをはじめるときに容易にプログラマーを確保できたり、規模が拡大したら容易にプログラマーを補充できるとか。
ユーザー数はパワー以外の何物でもないよな。
Haxeなんていうどマイナー言語より、知名度のある大企業が作った言語が魅力的に映るのはわかる。
俺だってHaxeの作者が誰なのか知らんし。
DeNAが作った言語なら、関連企業でもいろいろ使われていくんだろうなぁ。プログラマーも増えるんだろうなぁ、とは想像できる。
ユーザー数という言語のパワーが上がることを見越して期待する気持ちもわかる。
プログラム言語も株と同じく美人投票みたいなもんだな。
それでも俺は物分かりの良い”オトナ”になれない。
プログラムの自由な世界と、そういう”おりこうさん”な大人の思考って相容れるものなんだろうか。
みんなが使っているからApacheを使う。それでパフォーマンスが出ないからサーバーの台数を増やす。
失敗して責任をとりたくないもんな。そういう選択はありなんだろうよ。
でも、Lighttpdもnginxもあるのに、そっちには手を出さない。なんでよ?
パフォーマンスを気にしているという割に、なぜかそれとは結びつかない一番の安全牌を切る、そんな”オトナ”の選択が俺には理解できない。
悔しいなぁ。
JSXがHaxeみたいに型推論ができて、判別共用体とかパターンマッチができるようになったら使いたいと思うかもしれないよ?
でも、JSXは出てきたばかりで、すでにHaxeはあるんだぜ?
なんどでも言うさ。Haxeは2005年にすでにあったんだよ?
ああ、でも本当は俺もわかってるんだよ。
ハローエフェクトってあるだろ?
どこの馬の骨とも分からない人間が作ったどマイナー言語より、天下のDeNA様が作った言語が魅力的に映る、しょうがないよな。
美人だったら何しても許せる気になるのはわかるし。
でもな、プログラミングしているときは論理的に本質を追っかけている気がするんだ。
それなのにちょっと離れると人間の非論理的な側面が出てくる。
受け入れたくない。
受け入れたくないよ。
ぐぐるとHaxeは34.1万件、JSX DeNAは、297万件・・・・
俺は人間学園で素っ裸にされて、「素直になぁれっ! 素直になぁれっ! 素直に… 素直に、素直になぁれっ…! 悪魂退散! 悪魂退散! きれいな魂戻って来い…!」って愛情注入されている気分だよ。
disるっていうか、なんか悔しいんですけどねぇ・・・
誰か、わかっていただけますでしょうか、この気持。
よーし、パパ酔った勢いで言語について語っちゃうぞ
ま、F#が最高だって言いたいだけだけなんだけどね。
静的型付け言語
Pascal
昔はC言語なんて高くて買えなかったんだよ。
子供がお小遣いを貯めて買えるコンパイラーはTurboPascalしかなかった。
Pascalは文の区切りが ; とか . 場所によって変わるんだけども、Erlangもこんな感じだね。
昔のMacはPascalでプログラムを書いたんだゼェ。InsideMacはPascalで解説してあったんだゼェ。
C
高級なアセンブラ
C++
俺はboostを使い始める前にC++は使わなくなったので最近のことはわからん。
C++はstlとかスマートポインタを使うとメモリー管理とかをほとんど気にせず使えるようになる。
それでも常に死と隣り合わせの緊張感あるプログラミング。
よほどパフォーマンスが必要な物を書く時以外はもう触らないね。
Java
すごく保守的な静的型付け言語。未だにlambdaすら無いんだゼェ。
型推論が無いので型の記述が面倒くさい。
型推論なしの静的型付け言語使うってどんなドMだよって今は思う。
サーバーでもAndroidでも書けちゃう。
みんなが使っているから俺も使う、そんな言語。
C#
アグレッシブなJava。痒いところに手が届く良い感じのJava。
簡単な型推論があるので、まあないよりはまし。
MonoTouchを使うとiOSのアプリだって書けるんだゼェ。
VisualBasic
VB6までは本当にBasicって感じだったけど、それ以降のバージョンは書き方が違う劣化C#みたいなもの。
ゴルゴ13で世界最高の言語はBASICだとか言っていた愚かな教授がいましたが、それ間違いなので。
そもそもVisualBasicって静的型付けだっけ? ま、いいや、VisualBasicなんて。
Ocaml
実用的な関数型言語。
俺は好きだよ。うん、すごく好き。
Haskell
純粋関数型言語。理想を貫くことが至上の命題。
関数型言語のお勉強には良いと思う。
でも実用には使えないな。でも、それは俺の頭が足りないからなのかな。
Scala
悪くはないよ。
良い、と言い切れないのは、リストをわざわざList()とか書かなくちゃいけないとか、そんな些細な部分。
でも、関数型言語に慣れていない人が使うと、ちょっと書き方が違うだけのJavaになる罠。
JVMで開発するならコレだね。
F#
msilで動くOcaml。どうしてもF#がマッチしないところはC#で書けばいい。
.net frameworkが使えて、c#で書かれたライブラリーが全部使える。
書き方がOcaml。見た目からして今までの言語と違う。とりあえず普通に書くと関数型言語っぽく書ける。
今更パターンマッチの無い言語なんか使う気にもならないよ。
IDEであるVisualStudioがすばらしい。
「俺はLinuxしか使わない」とかハッカー気取っているバカは悔い改めなさい。
最高だね。
Haxe
型推論がある静的型付けのJavaScriptって感じ。
Ocamlで書かれていて、Ocamlの影響を多大に受けている。JavaScriptの皮をかぶったOcaml。
enumとかswitchとか、名前は同じだけど超拡張されている機能があったりして、Ocamlみたいにパターンマッチもできるんだゼェ。
HaxeのコードはPHPやらC++やらC#、Java、JavaScriptとかいろんなコードにコンパイルできるんだゼェ。
JavaScriptだけでは信頼性に足りないような部分をHaxeで書けたらいいんじゃないかな。
JSX
Haxe使えよ。
動的型付け言語
マイクロソフトBASIC(N88Basicとか)
昔はみんなこれでプログラムを書いたんだ。
VisualBasicなんかとはぜんぜん違う。変数スコープなんてないんだ。
Objective-C
静的型付け言語のC言語と動的型付け言語のSmallTalkをまぜこぜにしたような言語。
iOS、MacOSのアプリを書くならこれだね。
割かし好きな部類に入るんだけど、動的型付け部分はやっぱり実行しないとエラーがわからない。
でも、Appleへの愛があれば乗り越えられる。
PHP
$にアレルギーがある人は使えません。俺はアナフィラキシーショックを起こして死ぬ。
クロージャを取り入れたりがんばってはいる。
でも、謎な仕様がいろいろあって、怖くて使えない。
サーバーサイドは安全な言語で書こうよ。
Perl
俺はアナフィラキシーショックを起こして死ぬ。
関数の書き方がわからなかった。つまり、引数ってどうやって渡すの? って感じ。
受け付ける引数はちゃんと宣言しようよ。型どころかアリティもわかんねぇじゃん。生理的に受け付けない。
こんなのありがたがって使っているMixiやらGREEなんかに負ける気はしないんだけど、なぜか全然勝てない(お金的に)
こんなのありがたがって使っている小飼弾にも負ける気はしないんだけど、全然勝てない(髭的に)
Erlang
ErlangはOcamlよりも純粋関数型のHaskellっぽい。
一時期入れ込んでいたけど、F#があるからもう使わないな。
そもそも堅牢なサーバーを動的型付けで書く、っていうのが俺には理解できんよ。
JavaScript
function <- 長すぎる
ブロックスコープがない。
でも、俺にはその程度しかケチを付けることはできないよ。
悔しいけどこいつはデキる子。避けては通れない。
憎み過ぎて逆に好きになっちゃいそう。
Node.js
JavaScriptだけど。
サーバーサイドを全部非同期IOのJavaScriptで書こうという楽しいプロジェクト。
きらいじゃないね。でもF#があるからいらない。
まー、そもそも、Node.jsで書くようなものはErlangで書けばいいんじゃねーの?
CoffeeScript
変数のシャドウィングができない。ケチを付けるのはこんだけだな。
すごく素敵な言語。でも、やっぱJavaScriptを直接書く。
Ruby
MatzLisp。こいつはいいと思うよ。でもF#があるから使わないけど。
Python
こいつはいいよ。なんかパワーが渦巻いている。
でもF#があるから使わないけど。
Prolog
子供の頃勉強してもわかんなかったけど、最近やりなおしてやっとわかった。
でも、Lispで書けばいいんちゃう?
CommonLisp
もはやLispには宇宙を感じる。
動的型付けとして書いたけど、型の制約を入れることもできるんだ。
MSIL、JVMで動くCommonLispがあればなぁ・・・・
あ、ABCLはだめよ。JVMで動くけど遅すぎる。話にならん。
動的型付け言語を使いたいなら、CommonLisp使えばいいんじゃねーの?
誰の支援もいらない、一人で敵を皆殺しにする覚悟ができたらCommonLispで書きたいね。
気になっている言語
Google Dart
Haxe使・・いや、いいと思うよ。パターンマッチ入れてくれたらぜひ使いたいな。
Mozilla Rust
F#使・・いや、いいと思うよ。パターンマッチも使えるし。うん、いいと思うよ。
ちなみに俺の開発環境はこんな感じ
MacBookPro RAM8G
- VMWareFusion WindowsXP VisualStudio2010,EmEditor,Leksah
- xcode
- JetBrain WebStorm
- JetBrain PyCharm
- vim
- eclipse
- Emacs + SBCL + SLIME
そいじゃ今日はこんなところで。See you!
それでも静的型付けがいいに決まっている
俺は静的型付けができない言語は嫌いだ。
F#最高!
俺はPHPもJavaScriptも嫌いだ。なんとでも言え。ダメなプログラマーで結構。
PHPの$を見ているだけでめまいがする。
PHPは意地でも使わないが、JavaScriptは必要に迫られているから使いたい。
でも、動的型付けでブロックスコープもないJavaScriptなんか使いたくない。
だからHaxeを使いたい。
静的型付けだと、IDEが良い感じの補完をしてくれるんだぜ。
自分がいじくっている変数にどんなメンバーがあるかわかるんだぜ。
ケアレスミスだってコンパイル時にわかるんだぜ。
なんでこの良さがわかんねーんだよ。
JavaScriptでがりがりクールなコードを書くような連中は若い奴が多いんだろうよ。
若い頃はいいんだよ。何十万行ソースがあっても頭の中で全部処理できるだろ?
だからIDEのコード補完もいらないし、コンパイラーの補助なんかいらない。
でもな、若い頃に書いた素晴らしいコードは何年もメンテナンスされていくんだぜ。
何年もの間に他に面白いことを考えついて別のプロジェクトを始めたりするんだぜ。
スランプで全然頭が動かなくなることもあるんだぜ。
若いやつだって年を取るんだぜ。
デキルやつはそんな状態にはならないか?
何億行コードがあろうと全部頭の中で処理OKか。
さすができる奴は違うなぁ。
でも、俺はできない子だから、コンピューターがやってくれるどうでもいいことは、コンピューターに任せたい。
問題が起きる可能性がある状況下で必死にミスしないように無駄な努力をするより、最初から問題が起きない状況下で楽をしたい。
でもま、JavaScriptをそのままガリガリ書きたくなる気持ちはわかる。
やりたいことがたくさんあるのに、Haxeからライブラリを使えるようにちんたらラッパーなんか書きたくないよな。俺も書きたくないよ。だから矛盾しているけどJavaScriptで書くよ。
書き捨てみたいなコードはJavaScriptで、重要なコードをHaxeに置き換えていくとか?
JavaScriptなから書いてすぐ実行なのに、コンパイルのステップが入るHaxeはどうしてもここのリズムが悪いわ。
その点F#はすごいよな。
書き捨てのコードだろうがなんだろうがなんでもF#でできるんだぜ。
面倒くさいから最初は型推論に任せておいて、込み入ってきたら型で縛っていくような良い感じの書き方ができるんだぜ。
あーもうF#最高。最高すぎる。なんでみんな使わないのかな。こんな素晴らしい言語。
最近はサーバー系は全部F#で書いているけど、楽ちんすぎてマジ最高。
F#より何十倍も遅くて、しかも実行して初めてエラーがわかったり意味不明な仕様に気をつけながらPHPを使う人達、マジ気の毒(TT)
F#でもHaxeでも好きに使ってろ、って感じだろうけど、俺は今でも悩んでいる。
F#はすばらしい。関数型言語はすばらしい!
だが学習コストが高い!
だから使える人が少ない!人気がない!
だからF#やHaxeみたいなマイナー言語を使うと、書いた俺がずっとメンテナンスしなくちゃいけない!
援軍なしに一人で敵を倒しまくる真・三國無双みたいな状態になる。
やっぱ数は力だよなぁ。
長いものには巻かれろとは良く言ったもんだよ。
悔しいなぁ。
それでも俺はF#とHaxeで行けるところまで行くつもりだけどね。
|OCaml| |Smalltalk| です。
許してやろうじゃねえか・・・! 寛容な精神で・・・・・・・・・・!
ダウンロード
まだサンプルがJavaScriptで動作するだけですが、夢への第一歩です。
EnchantHX.zip
コード例
enchant.jsのsample1の移植
http://enchantjs.com/ja/sample.html
package ; import js.Lib; import EnchantHX; class Bear extends HxSprite { public function new() { super(32, 32); x = 8; y = 8; image = Main.game.assets.get('chara1.gif'); addEventListener(event_ENTER_FRAME, function(e) { // check input (from key or pad) on every frame if (Main.game.input.right) { x += 2; } if (Main.game.input.left) { x -= 2; } if (Main.game.input.up) { y -= 2; } if (Main.game.input.) { y += 2; } }); } } class Main extends HxGame { public static var game : HxGame; function new() { super(320, 320); fps = 24; preload(['chara1.gif']); // The images used in the game should be preloaded onload = function() { var bear = new Bear(); // add bear to rootScene (default scene) rootScene.addChild(bear); // display d-pad var pad = new HxPad(); pad.x = 0; pad.y = 224; rootScene.addChild(pad); rootScene.backgroundColor = '#aaaaaa'; }; start(); } static function main() { game = new Main(); } }
解説
クラスがJavaScriptのプロトタイプベースからJavaライクなクラスに変わっているので見た目がだいぶ違いますが、基本的に一対一でベタに移植したものです。
名前が衝突しないようにSprite -> HxSpriteのように、クラス名にHxが付きます。
haXeは可変長の引数を許さないため、preloadはリストを受け取るようになっています。
preloadしたリソースはassetsから取得しますが、assetsは単なるオブジェクトではなくHxAssetクラスのgetメソッドで取得します。
enchant.jsのシューティングゲームサンプルの移植
package ; import js.Dom; import js.Lib; import EnchantHX; import EnchantUtil; class Main extends HxGame { public static var game : Main; public static var player : Player; public var touched : Bool; public var score : Int; public static var enemies : IntHash<Enemy>; public static var scoreLabel : HxScoreLabel; public static function rand(r:Float) : Float { return Math.random() * r; } public function new(w:Int, h:Int) : Void { super(w, h); } static function main() { game = new Main(320, 320); Lib.window.onload = game.run; } function run(e:Event) : Void { game.fps = 24; game.score = 0; game.touched = false; game.preload(['graphic.png']); game.onload = function() { player = new Player(0, 152); enemies = new IntHash<Enemy>(); game.rootScene.backgroundColor = 'black'; game.rootScene.addEventListener(event_ENTER_FRAME, function(e){ if( rand(1000) < game.frame / 20 * Math.sin(game.frame / 100) + game.frame / 20 + 50){ var y = rand(320); var omega = y < 160 ? 1 : -1; var enemy = new Enemy(320, y, omega); enemy.key = game.frame; enemies.set(game.frame,enemy); } scoreLabel.score = game.score; }); scoreLabel = new HxScoreLabel(8, 8); game.rootScene.addChild(scoreLabel); } game.start(); } } class Player extends HxSprite { public function new(x:Int, y:Int) : Void { super( 16, 16); this.image = Main.game.assets.get('graphic.png'); this.x = x; this.y = y; //this.frame = 0; Main.game.rootScene.addEventListener(event_TOUCH_START, function(e:Dynamic) { Main.player.y = e.y; Main.game.touched = true; } ); Main.game.rootScene.addEventListener(event_TOUCH_END, function(e){ Main.player.y = e.y; Main.game.touched = false; }); Main.game.rootScene.addEventListener(event_TOUCH_MOVE, function(e) { Main.player.y = e.y; } ); this.addEventListener(event_ENTER_FRAME, function(e) { if(Main.game.touched && Main.game.frame % 3 == 0){ var s = new PlayerShoot(this.x, this.y); } }); Main.game.rootScene.addChild(this); } } class Enemy extends HxSprite { var omega : Float; var direction : Float; var moveSpeed : Float; var time : Float; public var key : Int; public function new(x:Float, y:Float, omega){ super(16, 16); image = Main.game.assets.get('graphic.png'); this.x = x; this.y = y; frame = 3; time = 0; this.omega = omega; this.direction = 0; moveSpeed = 3; addEventListener(event_ENTER_FRAME, function(e){ move(); if(this.y > 320 || this.x > 320 || this.x < -this.width || this.y < -this.height){ this.remove(); }else if(this.time++ % 10 == 0){ var s = new EnemyShoot(this.x, this.y); } }); Main.game.rootScene.addChild(this); } public function move(){ direction += Math.PI / 180 * this.omega; x -= this.moveSpeed * Math.cos(this.direction); y += this.moveSpeed * Math.sin(this.direction); } public function remove() : Void{ Main.game.rootScene.removeChild(this); Main.enemies.remove(this.key); //delete this; } } class Shoot extends HxSprite { var direction : Float; var moveSpeed : Float; public function new (x, y, direction){ super(16, 16); image = Main.game.assets.get('graphic.png'); this.x = x; this.y = y; this.frame = 1; this.direction = direction; moveSpeed = 10; addEventListener(event_ENTER_FRAME, function(e){ this.x += moveSpeed * Math.cos(direction); this.y += moveSpeed * Math.sin(direction); if(this.y > 320 || this.x > 320 || this.x < -width || this.y < -height){ remove(); } }); Main.game.rootScene.addChild(this); } public function remove(){ Main.game.rootScene.removeChild(this); } } class PlayerShoot extends Shoot { public function new (x, y) : Void { super(x, y, 0); addEventListener(event_ENTER_FRAME, function(e){ for(i in Main.enemies){ if(i.intersect(this)){ remove(); i.remove(); Main.game.score += 100; } } }); } } class EnemyShoot extends Shoot { public function new (x, y) : Void{ super(x, y, Math.PI); this.addEventListener(event_ENTER_FRAME, function(e){ if (Main.player.within(this, 8)) { Main.game.end(Main.game.score, "SCORE: " + Main.game.score); } }); } }