第80回 やねうらおの開発マシンについて(これが標準!) 99/11/6

弟子の強い要望により、弟子リンクのコーナを作らされた。作らされたという表現に語弊があるのならば、作らんと殺す!と脅迫されたと言っても良い。(余計、語弊あるっちゅーに…) まあ、やねうらおも、人の子だからして、泣く子には勝てないのである。

しかしやねー、なんで、奴もいきなりブ○セラやるかなぁ(笑) えっ?ブ○セラとちゃうんか?あれ、リサイクルページとでもゆうんやろか?水着とドレスのパステルや、リバーサイドシティやあるまいし(具体名出すなっちゅーに>俺) いまどきリサイクルでは通らんじゃろて…。しかも、そんなん紹介せんとあかんもんの身にもなって欲しいあるよ。(笑)

そんなこんなで、リサイクルと言えば、やねうらおの開発マシンについて紹介せねばなるまい。開発マシンというと、たいてい想像を絶するような馬鹿速いマシンでやっていると思われがちであるが、やねうらおの場合、想像を絶するような馬鹿遅いマシンでやっていることがある。驚くことなかれ、メインは486DX 33MHzのノートパソコンである。こいつは、TFT液晶なので目が疲れなくて大変良いのだ。非常に地球に優しいやねうらおである。(意味不明ぎみ)

やねうらおの場合、基本的に、プログラムにはテキストエディタしか必要なく、とにかくどんどんプログラムを打つ。2,3日で2000行ぐらい入力する。長時間コンパイルしないし、そもそもテキストエディタしか入ってないので、コンパイルなんてできない。WindowsのAPIの呼出しやらデバッグ作業をやっているならば話は別だが、基本的に自分で作ったAPIのwrapperを呼び出すぐらいのことしかしないから、Windowsでプログラミングをしていることすら忘れて、ひたすらプログラミングに専念できるのである。

ついでにこの手のマシンは安い。TFT液晶の割に中古市場で、ただみたいな値段で売られている。当初、TFT液晶だけ分離して使ったろかい!と思ったぐらいである。今後、486DX 33MHzのノーパソは、業界標準の開発マシンとなるだろう。(それは、絶対ないってば!>俺)


第81回 魚さんと遊ぼう(謎) 99/11/12

デジカメ買いました。ちゅーか、弟子に買わされたんですよ(笑) いや、買わされたという表現には語弊がありますね。弟子の名誉のために正確に言っておきますと、買ってこんとシバクぞコラ〜と脅されただけなんですけどね。(余計、語弊あるっちゅーに…)

機種は東芝のAllegrettoM3ってやつです。FUJI FILMのFinePixel600Zとそっくりな形で、性能表示も細部に至るまで同じです。形状が同じで性能が同じと言えば、簡単ですね。つまりは、盗品なんですよ。(こんなん書いて信じる人いたらどうすんねん!>俺)

冗談です。盗品ではなくて、こちらOEM製品なわけで、同じものが安くで手に入るということですよ!ソフマップで2つ並べて置いてあって、誰がFinePixel600Zを買うというんでしょうか?しかも、やねうらおは、めでたくルピー10%還元デーに買いました。

売値、4万弱。150万画素。光学ズーム3倍+デジタルズーム2倍。スマートメディア採用。パソコンへのリンクキット付属(NT対応)。リチウムイオンバッテリー使用。こんなのが4万で手に入るんかー(しかも10%ルピー還元) デジカメ流行るのがわかったような気がしました。ところで、この4万円はいつ返してくれるんでしょうか。>みずほさん(こんなところに書くなって…>俺) 

そういや、ずるずる公開をのばしていたyaneGameSDK1.00β4ですが、ネタがなくなってきたんで、ついに公開しました。ちゅーか、いままた、全面的に設計、見直そうかと思ってるんですけどね…。突貫工事で作ったもんで、やっぱ洗練されてない部分があって、そのへんが完全主義な私の心を魚でするわけですよ。えっ?自分、魚でするん??なんかめっちゃ生臭そうね。(何の話やねん)


第82回 Encapsulationについて考える(続OOP講座) 99/11/13

