2016年02月19日の日記です


秒殺(2)  2016-02-19 14:52:24  業界記

秒殺のプロジェクト進行は、予定よりも遅れていたようです。

本当なら、春のゲームショーには参考でも良いので出展するはずだった。でも、このペースでは出展が微妙。


だから、とにかく仕様書が作られ、先輩プログラマ3人が猛烈な勢いで実装していました。


プログラマならわかると思いますが、猛烈な勢いでプログラムするときって、品質は二の次になる。

とにかく動けばよい、という形で、類似ルーチンを切り張りして、似て非なるプログラムがどんどん増殖します。


これを3人でやっているのです。

人のプログラムに手を出してしまうと混乱するから、誰かが作ったルーチンを改造したいときは、コピーして改造する。

その改造ルーチンを別の人が使いたいときは、さらにコピーして改造する。


類似ルーチンが増えすぎ、どこかにバグや仕様変更があった時は、全部に手を加えないといけません。

管理が煩雑化しますし、何よりもメモリの無駄遣いでした。



途中から投入された僕の仕事は、このプログラムをすっきりと整理する、ことでした。

ただし、ショーが迫っているため、3人の作業を邪魔してはなりません。


混沌が追加され続ける作業を止めずに、混沌をなくすのです。




例えば、敵が弾を撃つことを考えてみましょう。


弾を動かすプログラムと、その弾を発生させるプログラムがあります。

発生時は、その弾を撃つ敵キャラクターの位置から弾が発生し、プレイヤーの操作する自機を正確に狙って飛ぶように移動方向が定められます。

そして、そのパラメータに従って、弾が動き続けます。一定速度でまっすぐ飛ぶ、のです。


秒殺でも、当然こうしたプログラムが最初に用意されたようです。


でも、縦シューやる人ならわかるけど、敵弾って自分を狙うばかりではないよね。

例えば、自分とは関係なしに、一定のパターンでばら撒かれる弾がある。

そういう動きを企画書で指示されたため、弾の発生プログラムがコピーされ、「角度」を渡せるように拡張されます。


さらに、弾を同時に3発、15度の角度を開けて撃つような指示があり、「散弾角度」や「同時発射数」が指示できるような拡張もあり、「弾の速度」などを変えられるような拡張もされています。


弾を動かす方のプログラムも、最初は弾の速度が一定だったのが、速度可変になったり、途中から加速する、自機を狙うホーミング弾を動かす…などなど、拡張されます。

これらがすべて、「少しづつ違う別のプログラム」として作られてしまっているのです。


これらを何とか整理してほしい、というのが僕に与えられた仕事でした。




まず、弾のデータを保持する構造体を整理しました。

多数あるプログラムごとに、少しづつ違う構造体があったのを、全部共用できるように。


ミソは「特殊処理ルーチンへのポインタ」を持たせたこと。

ポインタが NULL なら線形の動きをしますが、ポインタが存在していれば特殊ルーチンを呼び出します。


これは、ホーミング弾や加速弾などの特殊な動きに使われます。

あとは、線形でも速度が変えられるように「速度」パラメーターを持たせたり、その程度。


発生プログラムのほうは、自機を狙うかどうかのフラグ、発射角度、同時発射数…など、非常に多くのパラメータを受け取る関数を用意します。

先ほど書いた「特殊ルーチンへのポインタ」も、ここでセットできるように。


でも、引数が多すぎると使いにくいですし、今までのプログラムを全部書き換えないといけなくなる。

そこで、今までの関数と同じ体裁で、内容は「書き直した関数を適切に呼び出すだけ」の関数(ラッパ関数)を用意します。


これで、今までのプログラムはそのまま動くし、今後特殊な弾が必要になっても、多数のパラメータを適切にセットすれば、プログラムを改造する必要はなくなるはず。


といっても、一部で今までの構造体を直接アクセスするようなプログラムもありました。

そういう箇所は、個別対応で書き換える必要がありました。


#簡単にいえば、共通部分をまとめたスーパークラスを作り、処理の違う部分は個別のメソッドとしました。

 継承クラスとしてメソッドをオーバーライドしたものを作ることで、多様な動作を作り出せます。

 …と、オブジェクト指向の知識があればそう説明できるけど、使用言語はC言語でした。



2016.4.29追記


前提となるゲーム技術を解説しているページを見つけました。

というか、かつて存在したページが、Wayback Machineに保存されていた、という形かな。


上記ページの説明では「タスクシステム」と呼んでいますが、処理とデータをメモリブロック(上記記事ではワークと呼んでいる)内でひとまとめにする技法です。


上記ページでは「ギャラクシアン発祥説」を唱えているけど、、ギャラクシアンではこの技法は使われていないそうです。と、付記しておきます。


以下は、上記ページの内容を読んで理解した、もしくはすでに知っていた人向けの解説。



タスク生成がインスタンスの生成になります。

汎用ルーチンを使うなら(=クラスを継承するなら)、ワーク内のデータは位置を揃える必要があります。


上記記事で解説していませんが、例えば「画面に表示するキャラクター」のクラスであれば、X Y 座標とキャラクタの ID などをワーク内の共通位置に持てば「キャラクタ表示」関数を共通化できます。



ワーク上に処理関数へのポインタを置いて呼び出すのはメソッド呼び出しになり、ポインタの書き換えはオーバーロードに当たります。


キャラクタクラスを継承して「敵」のクラスを作ったとします。

あたり判定など、共通の処理は敵全体の共通処理です。


敵の動きなどは種類ごとに異なるので、「敵の動き」というメソッドを作ります。

