2012年12月1日土曜日

PySpa アドベントカレンダー 1日目 〜バカとPythonと芳泉閣〜

PySpaアドベントカレンダーというイベントに参加してみたところ、僭越ながら初日を努めさせていただくことになりました>< ということで本日は技術ネタではなくてPySpaというイベントとともに自分の職歴でも振り返ってみようと思います。


■そもそもPySpaってなんぞや

vの人という主犯格が定期開催している温泉旅館に泊まるイベントです。名前に反して実はPythonは全然関係ないです。詳細は以下のページとか見てみてください。
https://github.com/pyspa/pyspa
http://voluntas.hatenablog.com/entry/20081024/1218125470

基本的にvの人の知り合いばかりで固定PySpaメンバーと言えるメンバーがいるのですが、昔からいた人が仕事の都合とかで疎遠になると新しい人が定期的にやってきて全体が保たれているという感じの不思議な輪が形成されているのが特徴ではないかと思っています。後、全員やたら技術力があります。


■SIer時代(2008~2009年)

最初に参加したのが2008年に開催された第4回です。記憶が曖昧なのですが、確かTwitterだか何だかで参加者を探していたところに無理やり飛び込んだのがきっかけです。よくやった当時の自分。当時は新卒入社したSIerの会社でJavaを書いていて、Pythonって面白そうだなーとか考えて手を出していたころだったのでPythonの勉強会のノリで参加してました。あとそういえばiPhone 3Gを発売日当日に買い、Apple信者生活を開始しました。

第4回の記録
http://akisute.com/2008/10/4python-1.html

うん、今見たら恥ずかしくて死にたい。といっても年中後から振り返ったら恥ずかしくて死にたいようなことしかしてない気がするので今更気にしたら負けです。次行きます。次。
第5回からは完全にiPhone開発ばっかです。あとこの一年で随分PySpaのノリを理解した感じを文体から感じ取れます。

第5回の記録
http://akisute.com/2009/06/5-python.html

この期間は自分の基礎となる技術や興味を見つけることができた貴重な時期でした。最も向上心がありバックグラウンドもない新人時代を非常に有意義に過ごすことができたのではないかとおもいます。あと、今現在わずかに残っているのみとなった社会人として必要な常識などは全てこの時期に身につけさせていただきました>< 本当にありがとうございました><


■Web屋時代(2010年~2011年)

2009年末に新卒入社したSIerの会社を退職してビープラウドに転職しました。転職理由はもはや覚えていないのですが、確かこのままこの会社にいてはスキルアップにならない!よりよい環境へ移るべきだ!などという意識の高い社二病精神か何かが原因だった気がします。

このへんから面倒になったせいかPySpaメンバーの内輪みたいな感じになったせいもあるのかブログへの参加記録が途絶えてしまっていますが、PySpa自体には二年間毎回かかすことなく参加しておりました。というのもPySpa自体がビープラウドの非公式社外リクルートイベントみたいな感じになっていた関係上、半数近くの社員がPySpaに参加する時があったりしたからです。

例えば今回のアドベントカレンダー参加メンバーだと

12/1 akisutesama
12/3 tokibito
12/4 torufurukawa
12/8 shimizukawa

あたりがPySpa経由で雇用されたビープラウド社員だったりします。

第6, 7, 8, 9, 10と参加してきたPySpaですが、10回でいったん定期開催を締めようというvの人の考えで第10回を最後にしばらく開催が途絶えてしまいました。そのかわり定期開催する文化はPyFesへと引き継がれていきました。

この期間は良い意味でも悪い意味でも自分のアイデンティティが確立された期間でした。何か捨ててはいけないたぐいの常識を投げ捨ててしまった変わりに職業iOSプログラマとしてのキャリアが確立された感じでしょうか。あとは仕事でひどく失敗した時期でもありました。前職SIer時代では失敗ができるような機会はなかったのですが、ビープラウドでは数回ひどく失敗してご迷惑をお掛けしたことがありました。ほんとスミマセン>< お陰様で人類としての社会常識はなくなりましたがプロとして仕事を進める常識は多少身につきました><


■ゲーム屋時代(2012年~)

2012年の2月にビープラウドを退職して変なゲーム会社に転職して以来、しばらくご無沙汰していたPySpaですが、今年の10/26に開催されたのでふらっと参加してきました。

