LECTURE
Oeffentliches Kunst Nr.4
 これまで三回に渡って、主にプログラムの高速化技術について話してきました。それは非力なマシンでもできるだけユーザに快適にプレイしてもらうためでした。ご存じの通り、コンピュータ関連技術は驚くべき速度で発展を遂げ、アマランスII発売の頃にはV30-CPU搭載機よりもi80286-CPU搭載機の方が主流となっていました。これらの機種で前作アマランスをノーウエイトモードでプレイすると、ゲームに支障をきたすほど高速になります。
 このような背景もあり、アマランスIIではさらなるの表現力の向上を目指し、16色対応・80286-CPU搭載機推奨という形で作り始めたのです。ちなみに前作アマランスが16色対応ではなく8色モードだったかというと、PC-9801VM/VFが16色ボードオプションだったからです。VX以降の機種で標準搭載となりました。また、V30-CPU搭載機を対象外としたかというとそうではありません。快適とはいえませんが、十分にプレイ可能な速度になるよう配慮しながら高速化しています。
 多機能8方向スクロール
フィールドアニメーション例
 同時発色数が16色と倍になったことで、前作に比べても表現力がグッと向上しています。また、フィールド上にNPC以外にも、敵キャラクタやパーティーメンバーなども表示されるようになったため、賑やかな雰囲気になっています。横に流れる川はもちろんアニメーションしています。
 スクロールに関しては前作と決定的に異なる部分があります。それは「フリップ」を使用している点です。フリップに関しては前回説明したとおり、2枚のV-RAMを垂直帰線期間に入るタイミングで切り替えることによってちらつきを一切出さない手法です。余談ですが、この手法を採るとマップフィールドをデザインするグラフィッカが気をつけなければならないことがあります。それは「同じPCGをひとつおきに配置すると高速化する」ということです。前作やビートバイスでは同一のPCGをスクロール方向に並べると書き換えが不要になり高速化しましたが、フリップを使うと二枚のV-RAMがかわりばんこに書き換えられることになるため、「ひとつおき」になるのです。
 また、16色対応になったことで変化した点もあります。それは同時に表示できるPCGの個数です。前作では256個使えましたが、アマランスIIでは204個に制限されています。これは16色になったことでデータサイズが大きくなったことによるものです。当然、キャラクタのデータサイズも大きくなるので、こちらも数の制約がキツくなっています。このあたりはグラフィッカの努力によって補われています。
 ちなみに、PC-9801シリーズでフリップを使うということは、常に描画は裏V-RAMに対して行われることになります。V-RAMのアクセスが低速であることは前回書きました。ここで気になるのは、「裏V-RAMは画面に表示されていないメモリ」であるという点です。V-RAMが低速な主な理由は、画面に表示するためにグラフィックコントローラからもアクセスされるからでした。では、少なくともアクセスする時点で表示されていない裏V-RAMのメモリアクセス速度はどうなるのでしょう?実は表V-RAMよりもずっと高速なのです。ただし、メインメモリに比べるとやはり低速ですが。これにより、フリップは意外と高速動作させることができるのです。
 さて、フリップを使うことで速度的には若干低下しましたが、その分だけプログラムをすっきりと簡略化することができ、機能面が向上しています。二重スクロールのスクロールステップを任意に設定できたり、奥のスクロールプレーンもアニメーションさせられたりといった部分です。
 それ以外にもノウハウの蓄積が、より高機能・高効率なスクロールを実現する助けになっています。以下はアマランスIIのスクロールシステム用マップデータの属性ビットを示しています。

  0〜7・PCG番号(0〜203)
  8・透過指定(背景が透ける)
  9・アニメーション指定(アニメーションする)
 10・下半身非表示指定(下半身が表示されない)
 11・完全非通過指定(絶対に通過できない)
 12・非通過指定(キャラクタが通過できない)
 13・マスク指定(合成されるキャラクタにマスクがかけられる)
 14・全体マスクPCG指定(1PCG全体がマスクON状態である)
 15・イベント発生指定(この場所でイベントが発生する)

