見出し画像

ティラノスクリプト製ゲーム「マダム・ポプスキンの憂鬱」の技術的な話【調査手帳(html・css・js)】

今回は弊作「マダム・ポプスキンの憂鬱」の「調査手帳」で使っているhtml、css、jsについて説明します。

調査手帳

調査手帳でできること

シナリオ中好きなタイミングで画面を開くことができ
個別のアイテムを押すと、さらに詳細な情報が見られる

お探しの機能はもしかして

horono様が提供されている「TIPプラグイン」のほうがお持ちの要件と一致する方が多いのではなかろうかと思いますので紹介です。詳しくはリンク先の記事をご覧ください。

この記事を読み続ける前に

ティラノスクリプトの理解想定レベルやjsの記述ルール、配列(js)については以下にまとめています。ただし、今回の記事ではjQueryをjsに書き換えが一部できておらず、コメントアウトでゴメンナサイしています。

調査手帳を作ろう

実践1.要件を整理する

実装の前に、必ず何をしたいのか目的を書き出して、それを実現するための要件を洗い出します。

目的:シナリオが長いので、いつでも情報を見返せるものを作りたい

  1. ティラノスクリプトのデフォルト機能にある「メニュー」と同じように、シナリオ中の好きなタイミングで「調査手帳」を開閉したい

  2. 特定の文章追加で情報(親情報)が追加される

  3. 親情報の中に子情報を複数入れたい

  4. 追加された情報にはNEWをつける

  5. 既読の情報にはNEWをつけない

  6. 既読済みの親情報に子情報が追加されたらUPDATEをつける

  7. すべての子情報が揃ったアイテムには完了マークをつける

  8. 人物情報は立ち絵の切り替えができるようにする

などなど

すべての実装について説明すると説明側が大変なので、調査手帳の機能の肝になる「1・2・4・5」について解説します。

実践2.ティラノスクリプトのデフォルト機能にある「メニュー」と同じように、シナリオ中の好きなタイミングで「調査手帳」を開閉したい

さくた様の「htmlファイル読み込みプラグイン」を使いましょう!

プラグインを使わなくてもシナリオファイル(.ks)でも同様のことができるのでは?と思う方もいらっしゃるかと思いますが、表示速度やシナリオ中の演出あれこれそれなどを考えると、メニューなどと同じようにhtmlファイルを表示させるようにしたほうが吉です。

実践3.「調査手帳」を用意

上記のプラグインを追加して加えるhtmlの中身です。
中の挙動はコメントアウトに詳しく書いてあるので参照してください。
なおCSSはどシンプルなものですので、ガンガン変えてください。

