インディーRTAリレーのお手伝いをしました


インディーRTAリレーは2024/2/17(土) 19:30~開催された、リレー形式のRTAイベントです。

今回、運営としてはシステム面で任されました。
いくつかツールを製作したのでその備忘録と、反省点を交えてnoteに残します。


1. 配信オーバーレイ

nodeCGを使って配信画面の情報を更新していました。特段難しいことはしていませんが、需要があればリファクタリングしてリポジトリ公開します。

nodeCG操作画面

Runner: チームメンバーをプルダウンから選択し、更新ボタン押下
Audio Icon: 現在配信画面から音声出力している画面にアイコン表示
Time: 完走時間をチーム画面の上部に表示

実際の配信画面(あひるさんチームフォーカス)

頻繁に変更が必要になるであろう項目はワンクリックで、それ以外は何かのボタンを押下する、あるいはすぐに変更/非表示が可能になるように設計しました。
nodeCGなど配信オーバーレイソフトの良い所は、graphicsさえ用意していれば情報を書き換えるのが1箇所のみで済むところですね。

今回、名前の隣にパイプ( | )、twitchアイコンとtwitch IDを載せたいと要望があったので、大分強引に用意しました。

#idnex.html
	<p class="plateA"><span id="runnerNameA"></span> |
		<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="45" height="45" viewBox="0,0,256,256">
			<g fill="none" fill-rule="nonzero" stroke="none" stroke-width="1" stroke-linecap="butt"
				stroke-linejoin="none" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0"
				font-family="none" font-weight="none" font-size="none" text-anchor="none"
				style="mix-blend-mode: normal">
				<path transform="scale(5.12,5.12)"
					d="M48,1v29.4375l-12.59375,12.5625h-9l-6,6h-7.40625v-6h-11v-33.1875l3.3125,-8.8125z"
					id="strokeMainSVG" fill="#ffffff" stroke="#ffffff" stroke-linejoin="round"></path>
				<g transform="scale(5.12,5.12)" fill="#8611ff" stroke="none" stroke-linejoin="miter">
					<path
						d="M5.3125,1l-3.3125,8.8125v33.1875h11v6h7.40625l6,-6h9l12.59375,-12.5625v-29.4375zM11,6h32v22l-6,6h-12l-6,6v-6h-8zM20,13v14h6v-14zM30,13v14h6v-14z">
					</path>
				</g>
			</g>
		</svg>
		&nbsp;&nbsp;&nbsp;&nbsp;<span id="twitchidA"></span></p>

runnerNameと合致する名前とtwitchidをリストから呼び出しているだけなので、リストさえあれば情報は引っ張ってこれます。
twitchアイコンについては、ベクトルデータであるSVGを使うことで、画面を拡大・縮小しても品質は変わりませんのでこういった形で。
SVGはどこかのサイトで生成したものを使用したのですが、忘れました。&nbsp;で微調整してるのよくないですが、なんかCSSで上手くいかなかったような記憶があります。

また、今回タイマーを表示しなかったのですが、理由としてほとんどのゲームがLRT(Loadress Time)やIGT(In Game Time)で計測しており、機能しないためです。RTA(Real Time)の場合は実装してもいいかもしれないので、用意しておいてもいいかもしれません。

これらの配信レイアウトについて、以下のイベントを参考にさせていただきました。ありがとうございます。
 ・カービィシリーズタイトルRTAリレー2023
 ・全日本RTA駅伝
 ・Luck Game RTA


2. タイムキーパー

タイムキーパーは駅伝、リレー形式ならではの必須な機能です。どのチームが最初にチェックポイントを通過し、2位以降のチームは追いつくためにどれだけの時間を詰める必要があるのか、など一目で見てわかるようなものがあれば便利だな~と思って詰め込んだものを用意しました。

(左)配信画面に載せていたシート (右)ボランティアに書き込んでもらうシート

タイムキーパーシートの要望としては以下2点。

  • 1画面で収まるくらいのチェックポイント、シートの用意

  • 1位通過は合計タイムを、2位以降は1位とのタイム差を表示

nodeCGで管理してもよかったのですが、上手くgoogleスプレッドシートと連携することができなかったので、今回は全てgoogleスプレッドシートで管理することにしました。
関数としてはMINやIFBLANKを使うだけなのでこちらも特段難しい事はしていません。
一方で、2位以降は赤字で+〇:〇〇と表示する実装が割と時間かかりましたし、今も割と強引です。

ボランティアシート(入力用シート)
セルに設定した条件付き書式(配信用シート)

・=ISBLANK(INDIRECT("入力用!I4"))=TRUE
 ボランティア入力シートで該当セルの入力がない場合、真っ白表示

・=EXACT(INDIRECT("入力用!E4"),INDIRECT("入力用!J4"))=FALSE
 3チームのうち、2位以降の場合赤字で差分タイム表示

・=ISBLANK(INDIRECT("入力用!$I4"))=FALSE
 3チームのうち、1位の場合通過タイム表示

区間ごとにMINを計算すると、各チームの差分がその時点で反映されてしまい、+1:00:00とかいうありえないタイムが表示されたので、一番上に入力有無確認の条件を追加しました。
美しくないので、次回までに整形しておきたいところです。