二重スクロール&遠景アニメーション例
 二重スクロールによる奥行き感の強調。小高い丘の上から海を臨む状態。さらに遠くに見える海面がアニメーションしている。16ドット単位のスクロールでも十分に雰囲気が伝わる。

 8は二重スクロール時に奥のプレーンが透過する部分に立てます。10は浅瀬や草むらに入ったとき、キャラクタの身体が沈んだように見せるときに立てます。11と12は障害物指定ですが、壁抜け呪術が存在する関係上、2ビット必要になります。14は合成処理が不要であることを明示しており、速度向上に寄与します。15はその場所で何らかのイベントが発生することを示し、このビットが立っているPCGに主人公キャラクタが重なった場合のみ、イベントのチェックを行います。これもスクロール速度向上のために設けられているビットです。
 これらのビットの組み合わせで、アマランスIIのスクロールシステムは高い表現力と高速性の両方を実現しています。

 これは余談になりますが、アマランスIIのスクロールシステムは当初8ドット単位のスクロールにも対応していました。しかし、よりスムースなスクロールを実現できますが、80286搭載マシンでも十分な速度とはいえず、8ドット単位で動くのは戦闘モードの各キャラクタのみということになっています。実際にやってみて感じたのですが、スクロールはスムースであればあるほど良いというわけではないようです。フィールドの広さやイベントの密度との兼ね合いもあり、プレイヤーが「快適」と感じるスクロールステップと速度があるように感じました。人は二本の足で歩く生物ですから、一歩踏み出すごとにカクッカクッとスクロールしても違和感を覚えにくいのかもしれません。コンシューマ機用のスクロール型ARPGソフトのように、ドット単位でスムースにスクロールするフィールドでキャラクタがテクテクとアニメーションすると、地面を滑っているように見えたりします。慣れもあるのでしょうが、私などはこちらのほうが違和感を感じるから不思議なものです。(もちろん歩くアニメーションのコマ数が多ければ違和感は感じませんが。)
 クリッピング
 クリッピングは3Dゲームの世界で非常に重要な処理です。プレイヤーの視界以外の部分をカットする処理のことをいいます。これは2Dの世界でも同様に重要な処理です。フィールドに大きなキャラクタが出現した場合、そのキャラクタの一部がフィールドエリアの外にはみ出すことがあります。何もしないとフィールド画面以外のステータス表示域や飾り枠などが上書きされて壊れてしまいますから、フィールド画面以外の部分でないかチェックしながら表示しなければなりません。これは使用頻度の高い重要な処理ですから、ゲームにおいては効率よく高速化する必要があります。
 アマランスIIのクリッピング処理は非常に高速です。一般的なクリッピングアルゴリズムではなく、早い時期に場合分けを実行し、専用ルーチンで描画を行っています。ボスキャラをコマ落ちなく動かし、ザコキャラがわらわら出てきてもストレスを感じないようにと考えたのですが、今にして思えば、ここまでやることはなかったかな・・・・とも思います(^_^;)。
 スクリプト制御
 アクション型RPGのプログラムは多くの複雑な動作を要求されます。その全てをメインプログラムに組み込むとなると、プログラマの負担が大変大きくなってしまいます。デバッグも大変ですし、二人以上で作業を分担するときも問題が発生しやすくなります。