<div class="note">
  <div id="note_body" class="note_body">
    <ul id="note_list" class="note_list">
      <!-- モーダルを開くためのアイテム置き場 -->
    </ul>
  </div>
  <!-- モーダルを開いた時、うしろに半透明黒の色を敷く -->
  <div id="modal-overlay" class="modal-overlay"></div>

  <!-- モーダルの中身置き場、今回は情報3つなので、3つ分のモーダルを用意コンソールで見れてしまうのを避けたい場合はremove仕込むと◎ -->
  <div class="note-modal js-modal" data-id="modal-item1">
    <div class="note-modal__inner">モーダルの中身その1</div>
    <p class="js-modal-close">閉じる</p>
  </div>
  <div class="note-modal js-modal" data-id="modal-item2">
    <div class="note-modal__inner">モーダルの中身その2</div>
    <p class="js-modal-close">閉じる</p>
  </div>
  <div class="note-modal js-modal" data-id="modal-item3">
    <div class="note-modal__inner">モーダルの中身その3</div>
    <p class="js-modal-close">閉じる</p>
  </div>

  <style>
    .note {
      width: 1280px;
      height: 720px;
      background: #ffffff;
      font-size: 24px;
      text-align: center;
      position: relative;
    }
    .note_list {
      padding: 30px;
    }
    .note_list li {
      margin: 10px;
    }
    .note_list li.is-new::after {
      content: "【NEW】";
    }
    .note-modal {
      display: none;
      background: #ffffff;
      width: 1000px;
      height: 640px;
      position: absolute;
      margin: 0 auto;
      padding: 30px;
      top: 40px;
      left: 140px;
      box-sizing: border-box;
    }
    .note-modal__inner {
      padding:200px 0;
    }
    .modal-overlay {
      background-color:hsla(0,0%,7%,.6);
      width: 1280px;
      height: 720px;
      display: block;
      position: absolute;
      top: 0;
      left: 0;
      display: none;
    }
  </style>

  <script>
    //このファイル単体でチェックしたい場合は、↓配列のコメントアウトを削除してください
    //ただし、2回目開いた場合もこの変数が適用されてしまいます(readの書き換えが保存されていない)
    //TYRANO.kag.stat.f.note_array = [{num:'1',done:'true',read:'false',name:'ひとつめ'},{num:'2',done:'true',read:'true',name:'ふたつめ'},{num:'3',done:'false',read:'false',name:'みっつめ'}]

    //シナリオファイルで使っている「f.note_array」を変数化、ここで名前を変えればOK
    //何度も開くので、letとか使わない、変数の再宣言を許容
    var note_array = TYRANO.kag.stat.f.note_array
    var note_elm_id = document.getElementById("note_list")

    //配列で用意している情報分処理を3回まわす(情報量増えたら数字変更してね)
    for (var i = 0; i < 3; i++) {
      //処理を繰り返す。0からはじまるのでは1からにしたいので+1
      var notenum = i + 1
      //data-id用の変数を作成
      var data_id = 'item' + notenum
      //そのままでは整数なので文字列に変更
      var notenum = String(notenum)
      //1.配列の「f.note_array」内部にあるnumをすべて取り出す
      var result_array = note_array.map((val) => val['num'])
      //2.今処理している回数の番号と同じnumが配列のどこにあるか探す
      var result_num = result_array.indexOf(notenum)
      //3.探した番号の情報が取得できているか「done」でチェック
      if(note_array[result_num].done === 'true') {
        //4.探した番号の情報が未読か「read」でチェック
        if(note_array[result_num].read === 'true') {
          //既読の場合、クリックできるアイテムを画面上に追加
          note_elm_id.insertAdjacentHTML("beforeend",'<li class="js-modal-open" data-id="' + data_id + '">' + note_array[result_num].name + '</li>')
        } else {
          //未読の場合は「is-new」をclassクラス名につけた状態で画面上に追加
          note_elm_id.insertAdjacentHTML("beforeend",'<li class="js-modal-open is-new" data-id="' + data_id + '">' + note_array[result_num].name + '</li>')
          //一度表示した扱いで「read」を既読に変更
          note_array[result_num].read = 'true'
        }
      }
    }

    //ここから先、jQueryからjsに書き換えを諦めたのであった...
    //モーダル開閉、後からデータを追加する関係で先に表示している「#note_body」の中の〜のものをクリックできるようにする
    $('#note_body').on('click','.js-modal-open', function() {
      //アイテムのdata-idと、モーダルウィンドウのdate-idが一致しているかチェック
      var id = $(this).data('id')
      $('#modal-overlay, .js-modal[data-id="modal-' + id + '"]').fadeIn()
      //一度クリックしたらアイテムの「is-new」クラスは削除
      $(this).removeClass('is-new')
    })
    // オーバーレイクリックでもモーダルを閉じるように
    $('.js-modal-close, #modal-overlay').on('click', function() {
      $('#modal-overlay, .js-modal').fadeOut()
    })
  </script>

</div>

実践4.シナリオ中に「調査手帳」用の変数を設定する

#
メッセージ枠が表示されている前提。[r]
ティラノの「html」タグは描写に時間がかかりますので、描画が完了するまでお待ちください。

