これは F# Advent Calendar 2014の延長戦、 30 日目の記事です。
書いたきっかけ
@zecl ML Advent カレンダーに書いてくださいよーw
F#の人達は知ってるけど、MLな人は知らないとかあるかもしれないですし。
— h_sakurai (@h_sakurai) 2014, 12月 10
結局、25日に間に合いませんで。ゆるふわ #FsAdvent に急遽参加しました。そんなわけで、ML Advent Calendar 2014も合わせてどうぞ。 この記事は非常に誰得でニッチな内容を扱います。ほとんどの場合役には立たないでしょう。F# らしい成分もあまりありませんので、まあ適当に流してください。
UniFSharpとは?
UniFSharpは、私が無職だった(ニートしていた)ときに作成した Unityエディタ拡張 Assetです。割と簡単に導入することができます。
Unityでのゲーム開発はMacで開発する方がなんとなく多い印象がありますが、わたしがVisual Studio使いたい勢ということもあり、こちらWindows専用となっています。Mac対応はそのうちするかも(?) というか、リポジトリ公開してますから、誰か適当にうまいことやっちゃってください。
上の動画の内容は少し古いですが、概要は伝わるかと。UniFSharpを使うと、Unityエディタ上のAssets/Create/F# Script/NewBehaviourScript
のメニューから選択するだけで、F# Scriptを作成できます。 そして、Unityエディタ上でF# ScriptをDLLにビルドすることができます(MSBuild利用)。 Visual Studio(IDE)とも連携するよう実装しており、これにより F#(関数型プログラミング言語)でUnityのゲーム開発がしやすくなります。いわゆる、"作ろうと思えば作れるの知ってるけど、面倒くさくて誰もやらなかったことをやってみた系のツール"です。まぁ、実際やるといろいろ大変。また、オープンソースヒロインのユニティちゃん(ユニティ・テクノロジーズ・ジャパン提供)をマスコットキャラクターに採用しました。ユニティちゃんの音声で時報やイベント、ビルド結果の通知を受けられるという、本来の目的とはまったく関係のない機能も提供しています。
UniFSharpはUnityのEditor拡張です。 ← わかる
Unity Editor から F# Scriptを作成できます。 ← わかる
ユニティちゃんの音声でビルド結果の通知する機能を提供しています。 ← ????
https://t.co/opuuLaNPdT
— みずぴー (@mzp) 2014, 8月 15
Unityを使うならまぁ当然 C# 一択です。がまぁ、趣味で使う分にはフリーダム。
1000 人 Unity ユーザがいるとすると、その中の 4 人は Boo ユーザらしい (戦慄)
— たけしけー (@takeshik) 2014, 9月 4
1000 人 Unity ユーザがいるとすると、その中の 0.01 人は F# ユーザーかもね(適当)
ちなみに、UniFSharp自体も F# で書かれています(ちょっとC# Scriptが混ざってます)。そう、基本的には F#で Unity のほとんどの部分(エディタだろうがゲームだろうが)を書くことができます。この記事では、UniFSharpが提供する機能および、それがどのように実装されているのかについて書きます。ここで紹介でもしないと、GitHubのリポジトリを誰も覗いてくれることもないでしょうし。ハイ。
ご利用の際は、まぁいろいろあると思います(お察し)。覚悟しましょう。
ExecutionEngineException: Attempting to JIT compile method 'Microsoft.FSharp.Core.FSharpFunc`\
誰だよF# がUnityで使えますとか言ったの
— 広告収入欲しさのユーチューバー (@tikal) 2014, 7月 12
この記事を読むその前に...むろほしりょうたさんの初心者がF#をUnityで使ってみた!という記事をオススメします。
F# Scriptの作成
Unityのエディタ拡張では、カスタムメニューを簡単に作ることができます。
F#で実装する場合、Module
に定義した関数にMenuItem
属性を付けるとよいでしょう。
UnityのEditorWindow
は、ScriptableObject
がインスタンス化されたものです。ShowUtility
メソッドを実行すると、必ず手前に表示し続け、タブとして扱えないウィンドウを作れます。C# で作る場合と基本的に同じです。難しくないですね。以下のウィンドウでは、選択されたテンプレートファイルを元に、F# Scriptを生成するという機能を提供しています。
F# Scriptのテンプレートの例
テンプレートファイルを元に F# Script ファイルを生成したら、その生成したファイルを Unity エディタに Asset として認識させる必要があります。認識をさせないと、Unity の Projectウィンドウ上に表示されません。Assetとして登録する場合、F# Scriptファイルの名前の編集が確定したタイミングで行うようにします。EndNameEditAction
クラスを継承し、Action
メソッドをオーバーライドして実装します。AssetDatabase.LoadAssetAtPath
で、F# ScriptをUnityEngine.Object
として読み込み、ProjectWindowUtil.ShowCreatedAsset
で、Projetウィンドウ上に表示させることができます。
ちなみに、Visual F# Power Tools(VFPT)では、フォルダ名はプロジェクト全体で一意である必要があるので、UnityのProjectウィンドウ上で階層をフリーダムに作られると厄介なので、そのあたりの階層構造も一応 チェックしていたりという感じです。変な階層を作られると、.fsproj
ファイルがぶっ壊れて開けなくなっちゃいますからね。
@zecl 詳しくは知らんですが、実際は階層構造でなく単に属性的に所属するフォルダとしてフォルダ名をヒモづけられてるのではと予想(´・ω・`)
— omanuke (@omanuke) 2014, 6月 25
@zecl @omanuke @haxe http://t.co/j9KW2eN9qt
Folder機能を作った本人も何故駄目なのかわからないって言ってますね。
実際 <Compile Include="1\2\1\1.fs" /> とかするとエラーになるんですがどこが悪いのか…
— yukitos (@yukitos) 2014, 6月 26
Inspectorで F# コードのプレビューを表示
Inspectorウィンドウで F#コードのプレビューを表示するためには、カスタムエディタを作成します。ただし、カスタムエディタはDLLのみでは実装を完結することができないため(謎の制約)、C# Scriptで。
http://forum.unity3d.com/threads/editor-script-dll-and-regular-script-dll-not-adding-custominspector-scripts.107720/
Editor
を継承しOnInspectorGUI
をオーバーライドし、Projectウィンドウで選択されたF# Scriptを読み込んで表示するよう実装します。雑ですが以上。
F# DLL のビルド
Unity上から MSBuildでビルドするだけの簡単なお仕事です。これといって特筆すべきことはありません。誰かソースきれいにして。
UniFSharpでは、ビルドの結果をユニティちゃんが通知してくれます。ビルドエラーだとこんな感じ
F# Scriptのドラック&ドロップについて
「UniFSharp を使えば F# Script ファイルをUnity上で作れる」とは言っても、実際にScriptファイルとして動作するようには実装していないくて、実際はDLL化したアセンブリをUnityで読み込んで利用しているため、通常は Projectウィンドウに表示しているだけの F# Scriptファイルを、Inspectorウィンドウにドラック&ドロップしGameObjectにComponentとして追加することはできません。UniFSharpでは、アセンブリの内容を解析して、疑似的に F# Scriptファイルをドラッグ&ドロップしているかのような操作感覚を実現しています。
F# DLLとF# ScriptからMonoBehaviourの派生クラスを探索するモードは2種類用意していて、1つは、F# Scriptファイルを読み取って、シンプルな正規表現でクラス名を抽出し、アセンブリからMonoBehaviourの派生クラスを検索する方法。もう一つは、F# ScriptファイルをF# コンパイラサービスを利用して、解析して厳密にクラス名を抽出する方法。前者は精度は低いが早い。後者は精度は高いが遅い。それぞれ一長一短がある。
カスタムエディタということで、F# コンパイラサービスを利用する部分を除いては、またC#。
F# コンパイラサービスを使って、F# Scriptファイルから名前空間を含むクラス名の探索はこんな感じ。
ところで、F# コンパイラサービスの対象フレームワークは .NET Framework4
以上です。いまはまだ Unityでこのアセンブリを読み込むことはできません。残念!!なのですが、ここで、Microsoftが提供しているILMerge
という神ツールを使う(苦肉の策)ことにより、それを回避し実現してる(アッハイ)。
F# Projectファイルの操作とVisual Studioとの連携
Unityエディタで F# Script を作成することをサポートしたということは、つまり、IDEとの連携もサポートするってことだよね。Projectウィンドウ上でF# Scriptファイルを追加したり、ファイルのパスを移動したり、ファイルを削除したタイミングで.fsproj
ファイル(XML) の内容が書き換わってくれないと、それぜーんぜん役に立たない。そういうこと。この実装がけっこー面倒くさかった...。
こんな感じ
Assetを追加・削除・移動した際に独自の処理をしたい場合は、AssetPostprocessor
を継承して適宜処理を実装する。さらに、それがUnityで標準では扱われないファイルの場合(まさに今回の F# Scriptがこの場合)には、OnPostprocessAllAssets
メソッドを実装する。そこで .fsproj
ファイルをごにょごにょすることで、これを実現できる。
コードは、こんな雰囲気(あばばばば)
また、UnityのProjectウィンドウ上でF# Scriptをダブルクリックした際に、Visual Studio上でそのファイルをアクティブにする動作を実現するために、EnvDTEを利用した。
http://msdn.microsoft.com/ja-jp/library/envdte.dte.aspx
UnityからEnvDTE叩こうとするとUnityが死ぬ^p^
— ぜくる (@zecl) 2014, 6月 25
これはきな臭い...。UniFSharpがWindows専用であることが滲み出ているコードですね。はい(真顔)
あと、Retryビルダー。アッハイ。モナドじゃねえっス。
UniFSharpのオプション画面
ユニティちゃんの背景が印象的な画面です。
このオプション画面で、作成するF# プロジェクトの構成の詳細を設定できます。細かい説明は省きます(雑。
ユニティちゃんの機能もろもろ
ユニティ・テクノロジーズ・ジャパンが無償で提供してくれているユニティちゃんのAsset に同封されている多彩な音声。せっかくあるので使ってみたい。特に「進捗どうですか?」とか使わない手はない。そういや、いわるゆる萌え系だとか痛い系のIDEって結構あるけど、しゃべる感じのやつってあんまりないよなぁ。とかいうのが一応実装動機ということで。
- ・起動時ボイス(ON/OFF)
- ・ビルド時ボイス(ON/OFF)
- ・進捗どうですか?(ON/OFF, 通知間隔指定あり)
- ・時報通知のボイス(ON/OFF)
- ・イベント通知のボイス(ON/OFF)
- ・誕生日のお祝い(ON/OFF, 日付を指定)
F#でUnityゲーム開発する気はなくても、Unityをお使いの方で、ユニティちゃんに「進捗どうですか?」とか言われたい人は、まぁ使ってみてくださいという感じで(適当)。
Unityエディタ上で、音声ファイルを再生したい系の人は上記のような感じのをひとつこさえておけば、ハカドルかもね。
MonoDevelop、Xamarin、Visual Studioで Unity の F# DLLデバッグ
UniFSharpとは直接は関係ありませんが、Unity で F# DLLをデバッグする方法も紹介しておきたい。
基本的には、Unity ユーザーマニュアルに書いてあるとおりにすればよいです。
Unity プロジェクトでの Mono DLL 使用 / Using Mono DLLs in a Unity Project
ということで、.fsproj
のビルド後イベントに、下記のような感じで設定しておくと捗るかもしれません(パスとかは適当に変えて)。
Visual Studio 2013 Tools for Unityが無償提供され、あらゆるアプリを開発できる最強の開発ツールとの触れ込みのVisual Studio 2013 Community Editionが無償提供されたことで、誰でもVisual Studio で Unityのデバッグ実行ができるようになりました。本当にいい世の中になったものです。F# をお使いなら、 Visual F# Power Toolsも利用できますし、めしうま状態必至。
あ、fsharp .org に VS2013 Tools for Unityを使えば、F# で書いたDLLをデバッグ実行できるYOとしれっと書いているが、誰得? http://t.co/YHUiTdqSCI
— ぜくる (@zecl) 2014, 12月 11
おまけ
Unityえふしゃーぷまん達
http://t.co/Fdux8rbZCb
FSharpをUnityでも使えるんだろうけど、dll作って、アセットフォルダに突っ込んで読み込みかぁ。さらさらっと出来ると嬉しいなぁ。しかし、やる気がないw
— h_sakurai (@h_sakurai) 2014, 12月 10
UnityをF# で使おう委員会
— 切れ痔 (@lmdexpr) 2014, 9月 1
ヤッター! UnityでFSharp動いたあぁー!!!
— c000 :: RealWorld → (@c255) 2014, 5月 27
unitychan2Dを F# へ移植してみた https://t.co/qV0YI1NkVh #fsharp #unitychan pic.twitter.com/5G2DT4V6Ci
— ぜくる (@zecl) 2014, 7月 12
Unityもっと安くならないかな……。あとついでにスクリプトがF#に対応してくれないかな……
— 徹人 (@t_tetsuzin) 2014, 6月 20
当然、Unity でオール http://t.co/kfcpCbcFQ2 で書くことも可能(誰得すぎて誰もやらない
— ぜくる (@zecl) 2014, 2月 18
「F# のコードをDLLにビルド→Unityプロジェクトに自動でコピー→MonoBehaviourのラッパーを自動生成」で快適なF# (on Unity)生活が送れるかと思ったけどImportAssetの待ち時間イライラするかも
— よだ (@n__yoda) 2014, 1月 28
@hamazy @florets1 @kazuhito_m 空いてたら僕は発表します。最近UnityとF# を使ってるのでそういうのはいいかなと思ってます。
— ダニー (@tataminomusi) 2014, 11月 6
UnityでF#使えるんなら使ってやらんこともない(上から目線)
— 自然界 (@mizchi) 2014, 5月 6
次期メジャーバージョンアップで「Unity、F# を開発言語としてサポート」とかならないかなぁ。API がそぐわないとか色々あるんだろうけど…
— Yu I. into VR (@japboy) 2014, 7月 24
えふしゃーぷでUnityは理想的には可能(趣味の範囲で)
— ぜくる (@zecl) 2014, 6月 29
"Unity によりサポートされないコンパイラを使用できる場合があり(例えば F#)" http://t.co/v0xX4sgUxS なので全部F#でイケるが、いろいろ制約あって謎のノウハウが必要なのでメリットよりもデメリットが多いので素人にはお勧めできない
— ぜくる (@zecl) 2014, 5月 17
意外といらっしゃる。もちろんこれですべてではない。
Unity は良くできているゲームエンジンなので、F# でも使いたい!という気持ちはわかりますが、一般的には、F# でゲームを作りたいなら MonoGame あたりを選択する方がかしこいんじゃないでしょうか。はい。とは言え、 身の回りにUnity F# マンがいたら、ぜひとも情報交換などしてみたいですね。
ところで、わたくしごとで恐縮ですが、8か月以上という長いニート期間を終え、 12/1 から株式会社グラニで働いております。みなさんご存じ「最先端のC#技術を使った」ゲーム開発をしている会社です。とてもよい環境で仕事をさせていただいています。ということでわたくし現在東京におりますので、F# 談話室がある際にはぜひ遊びに行きたいです。趣味のF#erからは以上です。