テキストアニメーション合成例
 アマランスIIでも前作同様、テキスト画面を利用したアニメーション合成が随所で使われています。この朝日街道(ちょうじつかいどう)での激しい雨のフィールドシーンもその中のひとつ。他にも吹雪や砂嵐などがあります。
 そこで考えられたのがスクリプトによる制御・実行です。スクリプトは「台本」とか「手書き」といった意味の言葉ですが、メインのプログラマはこの「台本」通りに振る舞う「役者」のみをプログラムするのです。台本の方は文法と決まりさえ憶えれば誰が書いてもよいわけですから、作業の分散が効率よく行えるようになります。また、デバッグも非常に簡単になります。テスト用の役者プログラムさえ用意すれば、台本を書いている各自が自由に簡単に動作チェックできます。これはアマランスIIに始まったことではななく、リボルティーIIの頃から使用されているテクニックです。
 アマランスIIでは、イベントの実行アニメーション(ビジュアル)シーンの実行キャラクタの動きがスクリプトによって実現されています。下の2本のリストは実際のイベント・スクリプトです。Sample1は気候神ラウネンを騙った中ボスのキジャキとの戦闘に勝利した際に発動されるイベントを記述したもの、Sample2はゲハイムヴェーク(地下通路)で中ボスの光のラオトスの待ち伏せに突入するイベントを記述したもので、両方とも実際の製品に使用されたものです。
 Sample1
001 ;========================================
002 ;   偽ラウネン(キジャキ)断末魔
003 ;========================================
004 EVSTART  EV130 ; EV130開始ラベル
005 NOFIGHT ; 戦闘モードから抜ける
006 DELAY 500 ; 5秒待ち
007 SE 18, 0, 1 ; 効果音18を鳴らす
008 BGMCHANGE 21 ; BGMを21に変更
009 REMAKE 4, 0 ; 奥の間への通路出現
010 SPEAK 338 ; 【おや?………これは………】
011 MESSAGE 9, 16, 22 ; 「クロームの鍵を手にいれた」
012 ITEMGET ITEM, 21 + 10 ; 『クロームの鍵』入手
013 SPEAK 339 ; 【クリーデン、これが何か………】
014 SPEAK 340 ; 【いや、はじめて見る………】
015 FIN ; イベント終了
016 EVEND  EV130 ; EV130終了ラベル
 Sample2
001 ;========================================
002 ;   ラオトス出現
003 ;========================================
004 EVSTART  EV230
005 LDB@ SYSC ; システムカウンタをバイト変数にロード
006 IFB@NEI 52, #END ; バイト変数が52以外なら#ENDへ飛ぶ
007 EQUIPCHK ITEM, 0 ; アイテムNo.0(D−リヒト)の装備有無をバイト
008 IFB@NEI -1, #PASS ; 変数に入れ、無しなら#PASSへ飛ぶ
009 ON 101 ; F101 =「Dリヒト非装備フラグ」= ON
010 SPEAK 1538 ; 【行くぞ!二人とも………】
011 REMAKE 55, 11 ; <入り口閉鎖>
012 GOTO #FIG ; #FIGへ飛ぶ
013 #PASS:
014 SPEAK 1533 ; 【きゃっ!!】
015 MESSAGE 10, 16, 149 ; 「突然、ディンの服が引き裂かれた」
016 SPEAK 1534 ; 【くそっ! 見えない敵か?!】
017 MOVE 2, 2 ; パーティーを下にスクロールと共に一歩移動
018 #FIG:
019 BGMCHANGE 17 ; BGMを17に変更
020 FIGHT 15 ; <戦闘No.15発生>
021 #END: FIN ; イベント終了
022 EVEND  EV230
 簡単にリストを解説していきます。Sample1を見てください。全体を見ておわかりのように、セミコロン以降がコメントで、一行に一命令を書くようになっています。
まず、イベントのラベル(識別子)はEVSTART と EVEND で本文スクリプトを挟んで記述します。ここでは"EV230"という名前になっています。NOFIGHTは戦闘画面からマップ移動画面に切り替えるコマンドです。006〜008行は特に説明は不要でしょう。その次の REMAKEはマップの一部を「貼り替える」コマンドです。次回のツールの話にも出てくるのですが、あらかじめ切り取っておいたマップのパーツを指定したマップに重ねて貼り付けるのです。パラメータは2つの整数ですが、ひとつが対象となるマップの番号で、もうひとつが貼り込むパーツの番号です。貼り付ける座標はパーツデータに入っています。これによって、あるイベント内で遠く離れた場所のマップを事前に変更することもできるわけです。
 SPEAKコマンドは顔CG付き会話メッセージを表示します。顔CGやそれの位置、メッセージなどは別データとして定義しておき、その番号を指定するようになっています。次のMESSAGEコマンドは画面の任意の場所にメッセージを表示し、キー入力を待ちます。ITEMGETはその名の通り、指定したIDのアイテムをパーティーの所有物リストに加えます。そしてFINがイベントの実行の終了を伝えます。
