DENXブログ

同志社大学 電気情報研究会(DENX)の活動や日常風景などを紹介します。

mruby On Unity

この記事はUnity 2 Advent Calendar 2015 21日目の記事です。

 

はじめに

はじめましてfinoです。 技術系のサイトではyaegakiという名前を使っています。 今回は自分の所属している電気情報研究会(通称DENX)の宣伝もかねてここで記事を書いています。 よろしくお願いします。

この記事は基本的にWindowsで動作を確認していますが、MacLinuxを使用している人は適当に読み替えてください。 おそらくWindowsで環境を構築するより簡単だと思うので。

概要

rubyをUnity上で動かそうというものです。

rubyIronRubyとmruby

Unity上でrubyを動かしたい場合まず初めにIronRubyが思い浮かびます。 IronRuby.NET Framework上で動くrubyですが、2011年3月以降更新がなく色々と不安な感じがします。

そこで次に思い浮かぶのが組み込み向けの軽量rubyであるmrubyです。 mrubyは最近も活発に開発されており、さらに元々組み込み向けということもありiOSAndroid向けにビルドすることもできます。 RubyKaigi 2015に参加したときからmrubyで何か作りたいと思ってたこともあって今回はmrubyを選択しました。

事前準備

ソースの入手

まず初めにmrubyのダウンロードページにいってStable版をダウンロードします。 もちろんgithubの最新のソースを使用しても大丈夫です。 この記事執筆時のmrubyのStable版は1.2.0でした。

ビルドに必要なツールのインストール

次にmrubyのビルドに必要なツールをインストールします。 ビルドに必要なツールは以下の3つです

Visual Studio

ここからダウンロードしてください。 間違えないとは思いますがVisual Studio CodeではなくVisual Studio Communityのほうをインストールしてください。 おそらくVisual Studio2013などが既に入っている人はそれでも大丈夫です。

ruby

mrubyのビルドにはまずrubyが必要です。 RubyInstallerを使用すると楽にインストールすることができます。 とりあえず最新版を入れ解けば大丈夫でしょう。 インストール時には実行ファイルにPATHを通すようにしましょう。

bison

ここからComplete package, except sourcesをダウンロードします。 もしBinariesのほうを使用する場合はDependenciesも一緒にダウンロードし、bison.exeと同じフォルダにdllファイルを配置してください。 これもbison.exeにPATHを忘れないようにしてください。

mrubyのビルド

mrubyは普通のrubyと違ってWindowsでもほとんど何もすることなくビルド可能です。

まずVisual Studio コマンド プロンプトを開きます。 Visual Studio コマンド プロンプトはcl.exeなどのコマンドラインツールにPATHが通った状態で始まるのでコマンドラインからビルドするときにはこれを使います。 Visual Studio コマンド プロンプトは色々種類がありますが、32bit向けにコンパイルするならVS2015 x86 Native Tools、64bit向けにコンパイルするならVS2015 x64 Native Toolsを使用してください。 殆どの場合VS 2015 x64 Native Toolsのほうで大丈夫でしょう。

次にmrubyのフォルダに移動し

ruby minirake

を実行します。 すると下の画像のようにコンパイルが始まります。 ruby_minirake

とくにエラーもなく終わった場合以下のようになります。(少し上にスクロールしていますが) build_summary

もし以下のようなエラーが出た場合は普通のコマンドプロンプトで実行してしまっているか、古いバージョンのVisual Studio コマンド プロンプトを使用している可能性があります。 この場合は現在インストールしているVisual Studioに対応したVisual Studio コマンド プロンプトで実行してください。 ruby_minirake_fail

他のエラーが出ている場合はエラーメッセージを読みながら頑張って修正してください。

ビルドが成功している場合はbinフォルダの下にmruby.exeやmirb.exeが生成されています。

mruby.exeはmrubyの実行ファイル、mirb.exeはirbのmruby版です。

適当に遊んでみるとちゃんとrubyのコードが実行できていることがわかります。

mruby_test

ビルド設定の変更

mrubyのビルド設定はbuild_config.rbに書いてあります。 build_config.rbについては mrubyのビルド方法 を参考にしてください。 だいたいはそのままでも大丈夫ですがせっかくなので依存ファイルが少なくなるようにビルドしてみましょう。

まずデフォルトの設定でビルドした場合以下のようになります。(dumpbinの依存ファイルを調べるオプションを使用しています)

mruby_dependents

これは実行ファイルがKERNEL32.dllのほかにVCRUNTIME140.dll等に依存していることを示しています。 このままではこのファイルをVisual StudioのインストールされていないPCに持っていいった場合、起動することができません。 この場合、コンパイル時に/MTオプションをつけてコンパイルすることで依存ファイルを少なくすることができます。 コンパイル時に/MTオプションをつけるためには以下のようにします。