感想、みんな年食い過ぎ。

高齢化の並はPySpaにも押し寄せているのかいないのかわからんのですが、第4回第5回の頃の大学生のきゃっきゃうふふ的ノリはかなり鳴りを潜め、仕事の話をしたりだとかが増えたり徹夜組が全滅して朝早起きになってたりお菓子の減りが悪くなってたりと随所におっさん臭がしてきております。ピンチです>< まぁ時間の流れというのはそういうものなのかなぁと私自身おっさん的に思っております。

この期間は自分のこれまでの集大成であるような気がしています。子供の頃にハマりまくっていたゲームへの愛情と、SIer/Web屋時代に培ったサーバ側技術と、iPhoneリリースからやってきたiOS開発の集大成という感じです。そして随分と責任ある立場をまかされるようになってしまった気がします。うーん年だ。このあとどうしよう。とりあえず今しばらくはゲームが最高に面白いのでゲームをやろうと思ってます。

余談ですがうちらのゲームもうすぐリリースらしいです。一応宣伝。
http://www.donpy.net/appinfo/18791.html




■まとめ

こうして振り返ると私の仕事人生はiPhoneとPySpaとともに歩んできたんだなぁと思います。iPhoneは私に夢中になって開発できる何かをくれましたし、PySpaは私にスキルと人脈と情熱をくれました。この2つがあったからこそここまでやってこれたんだなぁと思っています。これからもまぁそんな感じで適当にやっていきます。

最後になりましたけれども、PySpaを毎年開催してくださっているvの人と、今回のアドベントカレンダーを企画していただいたとんぷーさん、どうもありがとうございます!

それでは明日はshkumagaiさんよろしくおねがいしまーす!

2012年11月12日月曜日

Unity 3.5 以下でプリプロセッサ定義を上手く使う方法

C/C++/Objective-Cベースのプロダクトのビルドシステムを構築するときに大変便利なのがプリプロセッサのdefineマクロです。defineマクロを使って環境を切り替えたり不要なログコードを削除したりなどは皆さんよくやってるかと思います。C#にも同様のプリプロセッサ定義が用意されているみたいですので、こちらを使ってUnityプロジェクトのビルドシステムを構築できないかと思ってやってみました。


■プリプロセッサ定義の使い方 (Unity 4以降)

Unity 4.0よりプリプロセッサ定義がUnity本体によってサポートされるようになりました!ビルドスクリプトからも自由にアクセスが可能になっており、非常に簡単に扱うことが可能です。
詳しくはけいごさんのブログに完璧にまとめられていますのでそちらをご覧ください。
http://anchan828.tumblr.com/post/32669868103/define


■プリプロセッサ定義の使い方 (Unity 3.5以降)