オーバーラップビジュアルシーン例
 このようなオーバーラップ・ビジュアルシーンも先のイベントスクリプトによるもの。でも、オープニングやエンディング、次回予告などの全画面モードのイベントは後述のアニメーションドライバによるものです。
 Sample2はイベントの流れを制御している例です。右のコメントを見てもえらえるとだいたいわかると思います。LDB@はバイト型のローカル変数に式で示される値を代入する命令で、この例ではSYSCという名前のシステム変数の値を代入しています。SYSCはゲームのメイン進行カウンタで、ストーリーがどの辺りまで進んでいるかを表します。次のIFB@NEI命令でその値が52か否かを比較し、偽であれば#ENDへ飛びます。つまりここでは「システムカウンタが52以外であれば何もしない」となります。次のEQUIPCHKはIDが0であるアイテムを誰が装備しているかをバイト変数に入れる命令で、誰も装備していないと−1を返すようになっています。次行でそれをチェックし、誰かが装備していたら#PASSへ飛ぶようになっています。ここでイベントの内容を分岐させているわけです。誰も装備していないと次のONコマンド以降が実行され、フラグNo.101がONになり、戦闘前会話が行われ、後戻りができないようにマップの入り口がふさがり、戦闘シーンNo.15に突入します。#PASS以降では別の戦闘前会話が行われ、パーティーキャラクタがスクロールと共に一歩前に移動してから同じ戦闘シーンに入ります。ちなみにフラグNo.101は後述の戦闘スクリプトで参照されます。
 このようにアマランスII専用の立派(?)なプログラム言語になっています。このスクリプトソースを変換してオブジェクト(中間コード)とし、これをメインプログラム中のイベントドライバが実行します。ちなみにアマランスIIでは変換にマクロアセンブラ(SLR社製OPTASM)を流用しており、上のコマンドはすべてアセンブラマクロとして定義されています。エルステディア以降になると専用のコンパイラを使うようになり、Windows版アマランスともなるとC言語ライクな高度な言語体系になっています。この詳細に関してはまた別の機会にお話しすることにしましょう。
 さて、今度はキャラクタの制御に関するスクリプトです。下の2本のリストは実際のキャラクタ制御スクリプトです。Sample3は戦闘シーンのとあるザコキャラの制御スクリプト、Sample4は同じく戦闘シーンの中ボスの制御スクリプトの一部です。これらもイベントスクリプト同様、アセンブラのマクロ機能を利用して変換されてから、メインプログラムのキャラクタ制御ルーチンで解釈・実行されます。
 Sample3
