yaneurao Game SDK 講座ついに開講!

§8.だからマイナーバージョンアップに徹する(99/10/19)

食事中にテレビを見てると、スカイ・パーフェクトTVのCMをやたら目にするのですが、スカ・パーと略されると、友達のところに行ったときに何気に置いてあった、スカ○ロ・パラダイス(お食事中のかた、ホンマすんません)とかゆーマニア系の雑誌を思い出してしまうのは、やねうらおだけなんでしょうか。CM中、そんなことを思い出しては、ちょっと、えれえれーって吐きそうになるんですけど。(どうしようもない奴…)

そんなわけで、ygs2Kのβ7の進捗状況を紹介します。(公開できるのは、今週末ぐらい?)

☆☆☆ 文字列操作のための関数 → 文字列の途中から取り出す/文字を数値化する等 → これは、DLLとして本日、Downloadのコーナーに追加しました。

☆☆  関数追加 → 三角関数sin,cos → これもDLLで提供済。

☆☆☆ プレーン拡張 → プレーンの回転blt機能,Secondaryプレーンを任意のプレーンと入れ換る機能 → プレーンの回転bltですが、これ、いま作ってるゲーム(年内発売のやつね)に必要だと言われて追加予定に入れていたんですが、「処理が遅くなりそうです」と話したところ、「それならパターンで持ちます」と言われたので、しばらく実装しません(笑) セカンダリプレーンを任意のプレーンと入れ換える機能は、追加しました。これは非常に便利です。

☆☆☆  / * %等をひとつの式のなかで連続使用すると計算を誤るbug-fix。(例 x = 12/3/2;) → 修正しました。

☆☆☆ マウス入力 → マウスの座標入力/ソフトウェアマウスカーソル → 追加します。

☆☆☆ 低レベルファイルI/O → 書き出し/読み込み → これもDLLで提供することにします。(後日)

☆☆  フォルダ内のファイルリストアップ等 → DLLとして後日提供します。

その他の対応予定としては、

