ようこそ。睡眠不足なプログラマのチラ裏です。

F# Build Tools for Unity(ゲームのやつ) - UniFSharpのご紹介

これは F# Advent Calendar 2014の延長戦、 30 日目の記事です。

f:id:zecl:20141229010705j:plain

書いたきっかけ

結局、25日に間に合いませんで。ゆるふわ #FsAdvent に急遽参加しました。そんなわけで、ML Advent Calendar 2014も合わせてどうぞ。 この記事は非常に誰得でニッチな内容を扱います。ほとんどの場合役には立たないでしょう。F# らしい成分もあまりありませんので、まあ適当に流してください。


UniFSharpとは?

UniFSharpは、私が無職だった(ニートしていた)ときに作成した Unityエディタ拡張 Assetです。割と簡単に導入することができます

f:id:zecl:20141229020738p:plain

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のゲーム開発がしやすくなります。いわゆる、"作ろうと思えば作れるの知ってるけど、面倒くさくて誰もやらなかったことをやってみた系のツール"です。まぁ、実際やるといろいろ大変。また、オープンソースヒロインのユニティちゃん(ユニティ・テクノロジーズ・ジャパン提供)をマスコットキャラクターに採用しました。ユニティちゃんの音声で時報やイベント、ビルド結果の通知を受けられるという、本来の目的とはまったく関係のない機能も提供しています。


Unityを使うならまぁ当然 C# 一択です。がまぁ、趣味で使う分にはフリーダム。


1000 人 Unity ユーザがいるとすると、その中の 0.01 人は F# ユーザーかもね(適当)


ちなみに、UniFSharp自体も F# で書かれています(ちょっとC# Scriptが混ざってます)。そう、基本的には F#で Unity のほとんどの部分(エディタだろうがゲームだろうが)を書くことができます。この記事では、UniFSharpが提供する機能および、それがどのように実装されているのかについて書きます。ここで紹介でもしないと、GitHubリポジトリを誰も覗いてくれることもないでしょうし。ハイ。

ご利用の際は、まぁいろいろあると思います(お察し)。覚悟しましょう。

この記事を読むその前に...むろほしりょうたさんの初心者がF#をUnityで使ってみた!という記事をオススメします。


F# Scriptの作成

Unityのエディタ拡張では、カスタムメニューを簡単に作ることができます。

f:id:zecl:20141224002558p:plain

f:id:zecl:20141224002627p:plain


F#で実装する場合、Moduleに定義した関数にMenuItem属性を付けるとよいでしょう。


UnityのEditorWindowは、ScriptableObjectインスタンス化されたものです。ShowUtilityメソッドを実行すると、必ず手前に表示し続け、タブとして扱えないウィンドウを作れます。C# で作る場合と基本的に同じです。難しくないですね。以下のウィンドウでは、選択されたテンプレートファイルを元に、F# Scriptを生成するという機能を提供しています。

f:id:zecl:20141224002702p:plain



F# Scriptのテンプレートの例


テンプレートファイルを元に F# Script ファイルを生成したら、その生成したファイルを Unity エディタに Asset として認識させる必要があります。認識をさせないと、Unity の Projectウィンドウ上に表示されません。Assetとして登録する場合、F# Scriptファイルの名前の編集が確定したタイミングで行うようにします。EndNameEditActionクラスを継承し、Actionメソッドをオーバーライドして実装します。AssetDatabase.LoadAssetAtPathで、F# ScriptをUnityEngine.Objectとして読み込み、ProjectWindowUtil.ShowCreatedAssetで、Projetウィンドウ上に表示させることができます。

f:id:zecl:20141224002941p:plain



ちなみに、Visual F# Power Tools(VFPT)では、フォルダ名はプロジェクト全体で一意である必要があるので、UnityのProjectウィンドウ上で階層をフリーダムに作られると厄介なので、そのあたりの階層構造も一応 チェックしていたりという感じです。変な階層を作られると、.fsprojファイルがぶっ壊れて開けなくなっちゃいますからね。




Inspectorで F# コードのプレビューを表示

Inspectorウィンドウで F#コードのプレビューを表示するためには、カスタムエディタを作成します。ただし、カスタムエディタはDLLのみでは実装を完結することができないため(謎の制約)、C# Scriptで。 http://forum.unity3d.com/threads/editor-script-dll-and-regular-script-dll-not-adding-custominspector-scripts.107720/

f:id:zecl:20141224002941p:plain


Editorを継承しOnInspectorGUIをオーバーライドし、Projectウィンドウで選択されたF# Scriptを読み込んで表示するよう実装します。雑ですが以上。

F# DLL のビルド

Unity上から MSBuildでビルドするだけの簡単なお仕事です。これといって特筆すべきことはありません。誰かソースきれいにして。


UniFSharpでは、ビルドの結果をユニティちゃんが通知してくれます。ビルドエラーだとこんな感じ

f:id:zecl:20141224003402p:plain


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


これはきな臭い...。UniFSharpがWindows専用であることが滲み出ているコードですね。はい(真顔)




あと、Retryビルダー。アッハイ。モナドじゃねえっス。


UniFSharpのオプション画面

ユニティちゃんの背景が印象的な画面です。

f:id:zecl:20141224003556p:plain


このオプション画面で、作成するF# プロジェクトの構成の詳細を設定できます。細かい説明は省きます(雑。

ユニティちゃんの機能もろもろ

ユニティ・テクノロジーズ・ジャパンが無償で提供してくれているユニティちゃんのAsset に同封されている多彩な音声。せっかくあるので使ってみたい。特に「進捗どうですか?」とか使わない手はない。そういや、いわるゆる萌え系だとか痛い系のIDEって結構あるけど、しゃべる感じのやつってあんまりないよなぁ。とかいうのが一応実装動機ということで。

f:id:zecl:20141224003648p:plain


  • ・起動時ボイス(ON/OFF)
  • ・ビルド時ボイス(ON/OFF)
  • ・進捗どうですか?(ON/OFF, 通知間隔指定あり)
  • ・時報通知のボイス(ON/OFF)
  • ・イベント通知のボイス(ON/OFF)
  • ・誕生日のお祝い(ON/OFF, 日付を指定)

f:id:zecl:20141224003918p:plain


F#でUnityゲーム開発する気はなくても、Unityをお使いの方で、ユニティちゃんに「進捗どうですか?」とか言われたい人は、まぁ使ってみてくださいという感じで(適当)。

Unityエディタ上で、音声ファイルを再生したい系の人は上記のような感じのをひとつこさえておけば、ハカドルかもね。

f:id:zecl:20141224003821p:plain


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も利用できますし、めしうま状態必至。



おまけ

Unityえふしゃーぷまん達


意外といらっしゃる。もちろんこれですべてではない。

Unity は良くできているゲームエンジンなので、F# でも使いたい!という気持ちはわかりますが、一般的には、F# でゲームを作りたいなら MonoGame あたりを選択する方がかしこいんじゃないでしょうか。はい。とは言え、 身の回りにUnity F# マンがいたら、ぜひとも情報交換などしてみたいですね。

ところで、わたくしごとで恐縮ですが、8か月以上という長いニート期間を終え、 12/1 から株式会社グラニで働いております。みなさんご存じ「最先端のC#技術を使った」ゲーム開発をしている会社です。とてもよい環境で仕事をさせていただいています。ということでわたくし現在東京におりますので、F# 談話室がある際にはぜひ遊びに行きたいです。趣味のF#erからは以上です。

広告を非表示にする