001 ;========================================
002 ;    ザコ敵キャラクタ(ゴブリン)
003 ;========================================
004 SPEED = 3
005 E5 PROC NEAR
006 FCSET #S ; 初期処理
007 IDSET 2 ; 敵のIDは0-127の間。128以上は町人を表す
008 LVSET 0 ; 敵のレベル(Lv)設定
009 STSET 200 ; 体力(St)設定
010 APDPSET 33, 10 ; 攻撃力(Ap)/防御力(Dp)設定
011 SIZESET 4, 4 ; 当たり判定用のサイズ。始点は左上固定
012 FWSET 2 ; 足元の幅。当たり判定用。スライムなどはY幅と同じ値になる
013 GELTSET 8 ; 所持金設定
014 POSSET 34, 12 ; 初期発生座標
015 DIRSET 5 ; 初期進行方向設定(キャラクタのパターン決定用)
016 APS_D 0, 1, 0, 2 ; アニメーションパターンテーブル
017 APS_R 3, 4, 3, 5 ;    |
018 APS_U 6, 7, 6, 8 ;    |
019 APS_L 9, 10, 9, 11 ;    V
020 CLET V0, SPEED ; V0 = 歩行スピードカウンタ
021 CLET V3, 0 ; リアン追尾指定
022 #S:
023 DEAD #E ; 死亡判定
024 CSUB V0, 1 ; 移動速度制御
025 FLAGNJ #E ;    V
026 CLET V0, SPEED ; V0再設定
027 FDISTCHK V3, 20 ; 相対距離チェック
028 FLAGJMP #N ; 20以上ならば追尾しない
029 CLET V2, 0 ; リアン追尾
030 CHASE V2 ;    V
031 #N:
032 ADVANCE ;1歩進む
033 OBSCHK ; 進行方向の障害物チェック
034 FLAGNJ #P ;    V
035 RAND V1, 8 ; 進行方向乱数指定
036 CADD V1, 1 ;    |
037 VLET V44, V1 ;    V
038 #P:
039 ANIME ; キャラクタパターンをアニメーションTBLに従って変更
040 #E:
041 STDISP ; ;敵のスタミナ表示
042 CPUT ; キャラクタのPUT
043 CEND ; 終了
044 E5 ENDP
 Sample4
;========================================
;    中ボス(キジャキ)
;========================================
; V0 (B):動作速度制御カウンタ
; V2 (B):追尾IDカウンタ
; V3 (B):ミサイルID番号(ミサイルが参照する)
; V4 (B):追尾キャラクタID番号(ミサイルが参照する)
; V10(B):追尾キャラクタID番号
; V12(W):追尾IDのX座標
; V14(W):追尾IDのY座標
; V16(W):ミサイル発生X座標
; V18(W):ミサイル発生Y座標
; V20(B):ミサイルID番号
; V22(B):ミサイル進行方向フラグ
; V24(B):ミサイル進行方向フラグ(ミサイルが参照する)
; V26(W):テンポラリ
;========================================
QUIJAKI START



#LP: CMOD V2,4 ;追尾対象ラップアラウンド防止
I3JMP V2,#DINCB,#LIANN,#CRIDEN ;追尾対象に従って分岐
#LIANN: VINC V2 ;追尾対象更新
CLET V10,0
JUMP #GOGO
#DINCB: CLET V10,1 ;ディンの存在チェック
JUMP #GO
#CRIDEN: CLET V10,2 ;クリーデンの存在チェック
#GO: VINC V2 ;追尾対象更新
BANCHK V10 ;追尾対象存在チェック
FLAGNJ #LP ; 存在しない
#GOGO: RAND V30,255 ;RATE/255の確率でマジックミサイル発射
CCAJMP V30,RATE,#E
CLET V20,MISSILE_BASE;  マジックミサイルのDCTを探す
#CHKLP: BANCHK V20 ;DCTがあいているか?
FLAGNJ #CHKEND ; Yes!
LOOPJMP V20,%MISSILE_BASE+MISSILENUM,#CHKLP
JUMP #E ;空きDCTがないのでマジックミサイルを発射しない
#CHKEND: XWLD V10,V12,V56 ;X座標取得
CWADD V12,2 ; 目標位置補正(キャラクタ中心を目標とする)
XWLD V10,V14,V58 ;Y座標取得
CWADD V14,2 ; 目標位置補正(キャラクタ中心を目標とする)
VWLET V16,V12 ;発生X座標設定
CWLET V18,0 ;発生Y座標設定
CCAWJMP V12,%XWID-1,#LEFT   ;左から発射
; 右半分からマジックミサイル発射
CLET V22,2 ;左下に向かって進む
VWADD V16,V14
CCBWJMP V16,%XWID*2,#SPAWN
VWLET V18,V16
CWSUB V18,%XWID*2-1
CWLET V16,%XWID*2-1
JUMP #SPAWN
; 左半分からマジックミサイル発射
#LEFT: CLET V22,1 ;右下に向かって進む