今日は、初心に戻って、カプセル化について考える。というか、あまりにも初歩すぎて、やねうらおはよく知らないところもある。実のところ、C++は真面目に勉強したわけでもないし、入門書の類は立ち読みでしか見ていない。人のプログラムざっと眺めてたら、いつしかC++が使えてたタイプの人間なので、間違いあらばご指摘願いたい。

C++で、classの外部から、classのメンバ変数に直接アクセス出来るのではカプセル化されているとは言い難い。publicなメンバ変数はやめなさいという人がいる。僕は、時間がないときなどは、たまに使ったりすることもあるが、基本的に使うべきではないというのには賛成である。

そこで、classのメンバ変数は、たいていprivate(かprotected)にする。派生させて使うことを考えると、protectedのほうがやや便利な気もする。(このへんは、好み?) だから、classのメンバ変数にアクセスするときは、classのpublicな関数を介する。多くのC++の教科書にはそう書いてあるだろうし、多くの人がそうしているだろう。

カプセル化の効用なんか説いていてもはじまらないので、そのへんの手法について考えていく。まず、

class XYZ {
 protected:
    bool m_bMember;
};

このようなメンバ変数があったとして、このm_bMemberを設定(変更)するための関数のスタイルとは、どんなものだろうか?boolにあることに何らかの意味があるならば、

void XYZ::EnableMember(void) { m_bMember = true; }
void XYZ::DisableMember(void) { m_bMember = false; }

と書くだろうし、値を設定することに重点があるのならば、

void XYZ::SetMember(bool b) { m_bMember = b; }

値を取得する関数も必要なのば、

bool XYZ::GetMember(void) { return m_bMember; }

ある人は、

bool* XYZ::GetMember(void) { return &m_bMember; }

とやっておき、XYZ型の変数xyzに対して、

*xyz.GetMember() = true;

という書き方をするのが好みだというかも知れない。慣れていない人は読み辛いと感じるかも知れないが、これはこれで味がある。上の最終行のように、

*そのクラスの変数名.Getメンバ変数名() = 値;

というこの形をひとつのパターンと認識している人にとっては、非常にわかりやすし、何より関数がひとつで済むのでお手軽なのである。しかし、m_bMemberの値を:現在の値から変更するときには、何かの処理をしたいことがよくあるのだが、そういうときに後者のスタイルだと、それが出来ないのである。よって、単にアクセス手段を提供するだけならば、後者を使えるのだが、それではメンバ変数に直にアクセスしているのとさほど変わりないし、あまり恩恵にはあやかれない。(このことは、後で詳しく議論したい)

ところで、参照を使えば、もっと簡単になるだろうか?つまり、

bool& XYZ::GetMember(void) { return m_bMember; }

とやって、XYZ型の変数xyzに対して、

xyz.GetMember() = true;

というように使う。この表現は参照を使っているのが不透明という欠点もある。(というか、参照自体が、ポインタに絡む変換をシームレスに行なうために産み出されたものだから、不透明で当然という話もある)

参照は、使っても表記が格段にわかりやすくなるわけでもない。というのも、関数呼び出しのための括弧が、とても見苦しいような気すらする。それに関数の返し値がLValue(=左辺値/代入のイコールの左辺にある式)になれるというのもなんだか不気味である。これが、もし、括弧がなければ、逆に自然な気がするのだが…。

そんなわけで、次回は、この問題を掘り下げて考えていく。


第83回 Windows2000について(最高のゲームマシン) 99/11/17

以前、Windows95のβ版を入れて痛い目に逢った経験もあるやねうらおだが、基本的にそういった学習能力が皆無に等しいので、今回もまた懲りずにWindows2000Professionalβ3なるものをインストールしてしまった。

WindowsNT4.0(SP3)からのアップグレードである。β版だから、ある程度のトラブルは覚悟していたものの、指示に従ってマウスをクリックしていたら、30分ほどで何のトラブルもなくインストール完了。

ウィルスバスター98が起動しなくなったが、どうせ、これ自体がウィルスみたいなもんだから(時々、悪さするし)、近いうちにウィルスバスター2000にしようと、こいつは削除。

あとは、環境設定もそのままだし、特に見かけ上は何も変わったことはないのだが、USBが使えるようになったことは大きい。最近USB対応製品が増えてきたので、これは嬉しい限りである。