タイムキーパーシートに記入するボランティアの方には、知らないゲームにも対応できるようわかりやすい箇所をピックアップしたつもりです。
一方で、事前にIGTかRTAか伝えそびれていたり、LiveSplitが配信オーバーレイのアイコンで隠れていたりと、結構な不便を感じさせてしまったと思う点が反省点です。


実は、配信とは別に、裏で詳細データを取っていました。
これはFinal Fantasy Series Relay Race VIIIを参考にしたもので、
「こういうデータを見ながら視聴してたら面白いんじゃないか…!」と急遽準備したものです。基本、ボランティア用のものからコピペしただけなので仕組みは割愛。



3. 閉会式スライド

閉会式スライドに各区間のタイムを自動入力できないか、という要望があったので実装しました。
これ、本番直前に作ったものなので上手く機能しませんでした。

閉会式スライド

2.のタイムキーパーで使用したボランティア用のシートから直接googleスライドにデータを反映するようにしました。調査~実装まで1日だったのでさすがに無理でしたが、備忘録ということで参考までに。

#Google Apps Scripts
 
function insertTextToSlide() {
  // googleスプレッドシートからgoogleスライドにデータを渡す
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName('シート名');
  var presentationId = 'googleスライドID';
  var presentation = SlidesApp.openById(presentationId);
  var cellValue = [];
  var ranges = ['D', 'H', 'L', 'P', 'T', 'W']; // タイムを参照している列

  for (var i = 0; i < ranges.length; i++) {
    cellValue[i] = [];
    for (var j = 23; j <= 25; j++) { // タイムを参照している行
      var value = sheet.getRange(ranges[i] + j).getDisplayValue(); // セルの値を取得
      value = value.split('').join(' '); // 各文字の間に半角スペースを挿入(※1)
      cellValue[i].push(value);
    }
  }

  // テキストボックスを挿入する関数
  function insertTextBox(slide, text, left, top) {
    var textBox = slide.insertTextBox(text);
    var textStyle = textBox.getText().getTextStyle();
    textBox.setWidth(300);
    textBox.setLeft(left);
    textBox.setTop(top);
    textStyle.setFontFamily("Noto Sans JP"); // ※1
    textStyle.setFontSize(52);               // ※1
    textStyle.setForegroundColor("#ffffff"); // ※1
    textStyle.setBold(true);                 // ※1
  }

  // スライドページを取得し、特定の座標に受け取ったタイムを上書きする
  function updateSlide(slideIndex, cellValues) {
    var slide = presentation.getSlides()[slideIndex];
    
    // タイムのシェイプのみ削除する
    slide.getShapes().forEach(shape => {
      if (shape.getWidth() === 300) {
        shape.remove();
      }
    });

    var leftPositions = [120, 590, 1050]; // X座標の配列
    // var topPosition = 590; // Y座標

    // セルの値を取得してテキストボックスに挿入
    for (var i = 0; i < cellValues.length; i++) {
      if(slideIndex == 10) {
        var topPosition = 610;
      } else {
        var topPosition = 590;
      }
      insertTextBox(slide, cellValues[i], leftPositions[i], topPosition);
    }
  }

  // スライドごとに更新を行う
  updateSlide(3, cellValue[0]); // ENDER LILIES
  updateSlide(4, cellValue[1]); // Metal Unit
  updateSlide(5, cellValue[2]); // Salt and Sanctuary
  updateSlide(6, cellValue[3]); // Gibbon
  updateSlide(7, cellValue[4]); // Have a Nice Death
  updateSlide(10, cellValue[5]); // Total
}

※1: スライドのフォーマットを合わせるために追記

googleスライドに反映させるシート(一部)

基本的なCSS、JS知識があれば何をやっているかわかると思います。
ただ、なぜか最後の // Total 部分だけ反映されませんでした。開発環境では動いていたのですが、ちょっと原因がまだわかっていません。
手動でタイムを入力するのもいいですが、スプレッドシートと同じ情報を用いることで"比較的"ヒューマンエラーをなくすことが目的です。

GASトリガー設定画面

googleスプレッドシートのタイムが書き換わった時にgoogleスライドのタイムが自動で書き換わるようにトリガーを設定しました。なんかエラーはいてますね。
スクリプト実行ボタンの場合、googleスプレッドシートのアクセス権があるユーザーのみ実行できるので、メールアドレスを収集する必要があります。これを厭う方もいるので、リスキーでもありますがこういったやり方もあるとのことだけ。

そもそもこれまでのスライドはcanva→エクスポート(.pptx形式)だということを知らず、GASはpptx形式に対応していないことも知らず、でばたばたしていましたが、基本設計~実装までしっかりと行うよう心がけようと思いました。



これまでのボランティア経験の知識や有識者の方からのアドバイス等をいただき、なんとか形に持っていくことはできたと思います。
今は汎用性、拡張性がなく他イベントで流用はできませんが、時間あるときに整備して、誰でも簡単に使えるようにしようと思いました。


このきじをかいたねこ:ふーにゃん
SNS
Twitch
マシュマロ

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