#E: STDISP ;残り体力(ST)表示
#EE: CPUT ;キャラクタのPUT
CEND ;終了
#EV: CPUT ;キャラクタのPUT
SE 15 ;中ボス死亡効果音発声
EVBORN 130 ;キジャキ断末魔イベント発生
GOTO #E
QUIJAKI ENDP
 では、Sample3をごく簡単に説明していきましょう。まず、最初からラベル"#S:"までの間は全て初期設定です。行ごとのコメントを見てもらえれば、おおよその見当はつくと思います。6行目のFCSETという命令は、2回以上実行されたときに、パラメータのラベルに飛ぶという動作をします。これによって作業域の初期化などの処理を1回だけ実行するようにしています。パラメータ部に出てくるV0〜44という名前は、各キャラクタごとに使用できる変数を示しています。これらの変数は基本的に1バイトサイズですが、偶数値のものは1ワード(2バイト)サイズとしても使用できるようになっています。若い番号のものは意味が決まっていますが、そうでないものは自由に使用することができます。
 このリストで制御される敵キャラクタは、プレイヤーキャラであるリアンが自分を中心に距離20以内にいると追いかけてくるという単純な動作をします(距離1は8×8ドットマス)。また、追尾中に障害物にぶつかったらランダムに進行方向を変えます。(コウモリなどの飛行キャラはこの処理が不要というわけです。)
対ザコ戦闘例
 これは船上でのザコキャラ戦から撤退するところ。敵キャラはもちろん、実は味方キャラも同じスクリプトで制御されています。さらにはプレイヤーキャラも同じくスクリプト制御です。キー入力を変数に代入するコマンドを使います。
  Sample4は非常に長いリストの一部を切り出したものです。複雑な攻撃を繰り出すボスキャラも、ザコキャラと同じスクリプトで制御します。パーティーのメンバーを識別したり、投擲攻撃をしたりしています。ちなみに、火の玉を投げたりビームを発射したりする攻撃はBORNという命令を使って、火の玉キャラやビームキャラを新しく発生させることで実現します。コメントに出てくる"DCT"とは、V0〜44までの変数を含む、キャラクタごとの設定/作業域を示すポインタテーブルを指します。当然ですが、仮にDCTが20あれば、同時に最大で20キャラクタ表示できることになります。そのためDCTに空きがあるか調べて、なければ新規発生処理を断念するようプログラムされています。
 最後から3行目にEVBORNという命令があります。これは指定されたイベントを戦闘中に発生させる命令です。ここでは130番目のイベントを起動していますが、これは先のSample1のスクリプトで記述されたものです。
 最後にアニメーション(ビジュアル)制御用スクリプトについても紹介しておきましょう。実はこのアニメーション制御スクリプトが最も歴史が古く、汎用性も高いものなのです。イベントやキャラクタ制御とは異なり、製品ごとに専用のものを作る必要がないからです。実際、このアニメーション実行に関しては、ソーススクリプトをコンパイルして出力されたオブジェクトを独立した専用の実行プログラム(AD.EXE)が読み込んで実行します。ビートバイスやアマランス1〜4などの店頭デモなどはすべてこのシステムで動いています。このアニメーション記述言語はFGAL(エフギャル)"Fuga General Animation Language"と呼ばれており、実行プログラムは「アニメーションドライバ」といいます。
 では実際にFGALスクリプトがどのようなものかをお見せいたしましょう。下のリストSample5を見てください。これはアマランスのオープニングアニメーションを記述したスクリプトの一部です。アマランスIIのものがすぐに見つからなかったので前作のものを持ってきました。
 Sample5
