yaneuraoGameScript2000で行こう!

初心者歓迎!プロのゲームプログラマーによる、×××ツクールでは物足りない人のためのゲーム制作入門

written by やねうらお


1.ノベルゲームの時間【後編】です

今回は、ノベルゲーム(アドベンチャーゲーム)の制作についての【後編】です。単純なようで、結構、奥が深いので、前編後編と2回に分けました。今回は後編ということで書いていきたいと思います。【前編】の内容で、すでに簡単なノベルは作っていただけるようになっているはずですが、【前編】に書ききれなかったことを、今回書いていきたいと思います。

前回までの内容は、私のホームページで参照できますので、今回から参加って人も読んでみてください。すぐに追いつけますから!


2.いまどきのゲーム業界事情ノベルゲームは必須要件..?

そう言えば、残念ながら、前回は、この連載のほうをお休みさせていただいておりました。

それと言うのも、SAGA PLANETSの『恋愛CHU!』のファンディスク、Paradeの『振り向いてCool Eye's』そして、Waffleの『麻雀遊戯』のプログラムのほうが修羅場っていたからです(笑) 麻雀で言えば、自分以外の3人がリーチ!をしていて、お、おれ、どうしたらええのんやー!というような状態でした(笑)

しかし、おそらく、これを読んでおられる方のほとんどの方はゲーム業界を未経験の方だとは思うので、あまりピンと来ないでしょう。一応、もう少し詳しくご説明致しますと、ゲームは発売日の前に、CDをプレスするためのプレス工場に、完成版をCD−Rで送らなければならないのです。たいていは、発売日の2〜3週間前です。これをマスターアップと言います。

それで、開発スタッフは、もうマスターアップ前になると、毎日が盆と正月、、もとい、台風と地震が来たかのような騒ぎでして、もちろん3日間、ずっと徹夜なんかあたりまえなのです。