(処理関数へのポインタを持たせる)


敵の共通処理の中で、このメソッドを呼び出すようにしておけば、敵の処理自体は共通化したままで、個別の動きは変えられるわけです。



僕が入る前の「秒殺」のチームでは、他の人が作ったタスクシステム上にすでに存在していた「画面表示キャラクター」用のクラスは使っていたのですが、そのクラスの下に敵の種類・敵弾の種類ごとに別々のクラスを多数作ってしまっていました。


僕の作業は、これらの多数のクラスの「スーパークラス」として、「敵」や「敵弾」のクラスを作り、個別の敵・敵弾は、そこからの派生クラスとした、というものになります。



以上、追記終わり。




大切なのは、すべてを統合した「巨大関数」について、詳細な仕様を残しておくこと。

呼び出し方法はもちろんのこと、どこのプログラムが、どんな理由でつくられており、実際にどのルーチンで呼び出されたときに有効になるか。

これを整理して文書化しておきます。


そうしなくては、「プログラムが理解できないから、いじってバグが出るのが怖い」という理由で、またコピーが増えることになります。

どこにどんな意味があるのか、実際どこで使われているのかが明確になっていれば、手を加える際にも間違いが減りますし、実際に影響がありそうな部分で動作の互換性を確かめられます。


弾だけでなく、敵の動きやボスの動きなども同じように統合していきます。



そもそも、チーム配属された時点で、僕はプログラムは一切理解できていないわけです。(まだ見てもいないのですから)

プログラムの理解から初めて、こうしたプログラム整理をするだけで、配属から1か月くらいかかった記憶があります。




しかし、1か月というのはショーへの締め切りを意味していました。

今後拡張しやすいように内部を整理する、という作業だけに追われ、結局ショーに向けての「拡張」を開始することができません。


ショーへの出展は見送り、と決定されます。


正直なところ、ここまで頑張ってきた企画・プログラマの面々には申し訳ないのですが、急に投入された僕から見ると、この時点でのゲームは全然面白くない。


形だけを突貫で整えた、というだけで、バランス調整などが入ってません。


ゲームの面構成も、今すぐ使えるプログラムを組み合わせた、という感じでバラエティに乏しい。

どの面も同じように見えます。



そのことは、企画者もわかっていたようです。

ショーへ出展しない、と決まった時点で、「間に合わないとわかっているから手を付けなかった」部分の拡張に入ります。



僕は、地上の敵に複雑な動きをさせたいので、配置してほしい、と頼まれました。


ここまで、地上物は「地上に固定」されていたのね。

ところが、ここで頼まれた地上物は、テクスチャに描かれた道の上を走ることになっている。

この「道」はただの絵で、どのように動かすか、というデータすらない状況。


しかも、3D表現を活かすために、この「道」がついているのは、実は巨大な空中物の表面だという設定になっていて、3Dでぐりぐり回るのです。

そんなこと、それまで一切考えられていない。


最初は、「それらしい動き」で誤魔化そうとしましたが、多数の敵を「巨大な空中物」の表面に固定するのには無理がありました。

ちゃんと計算するプログラムを作らないとだめだ、と思い、関数をくみ上げている最中に、プロジェクトの中止が決まりました。


だから、僕はこのチームで「プログラムを整理した」だけで、何も作り上げるような作業ができていません。




中止が決まる直前、春のショーが開催されました。1996年の AOUショーね。


このショーでは、タイトーから「レイストーム」が発表されていました。

すでに人気のあった縦シュー「レイフォース」の続編でありながら、3D表現を大胆に取り入れた、新たなジャンルを作り上げていました。


#知らない人は、レイフォースのリンク先の Youtube 動画を見た後で、レイストームを見るといい。

 ゲームシステムがほぼ同じで、前作を遊んだ人には違和感なく遊べるにも関わらず、画面表現が全く違う驚きがある。


狙いは全く同じ。ただし、秒殺はいまだ見せられる状態になっていないし、既存の縦シューをポリゴンで模倣するのが精いっぱいの段階で、「新たなジャンル」を感じさせるまでにはなっていません。


レイストームは、ヒットタイトルの続編で、違和感なく遊べるシステムを作り上げながら、新しい画面表現に成功していました。

どう考えても勝ち目のない勝負。プロジェクトの中止も当然でした。




メインプログラマの先輩は、本当に縦シューが好きで、このプロジェクトにかなり入れ込んでいました。


ただ、やっぱり作成経験が乏しかった。どんなに遊ぶのが好きでも、それで上手に作れるわけではない。

プログラマだけでなく、企画も含めてね。


経験が少ないジャンルって、よくあるゲームの模倣を作るのだけで精いっぱいで、新たなアイディアを入れる余裕がないのです。


メインの先輩は、このしばらく後に、家庭の事情もあって、退社して実家に帰りました。

入社直後からお世話になっていて、仕事以外の趣味分野でもゲームや本の貸し借りをしたりする仲の良い方だったのですが、その後は連絡もしていません。



同じテーマの日記(最近の一覧)

業界記

関連ページ

凄腕プログラマ【日記 18/06/06】

別年同日の日記

03年 とりあえず復活

04年 究極のプログラムツール

05年 忙しい1週間・金曜日

15年 ロケテストとショー発表

19年 「蓄音機」特許の成立日(1878)

19年 久しぶりの「今日は何の日」


申し訳ありませんが、現在意見投稿をできない状態にしています


戻る
トップページへ

-- share --

2000

-- follow --




- Reverse Link -