001 ;========================================
002 ;   Amaranth OPENING
003 ;========================================
004 ; 初期設定
005 GRAPHOFF
006 TEXTOFF
007 SGCLR 0, 128
008 APALET[0,0,0,0]
009 FADEOUT8 0
010 SCROLL 0
011 RESO 1
012 BANK 0,0
013 WIPE 0,0
014 ; 使用変数
015 DEFINE CPU
005 DEFINE A,D,F,G,N,T,W,X,Y,C1,C2,C3,C4,C5
006 ; CPU チェック
007 CPU = _506
008 ; ここから開始
009 BANK 0,1
010 IF [_510 = 1] #HDLOAD00
011 EXPAND B:FT.CG 0 0
012 JUMP #CONT00
013 #HDLOAD00
014 EXPAND FT.CG 0 0
015 ; JINGLE
016 #CONT00
017 IF [_510 = 1] #HDLOAD0M
018 MLOAD B:FGTTL.MD
019 JUMP #CONT0M
020 #HDLOAD0M
021 MLOAD FGTTL.MD
022 #CONT0M
023 MUSIC 0,0
024 APALET [0,0,0,0][1,8,12,15]
025 GET [0,0][80,80],C1,1
026 BANK 0,0
027 GRAPHON
028 PUT [0,60],C1,1,$301,7
029 FREE C1
030 _509 = 0
031 #MUSWAIT0
032 WAIT 0
033 IF [_509 = 1] #SKIPDA
034 IF [_508 <> 0] #MUSWAIT0
035 FADEOUT8 8
036 JUMP #START



145 ; 2秒で横線が上から下へ走る
146 SWAIT 200
147 APALET [1,0,12,7]
148 N = 0
149 LOOP 200
150 SWAIT 1
151 BOXF[0,N][639,N],1,0,0,0
152 BOXF[0,N-2][639,N-2],1,2,0,0
153 N = N+2
154 EWAIT 1
155 ENDLOOP
156 BOXF[0,N-2][639,N-2],1,2,0,0
157 EWAIT 200
158 ; 文字列,実際にスクロールインしてくる (表示含めて21秒)
159 SWAIT 2100
160 N = 49536
161 SCROLL N
162 Y = 0
163 IF [CPU = 1] #V30SCUP
164 LOOP 400
165 SWAIT 4
166 BANK 0,1
167 GET[0,Y][80,1],C1,7
168 BANK 0,0
169 PUT[0,Y],C1,7,0,0
170 FREE C1
171 N = N+40
172 Y = Y+1
173 VSYNC
174 SCROLL N
175 EWAIT 4
176 ENDLOOP 400
177 JUMP #SCUPEND
178 #V30SCUP



1072 ; ローゼをイン
1073 BANK 1,0
1074 GRAPHON
1075 FADEIN8 10[0,0,0][15,0,0][0,15,0][10,15,11][0,0,15][15,0,15][0,15,15][15,15,15]
1076 BOXF[0,0][639,20],7,2,0,0
1077 PENV[0,0],6,4,400,80,0
1078 TEXT 不思議な男の人……まるで風の遣いのよう…
1079 PRINTS
1080 GET[0,0],[44,16],C1,6
1081 X = 2



1143 END
 ほとんどコメントが無いのでわかりにくいかもしれませんが、グラフィック関連の命令がずらりと並んでいます。基本的にはBASIC風の言語体系になっています。普段はプログラミングをしないグラフィック担当者らの腰が引けないように、直感的なプログラムができるように配慮(?)してあります。
 アニメーション制作者はグラフィックパターンを準備し、それらを表示するスクリプトを記述します。テキストファイルとしてセーブしたスクリプトを専用のコンパイラ(FGALコンパイラ)にかけます。このコンパイラは1パスで処理するようになっており、非常に高速です。これもカット&トライ(試行錯誤)をしやすくするためです。あとはコンパイラの吐いたオブジェクトファイル名を引数に指定してアニメーションドライバを起動すれば、スクリプトに従ったアニメーションが画面に表示されます。