そして、最新版のDirectXが利用できるようになった。ヘルプファイルを見る限りでは、DirectX7が入っているようである。ずっとWindowsNT4.0(SP3)でDirectX3使っていたので、ずいぶんと隔世の感がある。ちゅーか、DirectX5以降とか書いてあってWindows95/98でしか動かなかったゲームが動くようになってしまった。これでは、開発マシンがゲームマシンと化してしまう。

インストール時にNTチェックをしている凶悪ソフトもあったが、逆アセしてチェッカールーチン潰したら無事インストール終了。普通に動いている。2,3日使っているが、いまだ一度もフリーズしていないし、謎なメモリ保護エラーも出ていない。実に安定している。

もちろん、YGS2Kだって動いている。もはや、これではWindows98マシンを残しておく意義がなくなってしまった。Windows2000は、ゲームマシンとしては、最高の環境である。ただ、DirectXのようにポート直叩き(この表現、やや難あり。まあ細かいこと言うなって^^)出来るような行儀の悪い奴がOSと共存しているのかと思うと、セキュリティ面ではまったく信用できないシロモノなのかも知れないが…。


第84回 Encapsulationについて考える2(続OOP講座) 99/11/18

今回は、前々回の続きである。本文が長いので、単刀直入にいく。

いま、仮に、プロトタイプ宣言で引数を(avoid)と書いて、関数呼び出しが省略できるように、C++の規則を拡充すれば、前々回の最後のスタイルは、

bool& XYZ::GetMember(avoid) { return m_bMember; }

とやって、

xyz.GetMember = true;


と、あたかもメンバ変数のごとく使用することが出来る。しかも、間には関数呼び出しが介在しているので、この代入は関数側でカスタマイズできる。これは、前々回の僕の発言にある、

> 参照は、使っても表記が格段にわかりやすくなるわけでもない。(中略)
> これが、もし、括弧がなければ、逆に自然な気がするのだが…。

という部分である。(ただし、やはりLVALUEにはなれないという欠点を持つ)

ときに某land C(何が某なんだか^^)に至っては、classのメンバ変数に対して__propertyキーワードによって、そのメンバ変数がLVALUEになるときに呼び出される関数と、非LVALUEになるときに呼び出される関数を指定することが出来る。

ついでに言えば、VC++であっても、

__declspec( property( get=get_func_name, put=put_func_name}) ) declarator

というような構文が用意されていて、これと同じことが出来る。

Windowsの二つの大手ベンダーによるC++コンパイラがあえてサポートしていることからも、どれだけ、このような“仮想データメンバ”へのニーズが大きいのか知れようというものである。

それなのに、この機能をどうしてC++ではサポートしようとしないのか。使いもしないストリームライブラリは送り返すんで、この機能をつけて欲しい。(送り返すって、どこへやねん…)

ともかく、このような拡張キーワードを利用することなく、(C++の)プリプロセッサのフェーズで、こういうのを実現できないかと考えたのだが、やねうらおにとってプリプロセッサは体育の次に苦手!だからして(なんのこっちゃ)、エレガントな方法が思いつかない。何かお考えをお持ちの方は、教えていただきたい。(もちろん、lexを利用すれば簡単なのだが…)

さて。上記のように、xyz.GetMember = true;と書ける真髄は、この代入プロセスにおいて暗黙的にユーザ指定の関数が呼び出されるところにある。関数が呼び出されるだけならば、代入オペレータを重複定義することで何とかならないのか?

いや、C++では、オペレータ(の重複定義)は属性(クラス/型)に対する作用素であって、つまりは、

operator = (bool x);

というような重複定義は可能であっても引数が同じ並びの関数は用意できないし、まして、

operator = (bool bMember,bool x);

というように、特定のメンバ変数の代入に対するオペレータという重複定義は出来ない。それがしたいならば、boolと同じ機能を持つ別の名前の型を用意するしかない。ちょうど、(C++の)例外処理で、classごとにしかハンドラを書けないのに似ている。

このへん、うだうだ言っていても仕方がない。(ソフトウェア工学的に面白い部分ではあるが)

結局のところ、どうしてもこの機能を使いたいのならばDEFINE文でVC++のときとBCのときとを切り替えるのが実践的だろう。あるいは、もうBCしか使わへんねん!だとか決め打ちしてしまうのも一策である。それが嫌ならば、この機能を使うのはやめればよいのである。この機能を使わないとプログラムが書けないわけではないんだし、増して死ぬわけでもないのだから…。


