|
3DFCに向けて新たに新技術、ピンポイントサバイバーを試してみた。今まで不毛だった大地の毛根を活性化し、どんな禿げちょろけた場所もみるみるフサフサという触れ込み(?)の、画期的技術である。
なんていうと、まぁ表紙の写真と比べてみたとしても、「何言ってんだ?」と首を傾げる御仁もいらっしゃるかもしれない。
要するに、「ピンポイントサバイバー」とは、ランドスケープに植物を生やすためのやり方なのである。
原理はあまりにも簡単で、要するにランドスケープが地面の起伏を生やしているように、起伏のかわりに樹木をただ生やしているだけなのだ。
実は、戦闘考証部門の責任者であるN.Sekiから、再三にわたって「起伏だけでなく、森林がなければ戦術的幅に乏しいゲームになってしまう」という警告を受けていたのだった。
今回の「ピンポイント・サバイバー」はそれを実現するための技術なのである。当初は「プログレッシブ・フォレスト」というコードネームで呼んでいたが、「ピンポイント・サバイバー」のほうがしっくりくるので名称変更を行った。
3DFC98まで、ネタ蓄積のために敢えて開発過程をバラさないという公約を少しばかり犯したのにはわけがある。
実は、今日から新二年生に向けてのオブジェクト指向集中講義を行うことになっている。そしてこの「ピンポイント・サバイバー」と「プログレッシブ・ランドスケープ」はオブジェクト指向について考えさせられる新しい機会を私に与えてくれたのだ。
実は、現在のところ、「プログレッシブ・ランドスケープ」を始めとして、計画推進中のプロジェクトは全てC言語レベルで記述している。
この理由は、C言語が極めて記述性に優れた言語であり、しっかりとした設計がなくてもある程度のところまでプログラムが書けるからである。
もしC++言語で書こうとしたら、アルゴリズムが大規模な変更を行うたびにソースのほぼすべての部分を書き直す必要があっただろう。なぜなら、オブジェクト指向言語にとって、アルゴリズムとはすなわちクラス構造であり、クラス構造とはすなわちプログラム全てなのである。
そしておそらくその度に私はある配列を、構造体を、初期化を、どこで行うか悩んだに違いない。さらに思い違いが発生し、新たなバグと格闘する必要も産んだだろう。
現在のソースコードは洗練されているとは言えないが、いまのところは私にとってわかりやすいものであり、どんな改造にも柔軟に対応できる。
C++言語とひとくちにいっても、その内容はかなり幅広いのだが、ここではクラスの構築を伴った、オブジェクト指向的言語としての側面を指している。
しかし、私は今書いているコードをいずれ近いうちに完全なC++コードへ書き換えるつもりでいる。それはこの部分のアルゴリズムがこれ以上動きようのないところまで固まってきたからであり、同時により柔軟に活用するには、現在のような混沌とした状態では役不足におもえてきたからだ。
しかしこの作業は一筋縄ではいかない。かなり大きな問題を孕んでいるのである。
第一に、もしここでクラス構造の設計をしくじれば、その「不完全な」クラスはプログラム全てが完成するまで迷惑を掛け続けることになる。
第二に、安易なクラス構造にしてしまうと、パフォーマンスが著しく低下したり、なんの意味もなくなったりしてしまう。
第三に・・・・これはこのプログラムの場合に限るのだが・・・・現在はロボットなどはRetained-Modeを利用して描画しているが、これを将来的には完全な独自ルーチンに置き換えたい。クラスが下手にRMを意識するような作りになっていたら、計画は台無しである。また、現在はDrawPrimitiveを使っているが、ゆくゆくは非同期Execute-Bufferを使いたいというのも悩みの種である。
以上のような問題から、今の今まで容易にクラス構造を設計することができないでいる。
たとえば、「プログレッシブ・メッシュ」と「ピンポイント・サバイバー」の構造は非常に似たものになっており、こんなときこそ、C++自慢の「コード再利用」が生かせないものかと思ったのだが、御察しの通り、お互いのアルゴリズムは処理が似てはいても、継承して解決できるような部分はなにもない。
結局、インライン関数としていくつかの共通部分をまとめてみたが、そこらへんが関の山である。
こんなふうに、C++言語をはじめとするオブジェクト指向的言語は当初の理想を達成できてないパチモノ。いわばなんちゃってオブジェクト指向である。
こんなコトだから、いつまでたってもオブジェクト指向的言語というのはシカメっ面をして語られるものなのだろう。
「オブジェクト指向なんて簡単だよ」と訳知り顔で語る人間に限って、オブジェクト指向的言語の暗部を無視しているか深く洞察したりしていないかのどちらかであろう。
そしてここが大切なのだが、オブジェクト指向というのは、その概念自体が従来の手続き型言語、ひいてはコンピュータそのものの構造をほぼ完璧に無視した概念なのである。
逆にいえば「なんちゃってオブジェクト指向」言語の雄たるC++はそのへんの適当な折り合いをつけた言語とも言える。そしてそこが扱いにくいところでもあるのだ。
たとえばこの計画で新たに利用したいアイディアなどを実現したいとしよう。例えばオブジェクト・プール技法ひとつとっても、汎用的に使うためにはテンプレートを利用しなくてはならない。
私はテンプレートというのは、言語仕様的にみて美しくないと思う
奇妙な構文で「テンプレート」を規定し、これまた奇妙な構文で「テンプレート」のインスタンスを作成する、しかも真のオブジェクト指向言語であれば全てのオブジェクトは動的に生成できるハズだが、「テンプレート」のインスタンスは静的にしか作れない(言語仕様上いたしたかないことだが)。
便利というのは理解できるが、できればあまり取り入れたくない概念ではある。
同じ目的を達成するのにも、もう少しスマートな手段がないのだろうかと首を傾げずにはいられない。これについてはいい方法を思い付いたら紹介しようと思う。
こんなわけで、やっぱりC++は難解な言語である。おそらくそれは世界中の人々が感じていることだろう。それならJavaならどうかというと、C++よりだいぶマシな部分もあるが、相変わらず気違いじみたこうぶんなどもあり、やはり好きにはなれない。
特に許せないのはtry{}catch構文である(これはC++とJavaの両方にある)。
こんな考え方はそもそものC言語の理念(全てプログラマが責任を取る)に反するし、どんなオーバーヘッドが産まれるかも明確ではない。
ところが残念なことに、いまのところtry{}catch(またはそれに類する方法)以外で、このような場合の処理を合理的に記述することができない。
それはセルフリカバリなコードを書くのが如何に困難かということでもあるが、なによりエラー処理こそクラスの上位レベルでラップされてしかるべきだろうと思うのは私だけだろうか。
たとえば、3Dの描画クラスを考えてみよう。メッシュのクラスであるC3DMeshは、3D描画クラスであるC3DObjectの派生クラスである。
C3DMeshの中で問題が発生した場合(たとえばDrawPrimitiveメソッドがエラーを返した)、C3DMeshはC3DObjectクラスで定義されたエラーリカバリルーチンを自動的に呼び出すが、C3DMeshが自分でエラーリカバリを行うこともできる。これこそオブジェクト指向のコード再利用を活用した合理的ではないか。
ところがC++言語の仕様上はこのようなやり方はできない。なぜなら、エラーコードは必ず呼び出し元に渡されるからである。スーパークラスではないのだ。もしこれを実現したければ、呼び出す関数が、エラーが発生したときに呼ぶ関数へのアドレスをあらかじめもってなくてはいけない。つまり、クラス毎に初期化する度にエラーリカバリルーチンのコールバック関数を登録する必要があるのである。そんな馬鹿な!
この問題は、やはりC++言語をはじめとするオブジェクト指向的言語が、相手を特定しないメッセージを送ることができないところにある。
ではオブジェクト指向の原点にたちもどって、今の問題を考え直してみよう。
オブジェクトとは、自立判断してメッセージをやりとりするものである。だから擬人化して考えるとやりやすい。
しかしオブジェクト指向自体が規定していないにも関わらず、現実のオブジェクト指向的プログラミング言語では強要される考え方がある。それはメッセージ呼び出しと返り値だ。返り値はいかなる事情であれ、呼び出し元に返される。
しかし本来ならば、あるメッセージの処理中にエラーが発生したなどということは、返り値のかたちではなく、本来ならそのオブジェクト宛に新しいメッセージとして送信すべきである。
もし、そのような構造になっていれば、前述の問題は極めてエレガントに解決できる。実現もさほど難しくない。メッセージの送信と受信だけでなく、「返信」を可能にすればいいのである。
ところがC++言語では頑なにポインタのないオブジェクトとのコミニュケーションは不可能になっているし、メッセージを送るときに自分のポインタは渡さない。ということは、いわば今、オブジェクト達は常に差出人不明のメッセージをあくせく処理していることになる。
ただし、彼らの唯一の接点は返り値である。返り値によって、処理側のオブジェクトは要求側のオブジェクトに対してメッセージを送ることが出来る。しかしこの表現は正しくない。ただしくは処理側のオブジェクトは要求側のメソッドに対してしか送ることはできないわけだ。
このようなエラーリカバリ機構を付加するだけでも、プログラムの記述性はぐんとあがる。もう、「HRESULT rval=」と記述する必要はなくなるのだ。
ただしこれは相応のフレームワークを用いる場合に限られる。
また、あるクラスのオブジェクトに送ることのできるメッセージが静的に制限されてしまうのも理解に苦しむ。無論、実装上の理由はあるが、たとえばオブジェクトの内容が動的にどんどん変わっていくようなものは記述できない。
もはやそこまでいくとプログラムではないと言われるかもしれないが、実は概念上のオブジェクトが動的に内容を変化させるのは既にずっと以前から我々の目の前で起こっていることである。
たとえばエディタがそうであるし、コンパイラがそうである。ゲームでいえば、成長して新しい技を覚えるキャラクタはまさにオブジェクトの規定(クラス)自体が静的なものではなく動的なものであるといえるだろう。プラグインで機能拡張するグラフィックソフトも同様だ。
ただ、従来はそれらをある種のスーパークラスの派生というオブラートで包み、あるいは内部パラメータの低レベルなインタープリタを実装することで忘れていただけなのだ。そう、オブジェクトというのは実行時に変質するものなのである。
プログラムという作業は、その観点からいけばオブジェクトの性質ひとつひとつを規定していく作業だが、オブジェクトがどのような組み合わせで全体としていかなるものになるかは既に予想できない。
現在いわれているオブジェクト指向はそのへんが半端なのである。そしてその表層の部分だけを取り入れ、解ったような気になって「活用」としているに過ぎない。真のオブジェクトとは組み合わせのある限り万能であるはずだし、極限すればCPUと同等の概念なのだ。
しかし現実に我々の眼前に存在するのは、依然として旧来のオブジェクト指向的言語であり、まずはこれを使ってどこまでできるのかやってみなくてはならない。しかし、それを使う過程に、ここで述べたような新しいパラダイムへの模索を行うのも、決して無駄ではないと信じたい。
|
|
|
|