HaxeでHashLink/SDLを使ってみる

> 追記：SDLとOpenALの導入のくだりは、自分でHashLinkをビルドする時にするものでした。必要ないので削除しました（恥

全くと言って良い程に日本語の情報がない**HashLink**を、恐る恐る使っていきます。

## そもそも

[HashLink](https://hashlink.haxe.org/)とは、皆さんご存知（でもない）[Haxe](https://haxe.org/)のターゲットとして、2016年に追加されたプラットフォームです。

ホームページを見てみるとわかると思いますが、「*HashLinkはHaxe専用のVMです*」と堂々と銘打っています。
そもそも開発者はHaxe FoundationもといNicolas Cannasse（Haxe、Nekoの生みの親）氏ですので、まさにHaxeによるHaxeの為のプラットフォームと言った所でしょうか。

そして、先ほども述べた通りHashLinkは**仮想マシン**なのですが、一方で**コンパイラ**でもあるというちょっと特殊な構成をしています。

## それってNekoと若干被ってない？

そう、Haxeには[Neko](https://nekovm.org/)という、これまたHaxe専用のVM（正確には、Neko VMで動作するNeko言語に変換しています）があったはず。
なぜ今になって新しいプラットフォームを打ち出してきたのでしょう？

実は、Nekoが登場したての頃はHaxeと独立した言語としてリリースされていた事もあり（今でもそうだとは思うのですが、実質Haxe専用ですよね）、ちょっとHaxeとは相性が悪かったのだそうで。

例えば、Nekoは**動的型付け言語**です。
Haxeは静的型付け言語だからこその高速な動作をウリにしているのですから、それならC++等に変換して使う方が良いですよね。わざわざNekoを使うメリットは薄いように思えます。

一方HashLinkは**静的型付け言語**ですので、その点に限ってもHashLinkの方がHaxeとの相性が良いと言えるでしょう。

また、HashLinkは将来的に**モバイル**と**コンシューマゲーム**に対応する事がアナウンスされています。
コンシューマっていうとPS4、Vita、Xboxあたりですかね。これは期待です。

## HashLinkのコンパイルターゲット

HashLinkでのコンパイルとは、Haxeと同様**他の言語に変換する**事を意味します。

Haxeで`-hl`オプションを付けてコンパイルするとHashLinkバイトコード（**.hl**）を吐き出すので、それをHashLink（hl.exe）に渡してやればコンパイルできます。

Haxeは、HashLinkを含めC++やJavaScriptなど様々な言語に変換できる言語でしたね。
ではHashLinkはどんな言語に変換してくれるのかと言いますと、それがなんと**C**（！）なのですよ。
CですよC。ロストテクノロジーです。
まぁ、パフォーマンスを追求するのならCは最良の選択肢なのでしょう。
私達がCを書かされる訳でもないですし、さほど問題はありません。

そして、HashLinkそのものもCで書かれています。
HashLink開発者の方は、あんな開発効率の悪い言語を書かなきゃならないのですね…さぞ大変な事でしょう。
Nicolas氏はすごい楽しんで書いてそうだけど。

Cに変換するほか、バイトコードを直接**HashLink VM**上で実行する事も可能です。
パフォーマンスはCに劣るとはいえ、NekoやV8エンジン上のNode.jsより高速に動作するそうで、開発時にはぜひこちらを利用してくれとの事。
デバッグ時はHashLink VMで、最終リリース時はCでって感じで使い分けると良いかと思います。


あ、そうそう。
現状、HashLinkは**Windows**と**Linux**にしか対応していません。
Cに書き出した後からならどうとでもなると思いますが、VMの実行やコンパイルそのものは**macOSではまだできない**のでご注意を。


今見てみたらこの記述は消えていて、代わりにmacOSでのビルド方法が書いてありました。
まだバイナリでのリリースはされていないようですので、自分でビルドする必要があります。

## HashLinkでできる事

HaskLinkでは、Cのライブラリである[SDL](https://www.libsdl.org/)の主要な機能をサポートしています。
サポートしている機能の中には、ウィンドウ生成やジョイパッドの管理など様々な機能が含まれていますが、最も重要な点は**OpenGLをフルサポートしている**という点でしょう。これは大きい。

HashLinkはSDL以外にも、Cのサードパーティ製ライブラリを幾つか内包しています。

- [Bullet](http://bulletphysics.org/wordpress/) - 3D物理エンジン
- [DirectX](https://www.microsoft.com/ja-jp/directx/) - Win専用のマルチメディアAPI（一部のみ）
- [FFmpeg](https://www.ffmpeg.org/) - マルチメディアエンコーダ
- [libjpeg-turbo](https://libjpeg-turbo.org/) - JPEGのエンコード/デコード
- [libmesa](https://www.mesa3d.org/) - OpenGLベースの3Dグラフィックス
- [libpng](http://www.libpng.org/) - PNGのエンコード/デコード
- [libuv](http://libuv.org/) - 非同期IOによるイベントループ
- [libvorbis](https://xiph.org/vorbis/) - Ogg/Vorbisのエンコード/デコード
- [mbed TLS](https://tls.mbed.org/) - SSL/TLS通信のサポート
- [OpenAL](http://openal-soft.org/) - 高度な音声処理
- [PCRE](http://www.pcre.org/) - Perlの正規表現
- [SQLite](https://www.sqlite.org/) - データベース管理
- [Steamworks API](https://partner.steamgames.com/) - Steamでのリリースに必須
- [zlib](https://zlib.net/) - 汎用可逆圧縮アルゴリズム

現状ではこんなもんでしょうか…？

SDLとDirectX、OpenALについては、HaxeLibにライブラリが用意されています（[hlsdl](https://lib.haxe.org/p/hlsdl/)、[hldx](https://lib.haxe.org/p/hldx/)、[hlopenal](https://lib.haxe.org/p/hlopenal/)）。
Bulletについても、まだHaxelibには登録されていないようですが、HashLinkの[Githubリポジトリ](https://github.com/HaxeFoundation/hashlink)にhlbulletが置いてあります。
Steamworks APIもBulletと同様、Heapsの[Githubリポジトリ](https://github.com/HeapsIO/hlsteam)に置いてあります。

それ以外は、Haxeの標準ライブラリにそれぞれ対応しているものが用意されているはず。多分。

また、Windowsに限り幾つか**UI**ライブラリが用意されています。
一部のUIしかないようですが、アラートウィンドウなど、欲しい所はきちんと用意してあります。

---

## **こんにちは世界**

いつもの。
とは言っても、普通にtraceするだけです。

あらかじめ[ここ](https://github.com/HaxeFoundation/hashlink/releases)からHashLinkをダウンロードしておきましょう。
PATHを通しておくとよりgood、コンパイル用のバッチを書いておくと完璧です。

```haxe:Main.hx
package;

class Main
{
  static function main()
  {
    trace("Hello, World!");
  }
}
```

```hxml:build.hxml
-cp src
-dce full
-hl test.hl
-main Main
```

これでコンパイルすれば、カレントディレクトリに**test.hl**が生成されます。

後は、hl.exeにtest.hlを渡してあげればオーケーです。

```console:
hl test.hl
src/Main.hx:7: Hello, World!
```

---

## **ウィンドウを表示してみる**

SDLを使って、ウィンドウを表示し3秒で閉じるプログラムを書いてみます。

hlsdlをインストールしましょう。`haxelib install hlsdl`でオーケーです。
この時に、hlopenalのインストールも自動で始まるはずです。もしされなかったら、手動で`haxelib install hlopenal`します。

導入が完了したら、Main.hxを以下の通りに編集します。

```haxe:Main.hx
package;

import sdl.Sdl;
import sdl.Window;

class Main
{
  static function main()
  {
    Sdl.init();
    var mainWindow = new Window("Test", 640, 480);
    Sdl.delay(3000);
    mainWindow.destroy();
    Sdl.quit();
  }
}
```

後はコンパイルして`hl test.hl`すれば、真っ白なウィンドウが3秒間表示されるはずです。

---

## 感想

色々と細かい部分がネイティブのSDLと違っていて戸惑いましたが、なんとかここまで漕ぎ着けられました…

HashLinkの情報に関しては、日本語はおろか英語の公式ドキュメントすらもほとんど整備されていません。
hlsdlなんか皆無ですよ。

幸いな事に、SDLに関しての情報はインターネット上にたくさん載っています。
これとhlsdlのソースコードとを照らし合わせつつ、じっくりと書いていくしか方法はありません。

みんなも、Haxe使おうね！（これが言いたかっただけ

---

### おまけ：ユースケース

HashLinkの使用事例が、既に**2件**もあります！
…多いのか少ないのか。
<br>

まずは、Shiro Gamesより[Northgard](http://northgard.net/)。
Shiro Gamesは、Nicolas氏とNCSoftの元CEOであるSebastien Vidal氏が設立したゲームデベロッパです。
[Evoland](http://evoland.shirogames.com/)が有名ですが、Nicolas氏がいるのだから当然Haxeで書かれています。地産地消とはこの事。

Northgardは、HashLinkとHeapsを使って開発されています。
[Heaps](https://heapsio.github.io/heaps.io/)とは、Haxe向けのゲームエンジンの事です。これまたNicolas氏が開発しています。過労死しないか心配。
<br>

もう1つは、Motion Twinより[Dead Cells](https://dead-cells.com/)。
Motion TwinもHaxeに非常に関わりのあるゲームデベロッパです。そもそも、HaxeはMotion Twinの社内プロジェクトである**MTASC**（ActionScriptの代替コンパイラ）から派生したプロジェクトでした。
同社がリリースしているゲームの多くもHaxeで実装されています。

Dead Cellsも、HashLinkとHeapsで開発されています。
しかし、こちらはなんとPS4、Nintendo Switch、Xbox Oneでのリリースもアナウンスされています。
Steam版のみHashLinkって感じなんですかね。

ちなみに、Heapsのリポジトリの中に[hlsteam](https://github.com/HeapsIO/hlsteam)というのが用意されています。
これは、HashLink向けにSteam APIを移植したもののようです。
恐らく、上記2つのゲームでもこれが使われているのではないかと思います。
<br>

…とまぁ、身内での使用事例がほとんどという現状でした。
しかし、HashLink（＋Heaps）の可能性は感じられたかと思います。みんなも積極的に使っていこうね。

---

誰かVSCodeのHashLink-Debuggerの使い方教えてください（小声