ここからが本題になります。Unity 3.5以前はプリプロセッサ定義を公式にサポートしていません。そこで以下の4種類のファイルをAssetsフォルダ直下に置くことでプリプロセッサ定義を読み込ませます。
/Assets/smcs.rsp (C#用)
/Assets/gmcs.rsp (C#エディタスクリプト用)
/Assets/us.rsp   (UnityScript、俗にJSと呼ばれている物用)
/Assets/boo.rsp  (Boo用)
このrspファイルにはC#コンパイラのコンパイラオプションとして渡すオプションが記述できます。ですので http://linux.die.net/man/1/mcs などに列挙されているコンパイラオプションであればひと通りなんでも使用可能です。今回はプリプロセッサ定義をやりたいので、以下のように書けばOKです。
-define:DEBUG
複数の定義が書きたい場合は、
-define:DEBUG -define:USE_DEV_SERVER
のようにスペースで空けて複数記載するか、
-define:DEBUG
-define:USE_DEV_SERVER
のように改行して複数記載するか、
-define:DEBUG;USE_DEV_SERVER
のようにセミコロンで列挙して書くことができます。注意点として、C/C++/Objective-Cのdefineマクロと違って
-define:DEBUG=1
のように値を定義することはできないみたいです。あくまでシンボルを作るだけみたいですね。

以下Twitterでのやりとりです。

さて、これでプリプロセッサ定義はバッチリできるようになったのですが、問題はこれをビルドごとに書き換える方法です。最初はビルドスクリプトでこのrspファイルを書き換えていたのですが、どうもこれをUnityが全く認識しないのです。普通にファイルをただ書き換えてもダメなようです。

そこで黒魔術を導入します。以下のスクリプトで使われているコードを利用して、無理やり書き換えた後のrspファイルをUnityに認識させます。
https://github.com/prime31/P31UnityAddOns/blob/master/Editor/GlobalDefinesWizard.cs#L131
AssetDatabase.Refresh();
reimportSomethingToForceRecompile();

private void reimportSomethingToForceRecompile()
{
 var dataPathDir = new DirectoryInfo( Application.dataPath );
 var dataPathUri = new System.Uri( Application.dataPath );
 foreach( var file in dataPathDir.GetFiles( "GlobalDefinesWizard.cs", SearchOption.AllDirectories ) )
 {
  var relativeUri = dataPathUri.MakeRelativeUri( new System.Uri( file.FullName ) );
  var relativePath = System.Uri.UnescapeDataString( relativeUri.ToString() );
  AssetDatabase.ImportAsset( relativePath, ImportAssetOptions.ForceUpdate );
 }
}
これでC#で書かれたコードに対しては無事にrspファイルへの変更が反映されるようになります。

しかしながら更に落とし穴があります。UnityScript(JavaScript)で書かれたファイルに対してはこの黒魔術が効きません。したがってUnityScriptで書かれたファイルに対して動的にus.rspファイルの定義を適用することができないようです。すべてのJSファイルに対して上記の黒魔術を適用しても効果がなかったため、おそらくダメだと思われます。


■結論

UnityScriptは使わないようにしましょう。

2012年11月11日日曜日

iOS 6.0の advertisingIdentifier と identifierForVendor にはバグがあるので注意

いささかタイミングを逃した感が強いのですが、厄介なバグにぶち当たってしまったので共有いたします。

iOS 6からUDIDに変わる識別子としてUIDeviceのidentifierForVendorとASIdentifierManagerのadvertisingIdentifierが使えるようになったのはすでにみなさんご存知かと思います。ですがどうもこやつらiOS 6.0だと正しく機能しない場合があるようなのです。

詳細は以下のとおり。
http://stackoverflow.com/questions/12605257/the-advertisingidentifier-and-identifierforvendor-return-00000000-0000-0000-000

こちらの情報元によると、iOS 6.0に Over-The-Air アップデート (iTunesを使わないで端末からアップデートする方法) するとこれらの識別子が常に00000000-0000-0000-0000-000000000000を返してしまうらしいのです!iOS 6.0.1では修正されているらしいです。

見事に私の UIApplication-UIID ライブラリもこのバグを踏んづけて大爆発してしまいました。

対処法としては生成されたIDが00000000-0000-0000-0000-000000000000でないか文字列比較する方法がよさそうです。

2012年9月26日水曜日

Unity の PostprocessBuildPlayer を使って Weak Framework を追加する方法

※2013/11/27追記: 第二版を公開しました。

UnityでiOSのアプリを作っていて困ることの一つに、iOSが提供するシステムフレームワークへのリンクをプロジェクトに追加するのが超面倒くさいという問題が挙げられます。UnityがiOSアプリを書きだした後、手動でXcode上からシステムフレームワークを追加してもいいのですが、これはとんでもなく面倒です。

そこでUnityジャパンの伊藤さんという方が PostprocessBuildPlayer という仕組みと Ruby の xcodeproj ライブラリを使ってビルド時に自動的にシステムフレームワークを追加する仕組みを公表してくださいました。お陰様で随分とはかどっていたのですが、その方法では実はシステムフレームワークをWeakリンク(Optionalリンク)することができなかったのです。これでは例えばSocial.frameworkを使うアプリをビルドしてiOS5で動かすと起動時に問答無用でクラッシュしてしまいます。困りました。iOS6/5両対応ができないと話になりません。

というわけで作りました。システムフレームワークをWeakリンクできるPostprocessBuildPlayerを。こちらです。


ライセンスはMITライセンスにしておきました。
使い方は大体見ればわかるかと思いますが、まず最初にgem経由でxcodeprojをインストールしておくこと。
sudo gem install xcodeproj
あとは上記のPostprocessBuildPlayerをUnityプロジェクトの /Assets/Editor 以下に配置して、コード中のフレームワーク名を指定している箇所をご自身のお好きなように変更してやればオッケーです。

Unity 3.5.5 以下で Game Center / iAd / UIImagePicker などを使用したアプリが iOS 6 でクラッシュする問題

現在 Unity 3.5.5 以下でビルドしたiOSアプリが、以下の条件をすべて満たしているとクラッシュしてしまう問題が発生しているようです。
  • UnityのiOSアプリビルド設定で、画面方向を横向き(Landscape Left/Landscape Right)のいずれかのみに設定している。
  • Pluginなどを経由してGame Centerを使用している。またはiAdやUIImagePickerなどのiOSが提供する特定のView Controllerを使用している。
  • iOS 6を搭載したiPhone/iPod Touch上で動作させる(iPadは大丈夫)。
詳細はこちら。
http://developer.coronalabs.com/forum/2012/09/17/ios-6-orientation-crash





すでにUnity側で問題は把握しているようで、現在修正版の3.5.6を用意してくださっているようなので、続報を待ちましょう。・・・といっても、すでにUnity 3.5.5以下でビルドされたiOSアプリをリリースしていて、しかもAsset Bundleを使用していたりすると、Asset Bundle間の後方互換性問題のためかなり厄介なことになると思われます。最悪過去のバージョンのサポートをすべて切る必要が出てくるかもしれません。


さて、ここからは技術話の余談です。

このクラッシュ問題なのですが、原因はiOS 6で変更になった画面回転(Auto Rotation)APIにあると思われます。iOS 6からはなんとこれまで画面回転に使用されていた
UIViewController shouldAutorotateToInterfaceOrientation:
が完全に廃止になっており、基本的には全く呼び出されないようになってしまっています。その代わりにより体型だった画面回転の仕組みが導入されています。iOS 6からの画面回転は、「アプリが対応する画面方向」と「各View Controllerが対応する画面方向」の2つによって画面の回転する方向が決定されるという仕組みになっています。

ここで、アプリが対応する画面方向は以下のように決定されます。
以下優先順位順に、
1. UIApplicationDelegate application:supportedInterfaceOrientationsForWindow: が返す向き。iOS 6以降のみ。
2. UIApplication supportedInterfaceOrientationsForWindow: が返す向き。iOS 6以降のみ。
3. Info.plist で指定されている UIInterfaceOrientation の向き。
各View Controllerが対応する画面方向は以下のように決定されます。
各ViewControllerが supportedInterfaceOrientations を実装しているなら、それが返す向き。
していないならば、
iPhoneだと UIInterfaceOrientationMaskAllButUpsideDown
iPadだと   UIInterfaceOrientationMaskAll
この2つの積集合をとって、両方が一致した向きに画面回転が行われる仕組みになっています。

では、ここで両者が全く一致しない場合はどうなるでしょう?答えは簡単でクラッシュします。ワオ。素敵。ふざけんなバカApple爆発しろ。

それを踏まえると、今回の問題でクラッシュしてしまう仕組みはこう考えられます。
  1. Unity 3.5.5以下が書き出すiOSアプリは当然ながらiOS 6に完全対応していない。
  2. Game Centerなど、Appleが提供しているUIコンポーネントは全てiOS 6の画面回転に対応しているが、それらのうち幾つかのものはiPhoneだと縦向き画面にしか対応していないものがある(iPadは基本縦横どちらでも表示できるように対応する必要があるとされているため、無事のようです)。
  3. Unityが書きだしたアプリは横向き画面にしか対応していないのに、上記のView Controllerは縦向きにしか対応していないと言い出すので、クラッシュする。
やれやれですね><
ちなみに対応策としては、アプリ自体は縦方向にも横方向にも対応しているというふうにapplication:supportedInterfaceOrientationsForWindow:メソッドを使って値を返すようにした上で、コンテンツを表示するUIViewをUIViewControllerに管理させるようにして、UIViewControllerのsupportedInterfaceOrientationsで横向き画面の値だけを返すようにするといいかんじになると思います。しかしながらiOS 5/6両方で上手く回る画面は結構大変そうです。

2012年8月19日日曜日

Unity のプラグインで iOS の bundle を使えるようにする方法

OS XやiOSには Bundle という仕組みがありまして、 NSBundle というBundleを扱うためのクラスが用意されています。皆様も一度は
[[NSBundle mainBundle] pathForResource:@"MyMusic" forType:@"mp3"];
みたいなコードを書いたことがあると思います。このBundleの仕組みを使うと、
  • 複数の画像や文言、JSONなどのデータファイル、音楽などを一つにまとめて扱うことができる。個別のファイルとしてプロジェクトに加えなくてよいので利便性が良い。
  • Bundleには最初から多言語化リソースを扱うための仕組みが用意されているため、多言語化が非常に簡単にできる。
  • OS Xだけになりますが、Bundleにはコンパイル済みのコードを含められるので、プラグインの仕組みが簡単にできる。
以上のようなメリットがあります。例えば実例を上げると、Facebook SDKなどがBundleの中に画像や文言などのリソースを格納して配布するようになっています。実際には確認できていないのですが、おそらくmobage, GREEのSDKもそのようになっているのではないでしょうか?ということでSDKなどを配布するときには非常に便利です。

で。このBundleによる配布はなかなか便利なので、UnityのiOSプラグインとして配布するときにも是非使いたいのですが、そのまま/Assets/Plugins/iOS以下にBundleを配置しても正しくBundleが認識されませんし、iOSのアプリにインストールされません。

そこでBundleを配布するときは、/Assets/Plugins/iOS/以下ではなくて、/Assets/StreamingAssets/以下にBundleを配置するようにしましょう。実は/Assets/StreamingAssets/以下のパスには隠し要素があって、このパス以下のファイル・ディレクトリは全てアプリケーション自身の/Data/Raw/ディレクトリに配置されるようになっています。
参考: http://sehm.blog48.fc2.com/blog-entry-159.html

あとはプラグインとして用意したiOSコードの中で以下のようにしてBundleを取得すればOKです。
NSBundle *bundle = [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:@"MyBundle" ofType:@"bundle" inDirectory:@"Data/Raw"]];
これでUnityプラグインを多言語化したり画像リソースを使ったりするのが楽になると思います。

将来的にUnityのバージョンが上がって、/Assets/Plugins/iOS/以下においたBundleも扱えるようにしてくれると楽なんですが・・・Unity 3.5の地点ではどうもダメっぽいです。

2012年7月25日水曜日

LLDB を使って CUI で動作させているテストケースをデバッグする

GHUnit のテストケースを Jenkins で自動的に走らせるために CUI のテストを作っているのですが、 GUI を使ったテストでは問題なく通るのに CUI を使ったテストのときだけテストが落ちるという問題が発生してしまいました。 Xcode 経由の実行であれば Instruments だろうが内臓のデバッガだろうが使い放題なのですが、 CUI となるとそうもいきません。そこで LLDB を直接使って CUI で動作させているテストケースを直接テストしてみることにしました。

参考にしたのはこちら。
http://lldb.llvm.org/tutorial.html

さっそくやってみましょう。lldbコマンドで LLDB の対話環境を起動した後、
process attach --name MyApp --waitfor
でMyApp.appという名前のプロセスが立ち上がるのを監視します。



この状態でMyApp.appというアプリを起動すると、上の画像のようにばっちり LLDB がプロセスを検知して捕まえてくれます。今、MyApp.appはポーズ中になっているので、適当な箇所に
breakpoint -f MyTestModel.m -l 123
とかやって適当にブレークポイントを設置した後、
thread continue
で続きを実行開始します。



ご覧のとおりバッチリブレークポイントで捕まえることに成功です。こちらの図はEXC_BAD_ACCESSが発生した時になんか自動的に止めてくれたときのものです。Xcode経由で起動するときに比べれば不便ですが、何もないよりはだいぶはかどりますよ。

2012年6月24日日曜日

__has_feature(objc_arc_weak) を使って賢く安全に ARC/Blocks を使う

iOS 6も発表されて、皆さんARCやBlocksをガンガン使用する感じのプログラミングスタイルに変化してきていると思うのですが、そこで問題になってくるのが後方互換性の話です。特にiOS 4。Blocksを使うとなるとどうしても以下の様に非同期で実行されたBlocksの中からViewを書き換えるようなコードを書きたくなるのですが、
__weak MyViewController *__weakSelf = self;
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse* response, NSData* data, NSError* error){
    __weakSelf.label.text = [[NSString alloc] initWithData:data encoding:NSUTF8Encoding];
}];
このようなコードを安全に実行するためにはselfを一度__weakな変数に代入して、それをBlocksにキャプチャさせるようにしないと、以下のような理由で安全ではなくなってしまいます。
  • __strongを使うと、対象の変数をキャプチャしているBlocksの実行が終わるまで対象の変数がreleaseされなくなるばかりか、最悪の場合は循環参照が発生してメモリが絶対に開放されなくなってしまいます。
  • __unsafe_unretainedを使うと、Blocksの実行が終わるまでの間に対象の変数がreleaseされてしまうとEXC_BAD_ACCESSでクラッシュします。