そんなとき、私も、とりあえず眠気を覚ますために、コーヒーでもと思い、近くのコンビニに行ったりするのですが、その日には、どこから見ても中学生やろ?っていう風貌の私服の女の子の5人連れが、何やらたむろして、商品をいじくりまわしているではないですか。迷惑なやっちゃなー、ちょっと注意したろか、、と思って、しばらく見ていると、ひとりは店の奥とか勝手に入って行きやがるのです。そっちはトイレちゃうっちゅーに!さらにしばらく見ていると、その5人連れは、そそくさと帰って行きました..かのように見えたんですが、帰りぎわ、レジに居た二人の店員いわく「お疲れさまです!!」..ん!?なになに?この5人連れって、商品の搬入業者だったの??コンビニの搬入業者は、女子中学生なのかえ?? それとも、土日だけ学校休みだから、手伝っているんかえ?? そう思っていると、その5人連れは表に停めてあったトラックに乗ってどこかへ行ってしまいました。ちゅーか、お前らトラック運転できるんかよ!!などと、まったく、驚きの連続であったのですが、とりあえず、こいつらの名前は、搬入戦隊女子中ファイブと名づけました。異論のある奴は、一歩前に出て、歯を食いしばれ!ヽ(`´)ノ

...なんて馬鹿話は、どうでもいいんですが(笑) この『麻雀遊戯』、名前からもわかるように麻雀なのです。ひと昔前、麻雀と言えば、ユーザーが勝つと女の子が、「イヤーン、エッチー」とか言いながら(そんなことは言わない?)脱衣しまして、負ければゲームオーバーという、そういう典型的な脱衣麻雀が麻雀ゲームの代名詞でした。ところが、いまは違います。この『麻雀遊戯』の場合、ゲームの女の子を育成させるという、育成要素、そしてシナリオを読むというノベル要素があるのです。近年、このように、麻雀ゲームにさえ、シナリオ画面は欠かせないものとなってきています。(アダルトゲームでは特に)

そういう、状況を踏まえると、アクションゲームよりは、ノベルをまず作ってみたいっていう人のほうが圧倒的に多いというのは、十分にうなずけます。

そんなわけで、前回は、ノベルを作るための足がかりについて、ご説明しました。今回は、そのノベルを、より完成された形にするための、いろいろな技法についてご説明いたします。


3.ノベルゲームの用語について

さて、ここで、いくつかノベルゲームで使う用語についてご説明しておきます。実際のところ、メーカーごとに違う呼び名で呼んでいたりするのが実状なのですが、ある程度、通用するであろう用語を中心にご説明します。

☆ 立ち絵

 単刀直入に言って、こんなのです↓ (笑)

 

膝から上なら、膝上、バストから上ならば、バストアップというように呼ばれます。この上の例では、膝上。素材としては、膝上で描いておいて、実際のゲーム画面では、バストアップしか使わないこともあります。非常にもったいないですね(笑) 私の関わった作品では、WAFFLEの『HAPPYほたる荘』のときがそうでした^^;; 細かな画面レイアウトまで詰めずに立ち絵作業を先行してやっていたりすると、どうしてもそういう無駄が出たりします。ある程度は仕方ないことなのですが..

☆ BG

 背景CGのこと。たとえば、こんな感じです。↓

 なるほど、背景って感じですね(笑)

☆ 台詞ウィンドゥ

 シナリオ(主人公の台詞等)が表示される窓のこと。
 たいていの場合、BG+立ち絵+台詞ウィンドゥ = 会話画面ということになります。

 BGが見えにくくなるので、台詞ウィンドゥは通例、半透明で表現したりします。
 「BG+立ち絵+台詞ウィンドゥ」を組み合わせると、こんな画面になります。

この絵は、来年の春に発売予定の、自社シューティングの開発中のものです。
(と、どさくさに紛れて宣伝(笑))
えっ?前回、今年の年末って言ってたじゃないかって・・?
そんなところは、あえて突っ込まないでください(笑)

 立ち絵は、通例、表情変えをします。これは、喜怒哀楽+αのパターンを用意して、状況に応じて、それを表示することです。口パクと言って、台詞に合わせて口だけパクパクさせたり、目パチと言って、一定間隔ごとに、パチパチとまばたきをさせたり、目をうるうるさせたりすることもあります。

 また、BGが変わったとしても、立ち絵自体はゲーム全体で共通して使います。(使いまわします) だもんで、一度、作ってしまえば、結構、融通が利くのが立ち絵の良いところです。だもんで、最近のノベルタイプのゲームでは、立ち絵を用意してあるものが多いです。

☆ イベントCG

 イベントCGとは、このようなものです。

 見ての通り、この場合、立ち絵(ゲーム全体を通じて共通の立ち絵)を使っているわけではありません。
 しかし、このようなイベントCGを、立ち絵を表示しないBGと考え、プログラマ的な観点から便宜上、BGとして扱うことがよくあります。

☆ SE

 効果音。ドアを叩く音だとか、ガラスが割れる音だとか、一般的に、短い再生時間のものを指します。

☆ BGM

 音楽。曲。通例、ループサウンドで、最後まで行った場合、また先頭に戻って再生します。

☆ ウィンドゥ消去ボタン

 台詞ウィンドゥが邪魔で、女の子の綺麗なおっぱいが見れないと、きっとみなさんは怒るでしょう(笑) 釈迦の生まれ代わりかと言われている私でさえも怒ります(誰も言ってません) そんなときのために、ウィンドゥを一時的に消すボタン、それがウィンドゥ消去ボタンで、マウスの右クリックで消えるゲームもありますし、それ専用のボタンがついている場合もあります。また、ウィンドゥを移動させる機能のついているゲームもありますし、ウィンドゥが半透明になっていて、邪魔に感じないように工夫してあるゲームもあります。その半透明度や色合いを調整できるゲームもあります。このへん、どうやれば見ていて不快に感じないか、いろいろ工夫がしてあるのです。

☆ バックログ

 ログというのは、記録のことを意味します。ノベルにおいて、バックログというのは、少し前に表示していたシナリオを遡って表示するような機能を言います。最近のノベルには欠かせないものとなっています。バックログボタンを押すごとに、ひとつずつ戻るタイプのものが典型的ですが、スライドバーになっていて、それで前後に動かせるものもあります。

☆ 途中ロード/セーブ

 シナリオ画面でも、ユーザーは、ゲームを中止して、またあとで再開したいと思うかも知れません。そういった場合、あとでそこから再開するための仕組みが必要になります。そういうのをプレイデータの途中セーブ(保存)/途中ロード(読み込み)と言います。

☆ シナリオスクリプト

シナリオは、普通、独自のテキストファイルです。シナリオの途中で、「ここで音楽を鳴らしなさい」だとか、「ここで、何番のBGを表示しなさい」だとか、そういった命令が書かれています。各ゲームメーカーごとに、独自のシナリオスクリプトを用いています。ものによっては、ある程度のキャラクターの動きまでシナリオスクリプトで表現できる(書くことが出来る)こともあります。

 小さなゲームメーカーにおいて、シナリオライターは、自分の会社で使っているシナリオスクリプトを自由に扱える、使いこなせることが必須になってくることは言うまでもありません。しかし、そうは言っても、実際にその会社で働いてみるまで、どんなシナリオスクリプトを使っているのか、わかりません。今回、この講座を通じて、シナリオスクリプトを読み込んで、表示する部分を実際に一度、作ってみれば、どこのゲームメーカーに行っても、シナリオスクリプトについては、十分理解できるはずです。逆に、プログラマに「こういう機能つけてくれないと僕、自分でプログラム書いちゃうよ」とか言って、煙たがられたとしても責任は負いませんが(笑)


4.今回もインポートライブラリを使います

 さて、今回使用するゲームスクリプト(yaneuraoGameScript2000以下、ygs2k)の最新版(1.64c)は、これです。(右クリックして対象をファイルへ保存してください) あと、今回必要になるインポートライブラリの最新版(1.04)は、これです。インポートライブラリってのは、前回も出てきたので、もう使いかたはバッチリですよね??(笑)

 念のため、再度説明しておきます。このインポートライブラリはygs2k本体だけでは足りない部分の拡張を行なうためのものです。このインポートライブラリのlibフォルダを、YGS2000.exeのあるフォルダにコピー(移動)させてやれば、このインポートライブラリが使えるようになります。(以下図)

今回も、このインポートライブラリが大活躍するので、インポートライブラリのマニュアルやサンプルプログラムとかも参考にしてくださいね。


5.シナリオスクリプトを読み込んで表示する部分を関数化する

前回の最後、一応、簡単なファイル(シナリオスクリプト)から、テキストを読み込み、それを表示するところまでは完成していました。今回は、それを拡張していきます。前回のプログラムは、こんな感じでした。

import "lib/string"
import "lib/file"
import "lib/patmatch"

void main(){
    int nLen;                   //  文字列の長さ
    int n;                      //  現在表示している文字数
    int hHandle;                //  ファイルハンドル
    hHandle = OpenFile("script/scn.txt","r");

    TextLayerOn(0,30,400);
    TextSize(0,24);
    TextColor(0,255,128,128);
    CreateSurface(0,640,480);
    loop {
        if (ReadLine(hHandle,string[1])!=0) break;
        //  BG指定か?
        if (IsPatMatch(string[1],"#bg%*\"%s\"",string[2])) {
            LoadBitmap(string[2],0,0);
            goto LoopEnd;
        }
        //  WAV再生指定か?
        if (IsPatMatch(string[1],"#wav%*\"%s\"",string[2])) {
            LoadWave(string[2],0);
            PlayWave(0);
            goto LoopEnd;
        }
        nLen = StrLen(string[1]);           //  szの文字数を返す。
        for(n = 0; n <= nLen ; n++){
            BltFast(0,0,0);     //  画面のクリアの代わり
            LeftStr(string[1],n-IsKanji(string[1],n-1),string[0]);
            TextOut(0,string[0]);
            halt;
        }
        //  キー入力を待つ
        loop {
            BltFast(0,0,0);     //  画面のクリアの代わり
            halt;
            KeyInput();
            if (IsPushSpaceKey()) break;
        }
    LoopEnd:;
    }
    CloseFile(hHandle);
}

本来、main関数に何もかも詰め込んであるというのは、あまり体裁の良いものではありません。シナリオを表示する部分をまるごと関数化できないでしょうか?たとえば、次のような感じで呼び出せると理想的です。

void main(){
    DrawScenario("script/scn.txt");
}

シナリオとして、scriptフォルダに入っている、scn.txtというシナリオスクリプトに基づいてシナリオを表示しなさい、とこのようにmain関数で書けると、main関数はずっとすっきりします。このDrawScenario関数は、引数としてファイル名をもらい、OpenFileでは、そのファイル名のものをオープンすれば良いので、以下のように書けば良いのです。

void DrawScenario(str szFileName){
   int nLen;    // 文字列の長さ
   int n;      // 現在表示している文字数
   int hHandle;  // ファイルハンドル
   hHandle = OpenFile(szFileName,"r");

           《以下略》

ここ以降は、さきほどのmain関数とまったく同じなので、割愛します。さきほどのmain関数と見比べてみてください。


5.台詞ウィンドゥの表示

次に、台詞ウィンドゥを表示します。これは、半透明の表現を使いたいですね。半透明を使うには、

BlendBltというのを使うと良いです。ところが、これ遅いんです。試しに、半透明で、表示してみましょう。

DrawScenarioのOpenFileしている直後にでも、

SystemMemoryPlane(2,1);
LoadBitmap("script/serifu.bmp",2,0);
EnableBlendColorKey(2,1);

というように追加します。SystemMemoryPlaneというのは、初めて出てきましたが、半透明転送を高速化するためのおまじないと思ってください。(詳しくは、マニュアルに書いてあります) EnableBlendColorKeyというのは、ブレンド転送(半透明の表現のこと)するときに、ヌキ色を有効にするためのものです。まあ、このへんもマニュアルに書いてありますし、この命令を入れないと、実際にどう表示されるのか、試してみるとわかりやすいと思います。そして、描画ループ、すなわち、描画しているところ、具体的には、haltの前で、

BlendBlt(2,0,370,50,50,50,256-50,256-50,256-50);

とやれば、さきほどの画面にあったような半透明ウィンドゥが表示されるというわけです。

しかし、これが遅いのだとしたら、どうすれば良いのでしょうか?ひとつの方法として、ブレンド転送を使わないことです。

ブレンド転送を使わないと、BGが見えなくなってしまうじゃないか!とお思いかも知れませんが、そうでも無いのです。昔の偉いひとは点ヌキという方法を考えました。(いや、別にそんなに昔でも無いんですけど(笑))

こういう素材を用意するのです。なんか、網タイツみたいになってますね(笑) そうなのです!網なのです。これを拡大してみますと、

このように、メッシュ(網目状)になっているのです。そして、この白い部分を抜き色として指定して転送すれば、擬似的にですが、半透明の表現が出来るというわけです。この技法は、点の狭間から背景を抜く(見せる)ということで、「点抜き」と呼ばれます。これを使えば、半透明なんかなくっても、少し見劣りはするものの、なんとかなりそうです。

ということで、台詞ウィンドゥは、DrawScenarioのOpenFileしている直後にでも、

LoadBitmap("script/serifu.bmp",2,0);

とやって、2番のプレーンに素材を読み込み、描画のとき、すなわち、BGを表示した直後にでも、

    Blt(2,0,350);

とやって、抜き色を有効にして描画しておけば、OKということです。

すでにお気づきかと思いますが、最初に描画したものは、画面上では、重なったときに後方(背面)に表示されます。つまり、BGの前面に台詞ウィンドゥ、台詞ウィンドゥの前面に台詞というように描画しないといけないので、プログラムとしては、

1.BGの描画
2.台詞ウィンドゥの描画
3.台詞の描画

という順序で描画しなくてはなりません。

また、このプログラムでは、台詞を一文字ずつ描画する部分と、台詞の一文字ずつの表示が終わって、ユーザーからのキー入力を待っている状態と、2つあって、それぞれ別々の描画ループになっています。そのこと自体は、別に構わないのですが、そうなると、上のように台詞ウィンドゥを追加しようと思ったりするごとに、2箇所に同じプログラムを追加していかなくてはなりません。これは、規模が大きくなってくると、保守するのが大変になってくるので、なるべく一箇所にまとめたいわけです。そこで、シナリオ画面の構築するための関数を別に用意してやろう、という気になってきます。これは、あとでご説明します。


6.画面のトランジション

前回の最後のスクリプトには、もう一つ、大きな(?)不満があったと思います。それは、次のシーン(BG)にパッと切り替わってしまうことです。このとき、何らかの画面効果を与えることはできないのでしょうか?

出来ます。以前、トランジションという方法を解説しました。これを利用してみることにします。

仕様としては、シナリオスクリプトのほうで、

#bgtrans "script/218.jpg" 15

と書いておけば、トランジションの15番のエフェクトを伴いながら、このBG(scriptフォルダに在る218.jpg)に変化する、というものにしましょう。

まず、プログラムの先頭で

import "lib/trans"

とやって、トランジション機能を使えるようにします。これは、インポートライブラリに含まれているものですので、今回の最初のところで説明したように、インポートライブラリを解凍して、libフォルダに入れておく必要があります。

次に、トランジション用の変数を用意しましょう。これは、DrawScenario関数のなかで用意しておけば良いと思います。

// トランジション用
int nTransType; // BGのトランジション効果ナンバー
int nTransPhase; // BGのトランジションのPhaseカウンタ
nTransPhase = 0;

ひとつ目のnTransTypeは、トランジションの効果ナンバーを保存しておくもので、上の例のように、

#bgtrans "script/218.jpg" 15

とやれば、この変数に15が入っているものとします。

ふたつ目のnTransPhaseには、トランジションがどの段階にあるのかを保存するためのものです。

トランジションの概念は、以前にも説明しましたが、簡単におさらいしておきますと、0に始まって、256になった段階で、トランジションは終了、というように、段階的な描画を行なうためのものです。そこで、今回のプログラムでは、この段階(フェーズ)が0ならば、トランジション中では無い、というように考え、0以外であれば、トランジション中なので、このフェーズカウンタを少しずつ加算していき、256を越えた場合、トランジションは終了した、だから、フェーズは0に戻す、という処理にします。

これを、そのままプログラムにしてみますと、次のようになります。

  BltFast(0,0,0);
  if (nTransPhase!=0) {
  // トランジション中なのか?
    BltTrans(1,0,0,nTransType,nTransPhase);
    // トランジションのPhaseカウンタの加算
    nTransPhase = nTransPhase+8;
    if (nTransPhase>=256) {
      // トランジションは終了
      nTransPhase = 0;
    }
  }

このプログラムでは、トランジション中は、前のBGは、0番のプレーンに、トランジション中のBG(次のBG)は、1番のプレーンに入っているものと考えています。

ひとつ忘れているのは、トランジションが終わったときに、1番のプレーンの内容を0番のプレーンにコピーしてやらないといけないということです。このプログラム、よく見ればわかると思いますが、トランジションのフェーズが256に達したとき、0にまた戻ります。そうすると、0番のプレーンしか描画されないのです。この0番のプレーンは、そのとき、次のBG(プレーン1の内容)になっていなければなりません。そこで、この最後のところで、1番のプレーンの内容を0番のプレーンにコピーしてやりたいのです。

ところが、YGS2Kのマニュアルをひっくり返して、お尻ぺんぺんしても(笑)、そのような命令はどこにも用意されていません。どうすれば良いのでしょうか?通常、BltFastで描画している先は、セカンダリプレーンですよね。これを変更してやれば良いのです。

つまり、こうやれば出来ます。

    if (nTransPhase>=256) {
      // トランジションは終了
      nTransPhase = 0;
      // 1番のプレーンの内容を0番のプレーンに転送する
      SwapToSecondary(0);
      BltFast(1,0,0);
      SwapToSecondary(0);
    }

少しトリッキーな感じがしますが、SwapToSecondaryというのは、セカンダリプレーンと一時的に入れ替えてしまう命令です。よって、一回目のSwapToSecondary(0);によって0番のプレーンとセカンダリプレーンとは入れ替わってしまいます。よって、この直後にあるBltFastは、(実際は0番のプレーンなのに)セカンダリプレーンと間違えて、そこに描画してしまう、ということです。これによって、1番のプレーンから0番のプレーンに画像を転送することに成功します。そのあと、SwapToSecondaryを再度実行して、こっそり元通りに戻すわけです。これが、YGS2Kにおける、プレーン間の転送テクニックです。

あとは、シナリオスクリプトを解析する部分を追加しましょう。すなちわ、DrawScenario関数のなかの、ReadLineしている次の行にでも、

                //      BG トランジション型の命令か?
                if (IsPatMatch(string[1],"#bgtrans%*\"%s\"%d",string[2],&nTransType)) {
                        LoadBitmap(string[2],1,0);      //      トランジションは1のプレーンに読み込む
                        if (nTransPhase!=0) {
                        //      現在のトランジションが終わっていないので、トランジション中の
                        //      プレーン(1)を、BGプレーン(0)とする
                                SwapToSecondary(0);
                                BltFast(1,0,0);
                                SwapToSecondary(0);
                        }
                        nTransPhase = 8;        //      トランジション開始
                        goto LoopEnd;
                }

と追加すれば、OKです。この手のパターンマッチを行なうときの基本ですが、長い文字列から順番に判定処理をします。なぜかというと、

  #bg
  #bgtrans

という二つの命令を判定する処理を書くとして、先に、#bgであるか?という判定処理を書くと、#bgtransと書いてある場合も、下手すると、そこに引っかかって(一致して)しまいかねないからです。(上のプログラムは、ファイル名のあとにトランジョンの種類を示すパラメータが含まれていないとIsPatMatchでマッチしませんから、大丈夫ですが)

このように、長い文字列から順番に判定処理を行なう方法を、最長一致法と呼びます。実際は、

  #bg
  #bgtrans
  #wav

と3つの判定を行なうような場合は、#bgtrans ⇒ #bg ⇒ #wav の順番に判定処理を行なっも、#bgtrans ⇒ #wav ⇒ #bgの順番に判定処理を行なっても構いません。(#bgtransが#bgより先行して判定処理が行なわれることが重要なのです)


7.そこで、サンプル

ということで、前回のプログラムに、今回の拡張をほどこしたものと、素材一式をまとめました。 これを解凍後、scriptフォルダにコピーしてやれば、良いです。またインポートライブラリを使える状態にしておくのを忘れないでください。YGS2Kを実行すると、こんな画面になるはずです。(スペースキーでメッセージを読み進めます)

一応、少しサンプルのほう、見ておきましょう。シナリオ画面を描画する部分は、OnDrawScenarioScreenという一つの関数にまとめられています。この関数は、トランジションのフェーズを示すnTransPhaseを引数として得るわけですが、この関数のなかで、この変数を加算する必要があるため、ポインタ渡しとなっています。これは、4回前の原稿でちらっと書いたのですが、私も書いたことすら忘れていました(笑) 私が忘れているぐらいなのて読者のみなさんは当然忘れていると思うので、その部分を再掲します。(誰ですか、原稿の水増しか!って言ってるのは..(笑))

先のプログラムと何がどう変わっているか見比べてください。関数の呼び出し側に、&があること、関数の定義部分で intのあと、* (アスタリスク)があること、そして、実際に変数を使うときには、変数の前に * があることの3点ですね。これは、ポインタというもので、C言語の入門書なんか見れば載っているので興味のある方は、そちらを見ていただくことにして、ともかく、こうすれば、関数内から、呼び出し側の変数の値をいじくれると、そういうわけです。これによって、グローバル変数にアクセスすることなく、関数を書くことが出来たので、めでたく関数の独立に成功したと言えます。だから、そうですね。今日を、関数の独立記念日と定めましょう。(嘘です)

とのことです。


8.まとめ

2回に分けて、ノベルを作るための方法、用語、技術について解説してきました。

もうすでに、みなさんは、実際に、簡単なノベルはすでに作れるようになっているはずです。ここにあるサンプルをそのままコピーして使っても構いません。男っ前なやねうらお(ただし、そう思っているのは本人のみ)は、商用利用した場合、お金を寄越しなさいだとか、「やねうらお氏のゲームスクリプトを使ってます」と見えるところに書けだとか、そういうケチなことは一切言いません。こんなものでよければ、勝手にコピーして、使いたいだけ使えばいいのです。

しかし、決して、このサンプルのもので満足しないでいただきたいのです。まだまだやり残したことはたくさんあります。あえて完全なものにせずに、読者のみなさんに作る喜びのようなものを残した、、というと聞こえが良いかも知れませんが、実のところ、忙しくて作りきれなかったというのが本音です(笑) ですから、足りない部分を、是非、読者のみなさんの手で埋め合わせて、完成に持っていっていただきたいのです。

特に、立ち絵の表示方法については、説明しませんでした。これは、BGと処理内容が同じですので、不要だと思ったからです。興味のある方は、立ち絵の表示にも挑戦してみてください。余力のある方は、BGのときのように、トランジションにも対応させてみてください。

あと、マウスのボタンでメッセージを読み進める機能や、右クリックを押したとき台詞ウィンドゥを一時的に消す機能もあれば良いですね。これは簡単ですので、追加してみてください。(後者はOnDrawScenarioScreen関数のなかに追加すると簡単です)

それから、始めに解説したバックログもあると良いでしょう。これは、一度読んだ部分を、配列に保存していく処理が必要になります。前回に説明した文字列処理の部分を読み返しながらやると良いと思います。

あとは、みなさんで、できれば、実際にシナリオを書き、グラフィックを描き、音楽も入れて、本格的なノベルにするのも良いかも知れません。そこまでやると、現状のYGS2Kでは足りない機能も出てくるかも知れません。そのときには、お気軽に、やねうらおまでご相談いただけたら、と思います。

私も、現状のYGS2Kでは、いろいろ足りない部分があるのも痛感しています。なんとか、大幅なバージョンアップをしよう(というかゲームスクリプト第二弾を作ろう)と、構想を練っています。まあ、自分以外の3人がリーチしているような状況(笑)が続いているので、なかなか、それも難しいのですが...。期待してくださっている方々のためにも、なんとか近いうちに、形にしたいと思っています。(もちろん、YGS2Kと同じく、完全にフリー、ロイヤリティもフリー、いくら使ってもタダ!という形で公開する予定です)

※ 書き忘れていたのですが、YGS2KでJPEGの読み込み機能は、Win95だと、IE等を入れないと使えないようです。あと、前回のバージョンで、一部の機種でJPEG画像が正しいサイズで表示されないことがあったようなので、その部分は、今回のバージョンで修正してあります。