第85回 天狗になったプログラマ(某恋愛シミュレーションを手がけた人の場合) 99/11/21

このコンピュータ業界でもゲーム業界は少し特異な部分のような気がする。いまごろ何言ってんだーと自分でも思うのだが、やはり他のコンピュータ関連の職種からすると、とても異色な分野のようだ。

まず大手ゲームメーカーでも、売れればボーナス等で年収がどかっと上がるし、何かヒット作品を手がけると、他メーカーからの引き抜きも跡を絶たない。そうなってくると、プログラミング技術と収入はもはや比例しないということが多々ある。

たまたま売れたギャルゲーを作った某プログラマーが僕の知り合いにいるのだが、たいした実力もないのに20代前半にして、もはや天狗状態で、勉強だってろくすっぽしない。

自分で調べようともせず、わからないことがあればすぐに掲示板やメーリングリストで質問をする。それでいて、妙なプライドを持っていたりするからタチが悪い。「僕は××万本売れたソフトを手がけた」のだと。なぜにプログラミング理論についてさえろくに知りもしないくせに、その程度のゲームを作ったぐらいでそこまで自分の実力を過信したり、自信を持てたりできるのだろうか。こういう奴と仕事をしなくてはならないときほど厭世的な気分になることはない。

しかし、彼のような天狗プログラマが誕生する背景には、ある程度共通した背景があるようだ。

まず、貧困生活を送ってきた時期が長いこと。あるいは評価されていなかった時期がある程度長いこと。その反動で、収入が増えると途端に自分が高く評価された、技術的にレベルが上がったと思うようだ。天狗になる第一の要因である。ことプログラミングに限って言えば収入は技術力を示すバロメータではないというのに…。

また、彼らは、知的好奇心からプログラムをやってきたわけではなく、単にゲームが作りたいからプログラムを勉強してきたことが多い。そして、ゲームが作れるようになって、そのゲームが馬鹿売れすると、目的が達成されたと勘違いするらしい。プログラミングは、ゲームを作るための単なる“手段”に過ぎないのだと。そう思い込みたい気持ちはわからないでもないが、井の中の蛙なのが、わかってないのねぇー。あなたたちの収入の数分の一しかなくとも、あなたたちの数百倍の技術力と知識を持っている人が世のなかには腐るほどいるってことが…。

きっと、彼らのなかでは言葉さえも日常生活をするために必要な“道具”に過ぎないのでしょうな。言葉自体が思考作用の中心的な役割を担っているだなんて思いもしないんでしょう。プログラミングにしてももちろん同じですよ。プログラミングはひとつの学問であって、冴えないプログラマの生活手段として存在しているわけでもなければ、ゲームを作るための手段として生まれてきたわけでもない。それなのに、クールに(?)「プログラミングはゲームを作るための手段に過ぎないですから」だなんて言ってくれるなと言いたい。あなたたちは、プログラミングという広範な学問領域のほんのひと握りだけをつかんで、さもしくも自分の生活の糧(かて)として生きているに過ぎないということにどうして気づかないのか…。


第86回 継承について考える(続OOP講座) 99/11/22

やねうらおは、C++を実はよく知らないんではないかと自分で思うようになった。そういや、アクセスがミリオンヒットしたからって、いまだホームページの作りかたもよくわからないし、入門書を見ながら3日で作ったという弟子のページにもデザイン的に劣るとあっては、やねうらおは、かなりの阿呆なのかなーと思う次第である。(どうでもいいんですけど、デジカメの借金、現物支給っちゅーのは勘弁してくださいね(笑)>みずほさん)

ところで、やねうらおはC++を知らないんではないかと思うに至ったきっかけが、このソースである。

class A {
public :
    int GetKey(void) { return 0; }
};

class B : public A {
    int GetKey(int) { return 0; }  // これが悪さしているようだ
};

main() {
    B b;
   
b.GetKey();    // ((A)b).GetKey();なら可能
}

VC++6.0でやっているのだが、赤い部分でコンパイルエラーになる。青い部分をコメントアウトすれば、コンパイルは通るのだが…。あれれ。継承って、そーゆーもんだっけ?またしてもVC++のバグなのか?