オープニングより
 こちらはアマランスIIのオープニングの1シーン。文字がくるくるとアニメーションしながら表示されたりする部分もすべてアニメーション記述言語“FGAL”で記述されています。
 では特徴的な部分を解説していきます。まず変数ですが、自由な名前を付けることができ、事前にDEFINE文で定義しておく必要があります。"_"(アンダスコア)に続いて3桁の数字が続いている名前を持つ変数はシステム変数です。また、配列は1次元1系統のみ使用でき、"@[式]"で記述されます。条件分岐は"IF"文により、"IF[条件式] #ラベル"という構文になります。リスト中のEXPAND文は、独自に可逆圧縮されたCGデータを展開表示するコマンドで非常に高速かつ省メモリです。
 また、いろいろな性能のCPUに対応するため、SWAIT〜EWAIT文が用意されているのが大きな特徴です。これは「間に挟まれた処理を指定した時間をかけて実行する」というものです。低速なマシンに合わせて時間を設定すれば、どんな高速マシンでもタイミングが狂うことがありません。また、入れ子も8段まで可能です。他にもBGMとの同期をとるコマンドや各種セミグラフィックのコマンドなど、上のリストでは使われていない様々な便利な機能が用意されています。
 このように文法の異なる(というかその用途に合わせた)スクリプト言語をいくつも創造し、より効率の良い開発ができるように日々頭を捻っていました。
 MIDIインタフェース対応
 アマランスIIから「標準化」したのがBGM演奏のためのMIDIインタフェース対応です。Roland社製のMPU-PC98/401インタフェース、およびその互換ボードへの対応がなされています。後にRS-232Cコネクタに接続するタイプのMIDIインタフェースも出回りましたが、それには対応していません。理由はいろいろありますが、とにかく風雅システムでは最後(Windowsに移行する)まで対応しませんでした。ちなみに某社の互換MIDIインタフェース「サウンド○レット」は、インテリジェントボードでありながら発声量が多くなるとテンポを維持できませんでした。つまり、それほどにアマランスIIのBGMのデータはもの凄かったわけです。RSインタフェース非対応の理由の一端です。
 風雅システムのMIDIドライバは、もちろん自社開発のオリジナルです。アセンブラのみで組んであるので、常駐サイズ(メモリ占有量)も小さく、処理も軽快です。演奏データ形式は暗号化されたオリジナルのものですが、専用のコンバータにかけることで、一般的なフォーマットのデータであれば変換してそのまま演奏させることができました。お察しの通り、その演奏データも独自の方法で圧縮されていて、「メインメモリにやさしい」ものです。
 最初からゲームのBGM演奏用に開発したので、演奏機能的にも特化されたものがいくつもあります。フェードイン・フェードアウトはもとより、テンポやキーの途中変更、インタフェースの使用割り込み番号の設定、EMS対応など様々です。
 中でもちょっと面白いのが「効果音の発声」機能です。LA音源モジュールやGS音源モジュールがターゲットでしたから、使用できる音色の中にピストルの発射音やヘリコプターの音、爆発音など、上質の効果音があります。そこでゲームからそれらがいつでも使えるようにしてあるのです。通常はFM音源で効果音を鳴らしますが、ここぞというときには音源モジュールからリアルな効果音が出るというわけです。が、実際にやってみるとそれまで鳴っていたFM音源の効果音との差がありすぎて、完全に音が浮いてしまいました。そのようなわけで、残念ながらこの機能は製品では使用されていません。
 それともうひとつ。「音痴演奏」機能。「指定した頻度で音程をはずしてくれる」というありがたい(?)機能です。ズッコケイベントなどで使おうと思って作った機能だったのですが、思った以上に間抜けで身体の力が抜けてしまうという現象が発生し、これも製品では使用していません。
 アマランスIIでは当初Roland社製のMT-32系LA音源のみの対応でしたが、後にパワーアップキットでGS音源にも対応しました。当時、数万円もする高価な音源モジュールだったにもかかわらず、「アマランスIIのために買った!」というユーザが続出しました。開発陣は嬉しい反面、申し訳ないような複雑な心境だったものです。が、「投資の甲斐があった」というご意見がほとんどで、小さくガッツポーズをしたものです。

特別講義メニューページへ
ディン:「こんな仕組みだったんだ・・・・・」