しかしながらiOS 4では__weakが使えず、状況に応じて__strongや__unsafe_unretainedでごまかす必要があります。このようなときにiOS 5では__weakを使い、iOS 4やno-ARCなプロジェクトではそれなりに適切な何かを使って実装するような仕組みが欲しくなります。

そこで便利に使えるのが__has_feature(objc_arc_weak)__has_feature(objc_arc)マクロです。こいつらを使うと簡単に現在のビルド環境・ターゲット環境がARCを導入しているか、weakは使用可能か、を判断できます。たとえば私は以下の様なマクロを組んで、
// ARC & memory management
// Use these prefixes to be compatible with ARC on iOS 5/ ARC on iOS 4.X / non-ARC
// 
#if __has_feature(objc_arc_weak) // iOS 5 or above
#define __my_block_weak        __weak
#define __my_block_weak_unsafe __weak
#elif __has_feature(objc_arc)    // iOS 4.X
#define __my_block_weak        __strong
#define __my_block_weak_unsafe __unsafe_unretained
#else                            // iOS 3.X or non-ARC projects
#define __my_block_weak        __strong
#define __my_block_weak_unsafe __block
#endif
こんな感じのコードにしてます。
__my_block_weak MyViewController *__weakSelf = self;
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse* response, NSData* data, NSError* error){
    __weakSelf.label.text = [[NSString alloc] initWithData:data encoding:NSUTF8Encoding];
}];
こうするとどの環境でも(比較的)安全にblocks内部でselfを触ることができるという寸法です。