VC++6.0 ServicePack3を適用してみたが、やはりエラーが出る。つまり、派生させて別の引数をとる関数は用意できんっちゅーことか?それでどうやって継承使えっちゅーねん!しかし、どうもVC++のバグのような気もする。不幸にして、他のコンパイラがいま手元にないのでテストできない。C++の仕様だとしたら、C++標準化委員の方に足を向けて寝ることにするし、VC++のバグならばビルゲイツのほうに足を向けて寝ることにするので、どなたかご指南ください。


第87回 DirectXは、何がDirectか(閑話休題) 99/11/23

今月号のC MAGAZINEでDirectX7についての特集がされている。例によって、いくつかウソまじりに書かれているが、他誌でDirectX7の紹介記事がなかっただけに(?)、貴重である。

ところで、DirectXを使っていると、同時に動かしている他のアプリと協調的な動作をさせにくい。往々にして行なわれるハードウェアへの“ショートカット”に頭を悩まされること必至である。

特にいまでも如実に覚えているのが、パレット関連である。標準のWindowsのパレット構造というのは、かなりダサいシロモノなのだが(詳しくは第51回付近を見よ)、DirectDrawPaletteは、その標準のWindowsパレットとはまったく別のところからしゃしゃり出てくる。Windowsパレットからしてみれば、「あんたもっと端っこ歩きなさいよー」((c)美川健一)なのだが、それはDirectDrawPaletteを使ってプログラムしている人間にとっても同じことで、「あんた(標準Windowsパレット)こそ、もっと端っこ歩きなさいよー」である。

DirectDrawPaletteによって、Microsoftの連中が何をどうしたかったについてはわからないでもない。何より標準のWindowsパレットは遅いのだ。なぜ遅いのかについてここで語っていても仕方がない(しつこいようだが第51回付近を見よ)。そこで別のフレームでパレット機構を提供する必要があったのだろう。

そんなわけで用意されたDirectDrawPaletteなのだが、こいつが散々なシロモノで、やねうらおも、いまだ(自分のプログラムを除いては)ウィンドゥモードで動いているプログラムでDirectDrawPaletteを使っているものをお目にかかったことがない。(ついでに言えば、自分のプログラムはDirectDrawPaletteについて、お世辞にも良いサンプルではない)

その他としては、入力処理のためにDirectInputを使う価値があるのか?という議論をよく見る。実際のところ、フォースフィードバック対応のジョイスティックでも使うのでなければ、DirectXを使わなくてもキーボード、ジョイスティックの入力は可能である。そういう議論において、DirectX否定派は、使う必要性がないんだから、むやみやたらと使うことはないというのを論理の根底に敷いている。それはつまり、DirectXはWindowsが標準でサポートするコンポーネントではないということが背景にあるようだ。

(DirectXが)入っていないならば入れればいいじゃないか、という意見もある。実際、最近の市販のWindows用ゲームはDirectX6がインストールされていることを動作条件に掲げてきているものも多い。いまのところWindowsNT4.0ではDirectX3までしか動作しないようだが、Windows2000ではDirectX7までがサポートされるようなので、そうなればそういった議論も少しは減るだろう。

では、実際のところキー入力やサウンドの再生のためにDirectXを使う価値がないのか?と言われれば、答えはNoだと思う。

やはり、キー入力にしてもWindowsのGetKeyboardState,GetAsyncKeyState等を使うぐらいならば、DirectInputを使用したほうが5倍ぐらい速い。(なぜこんなに差が出るのかは謎。最初の設計がよほど手抜きだったのか?) キーボード入力ぐらいたいしたものでもないが、それでも60FPSならば秒間60回行なうわけだし、10個のキー判定を行なうために1フレームごとにGetAsyncKeyStateを10回呼び出していたら、秒間600回にもなる。遅いマシンでは、処理の数%を締めることになる。(これを多いと感じるかどうかは感性の問題だろうが…)

サウンドにしても、DirectSoundを使用せずに再生させるとなると、その再生のlatency(遅延)が気になる。

そんなわけで、DirectXが標準的にWindowsに組み込まれている状況が出来上がってしまえば、使うだけの価値はあると考えるのが妥当だろう。それが当分先でないことを祈りたいのだが…。


戻る