;[note_set]というmacroを作成。「f.note_array」に配列として情報を足していく
;macroはfirst.ksなど、最初に読み込まれるファイルへの記載を推奨
[macro name="note_set"]
  [iscript]
    f.note_array.push({ num: mp.note_num, name: mp.note_name, read: 'false', done: 'false' })
    //配列の重複を削除処理
    var result_array = f.note_array.filter((val, index, array) => {
      //num だけをリスト化する
      var numList = array.map((val) => val['num'])
      //重複を削除する
      if (numList.indexOf(val.num) === index) {
        return val
      }
    })
    //重複排除した値をf.note_arrayに再格納
    f.note_array = result_array
  [endscript]
[endmacro]

;[note_done]というmacroを作成。「f.note_array」の配列内の情報を確認して書き換え
[macro name="note_done"]
  [iscript]
    //1.配列の「num([note_set note_num="数字"]の数字)」だけを取り出す
    var result_array = f.note_array.map((val) => val['num'])
    //1のなかのどこに今回書き換えたい数字([note_done note_num="数字"]の数字)があるか探す
    var result_num = result_array.indexOf(mp.note_num)
    //探した番号のところの完了フラグとして利用している「done」をtrueに書き換える
    f.note_array[result_num].done = 'true'
  [endscript]
[endmacro]

;変数「f.note_array」は配列であると宣言
[eval exp="f.note_array = []"]

;手帳の初期セットをする、ここの書き方は好み↑に直接書いてもいいYO
[note_set note_num="1" note_name="ひとつめ"]
[note_set note_num="2" note_name="ふたつめ"]
[note_set note_num="3" note_name="みっつめ"]

;console.logに「f.note_array」の内容を表示、リリース前に消すこと
[eval exp="console.log(f.note_array)"]


;シナリオ中に調査手帳のhtmlを開くボタンを設置
;詳しくはhtmlファイル読み込みプラグイン

;↑↑↑↑↑↑ここまでをシナリオ開始前に設定↑↑↑↑↑↑↑↑

#
シナリオ開始するわよ![p]

;シナリオ中、ひとつめの情報を取得した場所に書く
[note_done note_num="1"]
ひとつめの情報を取得したわよ![p]

;シナリオ中、ふたつめの情報を取得した場所に書く
[note_done note_num="2"]
ふたつめの情報を取得したわよ![p]

;シナリオ中、ふたつめの情報を取得した場所に書く
[note_done note_num="3"]
みっつめの情報を取得したわよ![p]

;任意の場所で調査手帳を開くボタンを押して、中身がどうなるか確認してみてください。

まとめ

これで、要件に書かれていた「1・2・4・5」が満たした調査手帳を作ることができました。

1.ティラノスクリプトのデフォルト機能にある「メニュー」と同じように、シナリオ中の好きなタイミングで「調査手帳」を開閉したい
2.特定の文章追加で情報(親情報)が追加される
4.追加された情報にはNEWをつける
5.既読の情報にはNEWをつけない

他の条件の解説まで行くと、ただでさえ長いnoteがさらに長いことになるので、自分で開拓してみてください。他の要件は1、2、4、5の応用です。

ということで今回は「調査手帳」を作成するために必要なhtml・css・jsを解説しました。
実際ゲーム画面でどんな挙動をしているか確認したい場合は、ゲーム「マダム・ポプスキンの憂鬱」をプレイしてみてください。

ノベルゲームコレクションの配信(ブラウザ・Windowsダウンロード版)https://novelgame.jp/games/show/6563

ふりーむの配信(Windowsダウンロード版)https://www.freem.ne.jp/win/game/28248

PLiCy(ブラウザ版)
https://plicy.net/GamePlay/138906

特設サイト
https://totetike.rgr.jp/madam/

これでマダム・ポプスキンの憂鬱で使った技術解説は一区切りにしようと思います。

twitterで話していたQTE的なものはどうなったかって?

動作の作りが甘いので次回作で見直していますので、次回作公開後に説明できればです。

※この記事は2023年2月4日時点の内容をまとめたものです。

この記事が気に入ったらサポートをしてみませんか?