ここで気になるのが__has_feature(objc_arc_weak)の判定条件です。個人的にこいつはiOS SDK 5.0以上を使っていたらターゲット環境がiOS 4とかiOS 3とかでも無条件で1を返してしまって使えないんじゃないのかと危惧していたのですが、なんとIPHONEOS_DEPLOYMENT_TARGETの値を見てきちんと値が変化する仕組みになっています!なので例えばSDKは最新だけれどiOS 3もサポートしたいみたいなプロジェクトでは__has_feature(objc_arc)の値が自動的に0になって良い感じに分岐してくれるというわけです。安心して使いまくりましょう!

2012年5月5日土曜日

C# で map とか reduce みたいな楽しいリスト操作をしたい

プログラミング言語がロジックを組むのに向いているかいないかを判断するときの基準に、私はよく「文字列の操作が優れているか否か」「配列・辞書・集合の操作が優れているか否か」を評価点に挙げます。文字列や配列、辞書、集合の操作はほとんどすべてのアプリケーションで必要になり、それらの生産性が高く高速に処理してくれる言語ほど簡単で高速なロジックが組めると思うからです。

そういう意味でObjective-Cを考えると、文字列の操作はまぁまぁ良い(特にUnicode周りがなかなか優れている、正規化もできるし)のですが、配列・辞書・集合の操作がイマイチで、作るの面倒なら操作するのも面倒。さらには良く欲しくなる以下の操作が欠けています。
  • map - 条件式を渡して、もとの集合の各要素に条件式を通した結果を新たな集合として返す。
  • reduce - 条件式を渡して、要素を前から順番に計算して畳み込み、集合から一つの要素にする。
  • any - 一つでも要素が条件式を満たすならtrue, すべての要素が満たさないならfalse
  • all - すべての要素が条件式を満たすならtrue, 一つでも満たさないならfalse
