いろいろ忙しい気がする。そうでもない気もする。
体調が悪くてなんかふわふわする。一回休みにして一日寝てたけどあんまりかわらず。微妙な風邪っぽいが。
この前の週末にPeerCastハッカソンというのがあったのでそこでUnityであそんだ。
最初はちょっと前に買っておいたUnityではじめるゲームづくりという本を参考に進めてたんだが、半分くらいまでいって飽きたのでぶん投げて適当にゲーム作り始めた。飽きた原因はいつまでも見た目ばっかり作っててなかなかゲームに入らなかったからだろう。
何作ろうかと悩んでたらボンバーマンと言われたのでそれを……っていつもボンバーマン作ってないか?べつにいいんだけど。
見た目は適当でいいので箱並べて適当にテクスチャを設定しただけ。三人称視点にしようとしたんだが、FPS Character Controllerを置いたあとに一回消してTPS Character Controllerを置いたらなぜか上手く動かなくなってしまったので諦めた。FPS Character Controllerを置いてFPS操作にしておいた。カメラはちょっといじったのでFPS操作のTPSみたいなかんじだったが。というか360ボンバーマンのFPBモード(とてもクソゲー)みたいなの。
あとは爆弾置いたり。64のボンバーマンは爆風が球形だよねとか言われてなるほどとひよったり、爆風がデフォでどんなブロックでも貫通するけど気にしなかったり、パーティクルが上手くつくれなかったので見た目が悪かったりしたがまあできたよ。
敵も作ってやった。高速で自機めがけてつっこんでくるだけという手抜きな敵だが、いい感じにいやらしすぎてひどいクソゲー感が出たので満足した。
最初の爆風があまりにもでかくて死にまくり、さらにちょっと行動範囲が広がると敵が倒せなくてやばいので火力UPのアイテムも作ってやった。ブロックを壊すと1/2の確率で出て上限無しで取るごとに火力が上がるおそろしいアイテムだ。爆風はブロックで止まらないので取りすぎると死ぬ。たいていはその前に凶悪な敵に殺されるがな。
残機とか敵全部倒したらクリアとかあってもいいかと思ったんだが時間もなかったし、ゲームオーバーとかクリア画面を作るのがめんどくさかったのでやめた。満足したら終わりということで。
てな感じでちょこっとゲームの残骸らしきものがUnityいじりはじめてから約2日でできたわけだ。もうちょい頑張ればもっとゲームらしくなったかもしれんが、まあこんなところ。
使ってみて思ったのがやっぱりUnityすげーなという感じ。
何がすげーって丁度よい。いじる前はいやーゲームエンジンってアクションゲームツクールみたいなもんなんでしょ?詳しくいじろうとするとしんどいんでしょ?と思ってたんだが少なくともUnityは違ってた。カメラ動かすにもなんにもプログラムを書く必要がある。ちょっと試すのにあると便利なものは標準のコンポーネントとして用意されているが、それにしたって自前で書いたコンポーネントとの差異はない。 じゃあ結局プログラム書かないといけなくてめんどいじゃんということになるわけだが、標準のコンポーネントがなかなか使い勝手が良いのでそれを使えばそれほどめんどくもない。
コンポーネントの仕組みもすごくよくできてるよねー。プログラムの単位はコンポーネントということになっている。コンポーネントはシーン中に配置するゲームオブジェクトにくっつけるプログラム。ゲームオブジェクトにはコンポーネントが複数設置できて、あるコンポーネント内で別のコンポーネントも参照できる。コンポーネントはモデルとかテクスチャと同じようにプロジェクト中のアセットとして保存されていて、いつでも適当なオブジェクトにくっつけることが可能。
コンポーネントクラスのpublicフィールドはGUI上で編集可能だし、VisualStudioでいじってUnityに帰ってくると即座に(ちょっと固まるけど)変更が反映されるあたりはとても素敵。他のオブジェクトを参照したいわーと思うとGameObjectのフィールドを作っておいてGUIでそこにドラッグ&ドロップするだけでできるしね。この辺の便利さはRubyCocoaとInterfaceBuilderの連携に驚愕した思い出が蘇えるが、UnityはMac発祥だからInterfaceBuilderを参考にした部分もあるんだろうか。
コンポーネントのいいところは、プログラムの再利用化が自然に行なわれるところ。まあもちろんプレイヤー用のコンポーネントとかいう再利用のしようもない物も普通に作るけど、HP管理して無くなったら死ぬだけというコンポーネントを作って、プレイヤーとか敵とか破壊可能ブロックとかにくっつけようというのを自然にやりたくなる。
最初はHP管理コンポーネントを継承して敵コンポーネントを作ろうとしたんだが、継承は上手く動かないようなのでやめた。継承じゃなくて必要なコンポーネントは全部ちゃんとくっつけとけよということらしい。確かに継承より再利用しやすいからな。ただし必要なコンポーネントをくっつけてないと取得しようとしてもnullがかえってきて終わるのは注意な。
見た目の方も自動でこれ生成して欲しいなーという物が簡単に作れるのがよい。地形の編集はめんどいが。ライトマップの焼き込みとか簡単にやってくれるし、法線マップ作ってほしいなーと思ったらインポート設定でできる。それでいてちゃんとした編集は結局外部エディタでおねがいしますとなっており無駄がない。 見た目に関してはBasic版だと水がしょぼいんだけど!とか影くらい出してほしいんだけど!とかポストエフェクトはないのかな!とかいう無くてもいいんだけどあるともうちょい派手になる辺りの機能がPro版買ってねとなってて、ちょっと欲しくなる絶妙な辺りを突いてくるのが憎い。 ゲームロジック作る分にはプロファイラがないくらいでProとBasicで違いはないみたいね。
一方でプログラムを書くにはおかしなところも散見される。まずJavaScriptで書けますといってるわりには静的型付け可能なJavaScriptじゃねーだろそれという言語だった。JScript.NETとかActionScriptをJavaScriptといいはるのは無理があるだろJK。
まあ俺はC#で書いたんですけどね。 しかしC#もなんかおかしい。まずこいつを見てくれ
public class MyComponent : MonoBehavior
{
void Start()
{
//インスタンス化された最初のフレームでここ実行
}
void Update()
{
//毎フレームここ実行
}
}
コンポーネントはこんな感じで実装される。一見普通なんだが、よくみるとなんかおかしい。StartとかUpdateがプライベートメソッドである。オーバーライドも何もしていない。なのになぜか実行されるのである。ど、どういうことなの…?
最初オーバーライドしないといけないのかーと思ったんだが、そもそもMonoBehaviorにStartもUpdateもなかったりした。あれー?おそらくはリフレクションでUpdateとかのメソッドを取り出して(ついでにリストにつっこんで?)実行してんじゃないかと思う。なんでそんなことするかというとvirtualにしてオーバーライドするようにすると派生元のクラスでは空メソッドを用意しておかないといけないが、ゲーム中大量に発生するコンポーネントの大半で空メソッドを呼ぶのはそれだけで結構無駄な時間になることがあるのでvirtualですらないんだろう。全くの想像だけどね。
速度の問題ってのは理解しても気持ちわるいなぁとは思う。ていうかさらに気持ちわるいのはプライベートメソッドなのに呼ばれることだよ!せめてpublic必須にしておけよ!!べつにいいんですけどねー。
もしかしたら速度関係なく、単にoverrideとかpublicとか書き忘れんだろおめーら、ということで書かなくてもいいようにしてるのかもしれない。そんなことはないと思うが。
もう一個気持ち悪い点がある。
var character = GetComponent<CharacterController>();
if (character) {
character.Move(~);
}
Updateの中にこんなのを書いたとする。MyComponentがくっついてるゲームオブジェクトからCharacterControllerコンポーネントを拾ってきてあったらそれを使ってキャラクタを移動させようとしてる。移動の中身は今関係ないので省略してるよ。GetComponentは対象のコンポーネントが無かったらnullを返してくるんだが、C#ではnull判定はcharacter!=null
と書かないといけないのでif (character)
とか書けないはずである。でもなぜか書ける。これはちょっと調べたんだがどうやってるかわからなかった。たぶんどこかにboolへの暗黙的変換があるんだと思うけど……きもちわるっ。だがこの書き方は好きだけどな!
気持ちわるい点ではないけどちょっと書いてみてだめだった点も挙げておこう。上にも書いたけどコンポーネントの継承は思ったように動作してくれない。GetComponentで指定した型のコンポーネントを取ってくるときに派生元の型を指定しても派生先のコンポーネントはとってきてくれない。完全一致じゃないとだめなようだ。これはコンポーネントは継承しないで多数くっつけろということだろうから納得できる。
プログラムで変だと思ったのはこんなくらいかなぁ。そんなにいじってはないけど。あと途中まで参考にしてた本でカメラ操作のコードが意味不明すぎて混乱させられたくらいだが、これは本の問題だしな。どう見てもコードがバグってる。
ちょっと最後に気をつけたい点。Unityは簡単だけど、誰でも簡単にゲームが作れます的なものじゃない。キーを押したらキャラが動くってだけでもプログラムを書く必要はある。それにしても3Dのベクトル演算とかしないといけないので全くわからんと厳しいだろう。つってもそんなに難しいプログラムを書く必要があるわけじゃないのでちょっと勉強すりゃ誰でも作れるってのは間違いないけどね。プログラムなんて無理だわーと思いこんでる人はアクションゲームツクールなりRPGツクールなりでも買ってきましょう。
逆にある程度3Dの知識があるんだけどゲーム作ろうとするとあれこれ一から作らないといけなくて大変すぎるよ!という人にはとてもおすすめできる。まあゲームエンジンってそういうものだよね……。
あー、あと2Dゲーム作るのには全く向いてないと思うのでやめておこう。3D描画の2Dゲーならいけると思う。物理エンジンは素直に2Dいけるんだろうか?詳しい向き不向きは俺もまだわからん。
最後に、座標系が左手系だ。死ぬがよい。
最近GUIいじってただけだなぁ。Windows.Formsはもうしょぼくて死にたい。
設定保存がGUIに依存してたんでPeerCastStation.exeに移行させた。GUI側といえば設定保存にやけに依存したコードになっていたのでそれをやめて、さらにHTML UIに合わせて構成を変更。リレーツリー以外はたぶんそれなりに直せたと思う。
あとリレーツリーが問題だな。ツリー作る自体はたぶんできるんだが、更新がとてもやりづらい。更新前と後のデータが取れるだけだと、あれが消えてこれが移動してそれが追加されたなんかの情報を自前で作らないといけない。とても大変。一旦アイテム全部消して追加しなおすとかやるとWindows.Formsのツリービューではスクロールもリセットされるし更新も遅いとなんとも使いづらい。しかしどうしても高速に更新は難しそう。HTML UI側での実装も高速な方法はないような気が……。
と思ってたがそんなに頻繁に更新する必要ねえな、これ。今だと変更がある度に更新してたけど、よく見る物でもないし手動更新でも十分だ。そうするか。手動更新ならちょっと遅くてもいいだろう。遅いっつてもせいぜい1秒程度だろうしな。