デフォルトの設定では/MDでコンパイルしているのでそれを/MTに変更しています。 この設定をbuild_config.rbに追加した後、ビルドしなおすと以下のようになります。 もしエラーが出る場合はruby minirake cleanを実行した後に再ビルドしてください。 mruby_dependents_2

KERNEL32.dllとADVAPI32.dllはほとんどのPCに入っているためこの実行ファイルは他のPCに移動しても起動することができます。

mrubyをC(C++)から使用する

すごく長かったですがここからがmrubyとUnityをつないでいく作業です。 mrubyをUnity上で動かすためにC(C++)で作成したdllファイルをC#で読みこむという方法をとります。 CでもC++でもどちらでもいいですが自分はC++が好きなのでそっちを使います。

mrubyをC++から読み込むために必要なファイルはincludeフォルダの下のヘッダファイルとビルドしたmruby.libファイルです。

まずはdllではなくコンソールアプリケーションでテストしてみましょう。 とりあえずVisual StudioでWin32 コンソールプロジェクトを作成します。 作成するときの設定は以下のようにします。

console-setting

そして適当に.cppファイルを作成したのち、プロジェクトの設定ファイルを開きます。 (作成した後でないとC/C++の設定がでてこないのでまず作成してください。)

プラットフォームをx64に変更したのち、 C/C++ > 全般 > 追加のインクルードディレクトリにmruby\include C/C++ > コード生成 > ランタイムライブラリを/MTか/MTd リンカー > 全般 > 追加のライブラリディレクトリにmruby\build\host\lib リンカー > 入力 > 追加の依存ファイルにlibmruby.lib に設定してください。

mruby-proj-include-path mruby-proj-mtd mruby-proj-lib-path mruby-proj-dep

プロジェクトの設定が終わったら64bit向けにビルドするようにターゲットをx64に変更します。

mruby-target-x64

これで設定は完了でようやくコードが書けます。 とりあえず以下のコードを入れて実行してみてください。

何もエラーが出なかったら以下のような実行結果になります。

mruby-first-run

もしエラーが出る場合は正しく設定できているか確認してみてください。

これでC++でmrubyを実際に使用することが可能になりました。

DLLを作成する

ここからがmrubyとUnityをつないでいく作業です。

DLLを作成するためにはWin32プロジェクトを作成します。 設定は以下のようにしてください。

mruby-dll-setting

プロジェクトの設定はコンソールプロジェクトで設定したものを同じように設定してください。

C++で作成したDLLをUnityから使用するためには関数をエクスポートする必要があります。 関数をエクスポートするためには以下のように書きます。

エクスポートの仕方がわかったのでmrubyを使用するためにmrb_open、mrb_close、mrb_load_stringをラップしたものをエクスポートします。

これでビルドするとプロジェクトのフォルダ/x64/DebugにDLLが作成されています。

UnityでDLLを使用する

Unityでプロジェクトを作りPlugins/x64フォルダに先ほど作成したDLLを配置します。 Pluginsフォルダはどこに作ってもいいのでどこかに作りましょう。

DLLを使用するためのC#のコードを書きます。

このスクリプトを適当なオブジェクトにアタッチしてエラーが出なければDLLの作成がうまくできています。

Unityの関数をmrubyから使用するために

作成したDLLをUnityで使用することはできましたが、mrubyのコードを実行したところでUnityの世界に反映することができません。 そこでC#の関数をC++に渡してそれをmrubyから呼び出してもらうことでその問題を解決します。

C#の関数を受け取りmrubyに登録する

まずはC++側を作成していきます。 C#から関数を受け取る部分は関数ポインタを使用します。 今回はDebug.Logをmrubyの世界に持っていくコードを作成します。 少し長くなってきたのでコメントを参考にコードをみて理解してください。

C#からC++に関数ポインタを渡す

C#で関数のポインタを取得するためにはまずデリゲートを作成し、Marshal.GetFunctionPointerForDelegatでデリゲートから関数ポインタを取得する必要があります。 デリゲートから取得した関数ポインタをC++に渡すことができればあとはC++で定義したmrubyの関数を呼ぶと完成です!

最後に

今回はWindows向けに作成しましたがiOS向けやAndroid向けなどにすることも可能だと思います。 また、mrubyをUnity上で実行することはあまり需要がないかもしれませんがサーバでRuby on Railsを使っている場合などは一部のコードをUnity側と共有できるかもしれません。

mruby-on-unity gifになっているのでクリックしてみてください。

明日は@rodostwさんの記事です。