ではMono上のC#ではどうなんだろうということで調べてみたところ、LINQを提供するSystem.Linq名前空間に高度な配列・辞書・集合操作を行うための拡張メソッドが用意されているということがわかりました。

http://docs.go-mono.com/?link=T%3aSystem.Linq.Queryable
http://msdn.microsoft.com/ja-jp/library/system.linq.queryable(v=vs.90).aspx

ということで早速使ってみます。



実行速度が高速なのかどうかはわからないのですが、なかなか面白いです。ラムダ式が使えるのもスマートで素敵ですね。うーん、C#好きになってきたかも。

Mono の System.String と string の違いについて調べてみた

MonoとかC#とか初心者なのでSystem.Stringとstringの違いがよくわからず、気になったので調べてみました。

以下のページのベストアンサーが一番わかり易かったです。
http://okwave.jp/qa/q7225655.html

ちょっと転載します。
string と System.String は型として使われる限り単なる別名なので同じものです。
foo.System.String みたいなものが用意されて foo 名前空間内から使うような場合は異なりますが,特殊例過ぎるのでこれは考えないものとします。
コンパイラは,ソース上の型として string と書かれているものは,System.String とかかれているものとして処理します。
# 正確には "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" という型 (.NET 4 の場合)

これは,SDK 付属の逆アセンブラでコードを見ると,string を使っても System.String を使っても同じコードになることから確認できます。