☆☆  発見されているbug-fix(現在発見されているのは、MIDIのループモードの不都合のみ)
☆☆  MIDIデータ解析DLL(MIDIファイルから、特定のチャンネルのデータを拾うような機能
☆☆  BMS読み込みサポートDLL(おお!ついに!?)
☆☆  構造体サポート(これ、出来るんかなぁ…)
☆   ハイスコア暗号化書出し機能

があるわけで、これらは次のバージョンに持ち越しかなーとか思ってます。

ところで、yaneuraoGameSDK1.00β2のほうは、VisualC++5.0ではコンパイルできないとの多数のご報告をいただきました。うえーん。開発途中は、コンパイル出来てたんですけどねぇ…最終チェックはしてなかったですけど…。(それがいかんのや、それが)

ご要望、ご感想、そして動作不都合やマニュアルの記載ミス等を発見された方は、やねうらおまでお気軽にメールください。めったなことがない限り、メールには100%返事を書きますんで。ちなみに最近、返事を書かなかったのは、「会社の後輩に聞いてBMを知りましたが、ポケモンの曲を是非作ってください」ってメールだけです(笑) なんでポケモンなんや?この人、ひょっとしていまあるBMSファイルは全部、やねうらおが作ってると思ってらっしゃるのでありましょうか(笑) 返事を書かなかったことを、この場をお借りしてお詫びいたしますけどね。はい。


§9.こんなん来ましたけど〜(99/11/1)

なんか、いま、趣味で電子制御による可動式の人形作ってます。参考にするためにトイザラスでバンダイの某人形を買ってきたんですが、母親に見つかっていまではすっかり変態扱いです。(しくしく)

そんなやねうらおは、昨日、こんなメールいただきました。原文そのまま転載します。(Luv-Reverseさん、無断で公開しちゃってすみませんね)

こんにちわ。初めてメールさせて頂きます。
Luv-Reverseというものです。ベーマガ読者ならお分かりかもしれませんが、「野菜
村」か「YASM」という投稿者がいたら、間違いなく私と同一です。よろしく。
さて、自己紹介はこの位にしまして、GameScriptβ7DLさせていただきました。ほ
んっとに使いやすいです。そしてかなり速いです。(HSPと比較)早速、DDRSOLOを移植
してみました。まだLEFTRIGHTMIRRORSHUFFLEHIDDENまったく追加機能なしですが、
msd(DDR99データファイル)ファイルを読んで踊れるくらいは出来ました。

なんというか、Luv-Reverseさんのように、ygsが「使いやすい&速い」と言ってくださる人がいるかと思えば、ygsは「わかりにくい&遅い」と言う人がいたりするから世のなか不思議です。まあ、どちらの意見も否定する気は毛頭ありません。貴重なご意見を、真摯に受け止めたいと思っています。

それは、さておきですね。いま、私は何をやっているかというと、まず、年末に発売するサウンドノベルですね。これ、結局、メインプログラム組んでないので、すでに私の仕事は終わりなわけです(笑) それから、年明けに発売する盗撮マニアの続編ですね。これは、らうーるさんに振ったので(笑)、私はバックアップのみです。

それよりか、いまの仕事にきちっとケジメをつけて辞めたいと思っているので、いまの会社の仕事を自宅に持ち帰って毎日やってるわけですよ。なかには、世界特許レベルの内容がいくつも含まれてるんですけど、会社の上司はそんなことてんでわからない人なんで、たいした評価もされてないんですが(笑) まあ、そういうほうが気楽でいいでしょう…。

そんなわけで、今後のバージョンアップは、のろのろになる可能性もなきにしもあらずですが、予定としては、

 Directory検索DLL → 11/3公開
  暗号化DLL → 11/5ぐらいに公開したい
☆ MIDIデータ解析DLL → 11/7ぐらいに公開できるんかな?
  β8 → 11/10ぐらいに公開できるといいね

β8(次バージョン)での予定

☆ 文字幅を得る関数追加(センタリング等のため)
 イニシャライザでサウンド数やプレーン数の上限を変更出来る機能追加
 ユーザー関数呼び出しに;がなくてもコンパイルが通るバグ修正
 DLL側で描画が出来るようにプレーンの情報を渡す関数を提供

それで、余すところ、

☆  BMS読み込みサポートDLL(おお!ついに!?)
☆  構造体サポート(これ、出来るんかなぁ…)

機嫌がよければ、

☆  ネットワークゲームのサポートDLL
☆  GDI系の描画DLL
☆  Mp3の再生DLL

関連アプリとしては、

  『Piano Mania』(ピアノトレーニング用ソフト)

さらに余裕があれば、3D関連も着手したいなーとか。(年内無理だろうなぁ…)

そう言えば、このygs2KはWindows2000で本当に動くんでしょうか(笑) フォント関連がまた何かトラぶりそうな気がしないでもないですが、いまのところ、Downloadのコーナーからリンクを紹介させていただいているみなさんの作品は、WindowsNTでも動作を確認していますので、Windows2000でもそのまま動くのでしょう(と思いたい)


§10.システムメモリを使う(99/11/7)

質問には2タイプあって、純粋に初心者的な質問と、マニュアル側の不明瞭さから生み出される質問とがあると思います。前者は、ロバートさんにお任せすることにして、後者の質問で、私しか答えられない部類のものについてこの場をお借りしてお答えしたいと思います。

Q.システムメモリは使うべきですか?使うととても遅いのですが。

この質問が何のことを言われているかわからない方もおられるかとは思いますが、これは、SetSystemMemoryUse関数を使って、プレーンを、システムメモリに配置する必要性があるかどうかについての質問です。

結論から言いますと、SetSystemMemoryUse(0);(初期状態)の場合、システムメモリを使わないではなく、ビデオメモリを優先して使い、ビデオメモリが足りなくなったら、システムメモリを使うの意味です。ビデオメモリだけを強制的に使うオプションは用意していません。また、SetSystemMemoryUse(1);の場合は、強制的にシステムメモリを使うの意味です。

ビデオメモリとは、ビデオカードに搭載されているメモリのことです。これを使うと、転送がビデオカードのメモリからビデオカードのメモリになるため、ビデオカード内で処理が可能なわけで、とても速いのです。

ところが、ビデオカードのメモリは、古い機種だと1MBや2MB程度しか載っていないことがありますので、ビデオカードに入りきらない分のプレーンは、システムメモリに配置されます。

そうすると、システムメモリ→ビデオメモリへの転送が必要になって、その分だけ遅くなるのです。(ビデオメモリとシステムメモリとの行き来には、少し時間がかかるとそうお考えください)

このへんは、普通にプログラムしている分には、まったく意識する必要はありません。たいてい、セカンダリプレーンは、ビデオメモリに配置されているはずです。(最初は、ビデオメモリからメモリを割り当て、足りなくなってから、システムメモリからメモリを割り当てることを思い出してください。ygs2Kが起動するとき、最初にセカンダリプレーンが生成されますから、まず間違いなくビデオメモリに割り当てられていると仮定して良いのです)

※ ビデオメモリにプレーンが配置しきれなくなった場合、システムメモリに配置されるので、結果としてシステムメモリ→ビデオメモリへの転送をしていることになり、ビデオカードによってはSetSystemMemoryUse(1);として、すべてシステムメモリに置いたほうが速いケースもありますが、そこまで心配しても仕方ないで良いでしょう。

ところが、フェードイン/フェードアウトやブレンド機能を使おうとすると、ここで問題が生じます。なぜなら、フェードアウトやブレンド機能は、ビデオカードの機能で行なっているわけではなく、ソフト側で(要するに自前で計算して)ピクセルをひとつひとつ操作するからです。ひとつひとつのピクセルを操作するために、ひとつのピクセルのRGB値を、読み込みます。これは、ビデオメモリ→システムメモリです。その後、書き出すには、システムメモリ→ビデオメモリという転送が必要になります。これが遅くなる原因のひとつです。(理解する必要はまったくありませんが、突っ込んだ話をすると、DirectDrawでDirectDrawSurfaceをlockすると、linearなメモリを供給するためにページフォールトハンドラが利用されるので、そのへんも処理時間に影響しているはずです)

よって、フェードアウト処理やブレンド機能(あと、テキスト表示も含まれるはずです)を利用するときに、ビデオメモリをシステムメモリに配置してあると、システムメモリ間の転送で済むので、その分、速くなるということです。デメリットとしては、たとえば、Blt関数を実行したとき、ビデオメモリを使っていれば、ビデオカードがその転送処理を受け持ってくれるのに対し、システムメモリに配置している場合、CPUが自前でその転送処理を行なう必要があるということです。要するに、普通のBlt描画は、遅くなるのです。このへんは、バランスの問題なのですが、フェードイン/フェードアウトをメインに使いたい部分は、事前にSetSystemMemoryUse(1);とやる手はあります。プログラムの途中で、自由にSetSystemMemoryUseを呼び出して構いません。ただし、その瞬間、いったんプレーンを破棄し、再構築(=ビットマップデータの再読み込みも兼ねる)される分の時間が暗黙的に乗ってくることに注意してください。

そんな難しいことはわからーん!という方は、基本的に、ビデオメモリを使って、フェードイン/アウトが遅いのは、仕様だと考えていただいて構いません。


§11.そろそろ正式バージョン公開(99/12/19)

日本海は日本の海ではないとか何とかで問題になっていますが、それより、なんで日本はJapanであってニッポンではないんでしょうか。(外人に『ニッポン』と言ってもまず通じない) たぶん『日本』の中国読みがジパングで、Japanというのは、そこから来ているのだと思うのですが、なんだか差別的なものを感じてやみません。外人にWhat nationality are you?と国籍を尋ねられたときは胸を張ってI'm ニッポン人と答えましょうよ。たぶん、I don't know nipponzing,where's that?とか言われて終わりでしょうけど(笑)

それは、ともかく、このように実体はひとつなのに複数の呼び名がある場合がプログラムにおいてもよくありますね。ひとつの概念なのに、複数の呼び名が存在したり、ひとつのことをするだけなのに、複数のインターフェースがあったりする。

インターフェースってのは、要は、入り口です。入り口がいっぱいあるけど、すべてひとつの大広間の扉だったなんてことがありますね。ここでは、入り口とは、関数の呼び出し規約、もっと簡単に言って、関数の名前や、その引数の数や、それぞれの引数の意味とぐらいに考えてください。

単に関数が別名であるだけならば、それはaliasと呼ばれるのですが、ちょっぴり引数のニュアンスが違ったりする場合、それはadapterだとかwrapperだとか呼ばれます。adapterというのは、電源アダプターとかのアダプターです。適合する(adapt)ように変換するからadapterです。wrapperのほうは、サランラップとかのwrapで、こちらは包むの意味です。

このように、あるインターフェースを、wrapして、別のインターフェースを用意する意義は、いろいろあります。

まず、より単純なインターフェースを提供すること。呼び出し規約が複雑すぎて使いにくい場合(たとえば音を再生するだけなのに関数を何十個も呼び出す必要があるような場合)、より単純なインターフェースを用意することによって、使いやすくなるはずです。これはwrapperと呼ばれます。

次に、別のタイプのインターフェースを用意してあるほうが、プログラムが組みやすくなる場合。これはadapterと呼ばれます。

どちらも、ソフトウェア工学上、とても面白い概念なのですが、ここでその効用を語っていても仕方ないので、今回はadapterの例を考えてみます。

たとえば、ygs2Kには拡大表示するための関数としてBlt系の関数にはsuffix(末尾辞)にRがつくバージョンがあり、BltRならば、それはBltの拡大縮小機能つきのバージョンということです。

このBltRが、ユーザーにとって使いやすいとは限りません。たとえば、拡大縮小する矩形の中心を拡大縮小中心として、拡大率を指定したいことがあるでしょう。この場合、BltR2として、以下のような関数を用意します。(このようなファイルを作って、必要に応じてincludeして使います)

//
// bltr2nd.h :
// 中心から拡大縮小bltするサンプル
//

int BltR2(int no,int x,int y,int rx,int ry){
    // noのプレーンを(x,y)の座標を中心にrx,ry倍したものをblt
    // ただし、rx,ryは65536倍しておくこと。(<<16)

    int px,py; // プレーンサイズ
    GetPlaneSize(no,&px,&py);
    // 拡大後のサイズ/2を計算
    px = px*rx >> 17;   // (px*rx>> 16) / 2の意味
    py = py*ry >> 17;
    BltR(no,x-px,y-py,rx,ry); // その分、表示座標をオフセットする
}

また、他に考えられるケースとしては、拡大縮小後のサイズを指定したBltRが欲しいという人もいるでしょう。この場合、

//
// bltr3nd.h :
// 拡大縮小後のサイズを指定してbltするサンプル

int BltR3(int no,int x,int y,int sx,int sy){
    // noのプレーンを、x,yに拡大縮小して表示。
    // 拡大縮小後のサイズを(sx,sy)に入れておくこと。

    int px,py; // プレーンサイズ
    GetPlaneSize(no,&px,&py);
    BltR(no,x,y,(sx << 16) /px,(sy << 16) / py);
}

ですね。希望サイズ/元のプレーンサイズを拡大縮小率として指定すればよいわけですが、こいつは65536倍しておく必要があるので、16回左シフト(∵65536 = 2^16)しています。Blt系の関数ならばどれでもこのテクが使えます。(自由に使ってください)

あるいは、プレーンのある矩形を、拡大縮小後のサイズを指定してBltしたいという人もいるでしょう。あるいは、そのとき、プレーンの中心を拡大縮小中心にしたいという人もいるでしょう。(上の2つのテクを応用すれば可能ですね)

このへん、どんなゲームを作るかに応じて、必要なインターフェースの形態は異なります。上に挙げた以外のパターンも複数考えられます。そして、そういう関数があればいいのにという人はいます。しかし、すべてを用意するのは不可能ですし、また、いろんなインターフェースが用意されていれば使いやすいというわけでもないです。

このへんがライブラリ設計の難しいところで、実際に使っている人は、「なんでこういう関数仕様になってないんだろう?こうなってれば、凄く使いやすいのに」と考え、「こういう関数仕様のものがあれば、あなたのライブラリはもっともっと立派になりますよ」とメールしてきます。(それが悪いって意味じゃないんですよ) もちろん、彼は本気でそう信じています。(気持ちはよくわかります)

しかし、よく考えてみてください!拡大縮小系の関数ひとつ採って考えても、これだけのバリエーションが存在するわけです。それらすべてを用意していたらキリがありません。このような場合、同じ機能に対して、複数のインターフェースを用意するということは、とてもナンセンスだと言わざるを得ません。


§12.ついに正式バージョン公開(00/01/19)

もうみなさんご存知でしょうが、ygs2Kの正式バージョンのリリースを開始しました。お正月を潰したわりには見た目は何も変わっていません。主にバグ取りと、DLL側からプレーンやサウンドを直接操作できるようにしていました。(スクリプトSDK)

と言うことは、DLL作成者以外はあまり関係ないようにも思えますが、副産物としてスプライト表示用のDLLやトランジションを行なうDLLが完成しました。

このスプライト表示用のDLLですが、キャラクターもののゲームには必須とも言えるもので、いままで作りたくてもDLL側からプレーンを操作できないために作れなかったのです。これは、あくまでサンプルのつもりですが、このスプライトDLL自体、ある程度、使いものになるDLLだという感触はありますし、またスクリプトSDKによって、いままでスクリプト単体では不可能だったようなキメの細かい操作がDLL側から行なえるのではないか?という期待もあります。(トランジションDLLなんか、ちょうどそれですね)

普通にBltするのとこのスプライトDLLを使うのとどちらが速いですか?という質問を受けたのですが、複数のスプライトを表示するならばSpriteDrawの呼び出し一発で終わる分だけスプライトDLLのほうが速いです。単発でも引数が少ない分、普通にBltするより微妙に速いかも知れません。まあ、キャラクターゲームならば使って損のないDLLと言えるでしょう。

あと、トランジションDLLのほうは、徐々に移り変わるタイプの画面効果を集めたものです。

トランジションDLLを作るに至ったきっかけは、

http://www.din.or.jp/~keijiro/products/

のminimalというデモプログラムです。これ、ソースも付いてるんですが、はっきり言ってすげーです。個人の作品で、こういうの見たことなかったので、感動しました。まったく、世のなかには凄い人がいるもんです。鼻水出ました(笑)

トランジションDLLには、まだ追加したい表現が100種類ぐらいあるのですが、DirectXを使用している都合上、矩形の転送系は強いのに、フェード、ブレンド、ぼかし、ピクセル操作等は全般的に弱く、たとえば、テレビのチャンネル切り替えのようなノイズを表現するために、画面全体にランダムで弱いノイズをバイアスで(つまりいまのピクセル輝度に加算されるように)かけようとしたりすると、これはもうDirectDrawでは手に負えないのです。(サーフェースをlockして、直接書けば出来なくもないのですが、そうすると256色モード、HIGH COLOR、FULL COLOR、TRUE COLORのそれぞれのモード用に固有のルーチンが必要になって、かつ、このようなサーフェースの直書きが非常に遅いビデオカードもあり、おまけに256色モードだとパレットのことを考慮する必要が出てきて、さらに、MMXぐらい対応させようかなどと考え出すともう夜も眠れないほどの労力を必要とするのです。テクスチャーを多角形に貼り付けるような処理も、この部類に入ります。これが出来れば擬似ポリゴンが可能となるのですが、DirectDrawでその処理を書くよりDirect3Dに対応させるほうが遥かに簡単なのです)

まあ、トランジションDLLのほうは、もう一度、大幅バージョンアップを行なう予定なので、それについて、みなさまの要望をメール等でお聞かせください。なるべく反映させたものにしようと思いますので。


まあ、こんな感じで次々に拡張していると、突貫工事的に用意した機能が逆に目障りに思えてきます。私にとって、目の上のたんこぶ的なのが、まずシナリオ読み込み機能。こんな特殊用途向きのものはygs2Kの設計理念からしてDLL化すべきなのですが、この機能を実装しないといけなかった時点ではygs2kがDLL読み込みに対応していなかったので、仕方なく付けたのです。普通のファイル読み込み用ならばファイル読み込み用のDLLを使って欲しいところです。(機会があればシナリオ関連については、これを切り離して、別でDLLを用意しようと思っていますが)

それから、Blt系の命令の転送先がセカンダリプレーン固定であるというのもなんだか良くない設計だったような気がします。とは言っても毎回指定するのは面倒なので、転送先を切り替えることが出来ればよかったような気がします。それと、セカンダリプレーンもプレーンの一種として、それをプレーンナンバーとして指定できると良かったように思います。言い訳がましいですが、このへんの設計のまずさは、当初から気づいていました。ただ、ゲームの納期とかの問題もあって、そうも言ってられなかったのです。(マルチウィンドゥ対応にする気はないので、いまさら、変更するほどのことではないでしょうが…)

あと、ygs2Kは、いったん仮想マシンコードに変換して、それを実行しているのですが、その仮想マシンコードをi386のネイティブコードに変換することは、それほど難しいことではありません。今日は、時間があったので、変換実験等をやってみたのですが、なかなか速く動きます。描画などは、もともとDirectXを利用した描画ルーチンを呼んでいるだけなので、まったく速度の向上は見られませんが、四則演算・配列操作・条件分岐等においては、5倍〜10倍程度の速度upが計れています。なかなか面白いです。今月中には、その完成バージョンを公開したいと思っています。これで遅れ馳せながらygs2kも、ネイティブコンパイラの仲間入りというわけです。


§13.動的束縛を利用する(00/03/13)

あまり簡単なことばかり話していると初心者君になめられるんで(笑)、今回からは少し高度なテクニックについて解説していきましょう。なんかたいしたプログラムも組めない人から「こんなもん使えると思うんなら、自分で使ってみるがよろし!」とか言われるとやっぱ辛いですよ(笑)

まずygs2kを使った、私のコーディングスタイルについてご説明します。

私はシーンごとにファイルを分けます。シーンというのは、場面のことで、ゲームのタイトル画面、コンフィグ画面、ゲーム画面、ゲームオーバー画面…に関して、それぞれ異なるシーンだと考えます。

シーンからシーンはJumpScriptかCallScriptで飛びます。たいていは戻ってこないので、JumpScriptで良いです。グローバル変数のスコープはそのスクリプト内なので、ファイルを超えて保持しておきたいパラメータ等は、gameflagを使います。つまり、C++のグローバル変数はygs2kのgameflagに相当し、C++のクラスのメンバ変数が、ygs2kのグローバル変数に相当すると考えています。よって、ygs2kではグローバル変数はファイル単位で外部から隠蔽されていると考え、これにより擬似的なカプセル化が達成出来ていると考えます。

そんなのカプセル化じゃないよ!と言われるかも知れませんが、それもカプセル化だと思います(笑) たとえばC++のクラス名にしても、結局、ある程度の規模になってくると他の人のライブラリと合体させたときにクラス名が衝突したりします。言うまでもなく、namespaceがありますが、namespaceで付けている名前自体が衝突する可能性は依然として残されているわけです。

しかし、実用的にはそれで十分です。カプセル化とはそういうものです。外部から内部の変数を直接的に参照出来ないこと。参照出来ないようにしてあること。どこを外部と捉え、どこを内部と捉えるかは、いくつもの考え方、方法、段階があると、そういうことです。

まあ、カプセル化についての説明はそれぐらいにして、次に描画ルーチンです。

描画ルーチンは、必ず一箇所にまとめます。OnDraw()という関数が良いです。どんな描画であれ、必ずその関数で行なうことにします。しかし、このとき気をつけるべきことがあります。それは、その関数に引数を取ってはならないということです。引数を取らないメリットは意外と大きいのです。なぜでしょうか?

たとえば、現在の画面をフェードアウトさせようとしたとき、fadeout()という関数を呼びます。その関数は、あちらこちで使うのでfade.hというヘッダーの中で定義し、includeします。ygs2kにおいてincludeとは、C言語的なincludeではなく、その場所へ埋め込むという、define文に近いものがあります。つまり、プログラムのどこであってもinclude文が使えます。そして、includeの先でincludeするというようなincludeのネストも16回まで可能です。

fadeout()のなかで、画面に描画して、そしてSetBrightnessする必要がありますが、画面に描画するのはOnDrawすれば事足ります。C言語ならば、描画する関数ポインタを渡し、そいつにコールバックしてもらうことで実現できそうですが、残念ながらygs2kには関数ポインタという概念はありません。(関数アドレスを得ることが出来ない) あるいは、C++ならば、virtualなDraw関数を用意して、派生クラス側でそれをオーバーロードすることによって実現できそうですが、クラスなんて使えないygs2kには、それも無理な話です。というわけで、OnDrawを呼び出すことにします。面白いことに、次のシーンにJumpScriptして、そこでfade.hをincludeしている場合、そのなかのfade.hでは当然、OnDraw()を呼び出しに行くわけですが、その呼び出すOnDrawはそのシーン内の(そのスクリプトファイル内の)OnDrawになります。これは、includeが、マクロ的埋め込みであることと、JumpScriptによって、再コンパイルすることから、こうなります。

LISPなどではこれを動的束縛と言います。C++的にはポリモーフィズムの一種と考えるべきでしょう。このように、includeされたモジュール(fade.h)とbindするOnDrawが動的に決定されるというのは、面白いです。無論、関数だけでなく、変数に対してもこのような動的束縛が出来ます。

この技法を使うことによって、描画に対する効果(フェードイン/フェードアウト/トランジション等)は、すべてパッケージ化(モジュール化)を計ることが出来ます。あるいは、この技法によって、コールバックが必要なものを簡単に書くことが出来ます。

ところで、OnDraw()が引数をとってはいけないのはなぜでしょうか?fade.hからもOnDraw()を呼び出すことがあるので、そのときに引数があると、fade.hの汎用性に欠けるからです。引数をとりたいよーという方、心配いりません。そのためにグローバル変数があります(笑) グローバル変数に何を描画すべきなのかを保持しておきます。グローバル変数を使うとカプセル化が出来ないからダメなんだよー!というかたは、今回の記事の一行目から読み直していただくことにして(笑)、今回は、とりあえずこれでおしまい。

実のところ、ygs2kを作った当初は、あんまり便利でないと思ったんですが(笑)、最近、マップ移動ゲーをいくつか作ってると、リアルタイムにプログラムを編集出来るので、とってもやりやすいです。主人公動かして隣の部屋に行く前に、その部屋のスクリプト作って、どんどんプログラム書きながら主人公を歩かせることが出来るし(チクタクバンバンみたい(笑))なかなか使い心地いいと弟子のらうーる君が言ってました。(なんや、お前使ってへんのやないか!>俺) ごめん…。ちゅーか、らうーる君、ここのところ監禁しててごめん…いま作ってるゲームのマスターアップ出来たら、お家に帰したげるからね(笑)


§14.開発終了の兆し(00/06/03)

いやーygs2kのオフ会、楽しかったです。烏龍茶ひとつ授与するだけなのに、なかなか壮絶なメンバーでした。また機会があったらやりたいと思います。

さて、もうみなさんご存知かと思いますが、ygs2kは、MP3対応になって、そのあとJPEGとSusieのPlug inに対応になりました。

あと、お楽しみCDの原稿書いてて、HTMLからカット&ペーストすると全角スペースが混じるのでサンプルがコンパイル出来ないと編集者から指摘を受け、全角スペースに対応、ついでに変数名・関数名に漢字を使用可能にしました。返す刀で/*  */によるコメントをサポート。

漢字が使えるのが良いのか悪いのかはわかりませんが、かなり独創的なプログラミングが出来ることでしょう(笑) あとは、defineみたいなのを用意して、命令すべて日本語で書くというのもできそうですが、今回は面倒なので割愛。

その後、DLLが気にいらないからimport一発で読み込んで関数設定まで出来るようにしました。せっかくだからグラフィックを扱うGDIライブラリと時間取得のtimeライブラリ追加。あと、正規表現による文字列のマッチングをインポートライブラリで対応したいと思ってましたが、本格的にやるとどうも遅くなるのと面倒なのとで、簡易的なパターンマッチングのみにしました。(あと綺麗な文字描画とかも欲しいですが…そうそう、BMS読み込みのやつもいるのかな:p)

…と夢があるようですが、なんだかこのスクリプト、私の理想とはかけ離れているんですよね〜。私が自分で使いたいと思うのはJavaのようなオブジェクト指向言語です。もちろん初心者の人がとっつきやすいとは到底思えないですが(笑)、それでも自分が使うとなるとそっちのほうが断然いいです。

そんなわけで、ygs2kは初心者向きのゲーム開発言語としては、ほぼ熟してきた感じがするので、いまの開発が一段落したらオブジェクト指向スクリプトを開発しようと考えています。まあ、公開するかどうかは正直わかりません。それというのも敷居はかなり高くなりそうだからです。初心者の人から、こんなもん使えないにょ!とひとことに言われておしまいのような気がしますね(笑) だとしたら、そんなものは一般公開するに値しないわけで...。

というか会社の仕事がいっぱいいっぱいで…。(泣きごと)


戻る