同じように,int は System.Int32 の別名ですし,bool は System.Boolean の別名です。


使い分けは,特別決まりはありません。
唯一,メソッド名等に使う場合には言語固有の名称を避ける (CLR の名前を使う),というのはあります。
MSDN: 一般的な名前付け規則
http://msdn.microsoft.com/ja-jp/library/ms229045.aspx
具体的には,
・ToInt
よりも,
・ToInt32
の方が好ましい,ということです。
# 上側の名前付け規則だと,Visual Basic においては ToInteger であるべき,となる。


私は,static メソッドの呼び出しに使う場合は CLR の名前を使い,それ以外では言語固有の名称を使っています。
書籍によっては,常に CLR の名前を使うべき,という物もあったりします。
# が, for (Int32 i = 0; ……みたいなコードはほとんど見ません。

自分なりの物でいいので,統一したルールを用意しておくのがよいでしょう。
# 常に言語固有の名称でもよいと思います。

そもそも.NET Framework (とMono) は実装言語に依存しないような作りになっている (CLRというやつ?) のでこのような仕組みになっているようです。なるほど。 int, bool, string はC#の型で、 System.Int32, System.Boolean, System.String はCLRの型なわけですな。勉強になりました。

Unity でシステムが使用しているリソースを一覧表示したい

簡単なEditor拡張機能を書くときとか、デフォルトでUnityのエディタが使っている画像とか借りて表示したいときが多々あるんですが、これが実は公開されていなくてそのままでは使えないのです。ということでデフォルトでUnityのエディタが使っているリソース一覧を暴くスクリプトを用意してみました。



実行するとログに全てのリソースの一覧が表示されますので、あとはそれっぽい名前のやつを適当に拝借すればOKです。

自作の Unity Editor Script を github に公開してみた



最近は仕事の関係でUnityばっかり触っているのですが、中でも今お気に入りなのがEditor拡張機能です。これは自分で簡単なスクリプトを書くだけでUnityのエディタ上の表示を自由にカスタマイズできる機能なのですが、コイツの出来がなかなか素晴らしいのです。これまでいろんな開発環境を触ってきたのですが、ここまで簡単にエディタ上の表示を自在にカスタマイズできる環境は他に類がありません。

ということで調子に乗って自作のEditor拡張機能を書いて公開してみることにしました。まずは簡単なものからということで、シーン上に配置できる定規を作りました。


■機能
  • 原点からの距離(u)、高低差(u)、対象位置地面の水平方向傾き(度)を測定可能 ※1u=Unity上での長さの単位1とします
  • イメージを見ての通り全数値がエディタ上に表示されるので一目でわかる
  • Raycast飛ばしてるので確実に地面位置を基準にして判定してくれる、Raycastが外れても空中の座標がきちんと出る隙を生じぬ二段構え
  • 画面上の色/フォントを自由にインスペクタから変更可能
  • すべてEditorScript/Gizmoなので万が一何かの間違いでリリース版のシーンに残っていてもMesh Rendererが走って画面に表示されるという悲しい思いをしない
  • 操作は原点を選択してAdd Pointボタンを押して出てきた点を任意の位置に移動して配置するだけ
  • Clear Pointボタン付き
ひと通り基本的なのは揃えてみました。


次は高低差メッシュをTerrainの上に表示する機能とか作ってみたいっすね。