OBS でランダムな画像表示がしたい(配信終わりに表示する1枚絵をランダムに選択)


はじめに

Linelight の配信では最後に "Thank you for watching" という文字が入った画像を表示していましたが、他のゲームの配信でも同様に画像を表示しようと思いました
 その際、複数の画像を用意してランダムで選ばれるようにしたら面白いんじゃないかと思い、HTML + JavaScript で作ってみました

この記事では次の前提条件があります

  • 表示する画像の縦横サイズは全て同じサイズ
  • JS も CSS も HTML ファイルの中に記述する方式
  • HTML ファイルも画像ファイルも全てローカルにあるファイル
  • とりあえず動けば良いや、なのでHTML文書としては不完全です
  • 私の知識はほぼ HTML 4.01 以前の状態で止まっています


ランダム選択するための JavaScript

基本型 全て等確立
候補を抽選リストに入れて、そこから1つ取り出します
全ての候補が 1/N の確率で選ばれます

抽選の候補である N 個の玉を箱に入れて、その箱から玉を1個取り出すときの当選確率と同じイメージです



コード例の img タグ内で画像サイズを指定しているのは、異なるサイズの画像が混ざってしまった場合でも表示されるサイズを同じにそろえるための保険です

HTML文書の例(基本型の JS コード)
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
<body>
  <script type="text/javascript">
    var imglist = new Array(
      "./img01.png",
      "./img02.png",
      "./img03.png",
      "./img04.png",
      "./img05.png"
    );
    var selectnum = Math.floor(Math.random() * imglist.length);
    var output = "<img src=" + imglist[selectnum] + 
                 " width=\"640\" height=\"480\">";
    document.write(output);
  </script>
</body>
すでにこの段階でランダムで画像が選ばれる状態になっているので、HTML ファイルを保存して、普段使っている web ブラウザで開いて、更新すると画像がランダムで選ばれることを確認しておくと安心です


応用型 画像によって当選確率を変える
候補によって当選確率を変えたい場合、箱に「入れる・入れない」を確率によって決めます
 箱に入れた後は基本型と同じで、1つ取り出すだけです

ちなみに、この抽選の仕組みは CookieClicker のゴールデンクッキーの抽選と同じだったりします(というより、それを参考にしました)



Math.random() の値の範囲が 0 以上・1 未満なので、Math.random() < 0.5 ならば 50 % の確率です

HTML文書の例(応用型の JS コード)
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
<body>
  <script type="text/javascript">
    var imglist = new Array(
      "./img_A01.png",
      "./img_A02.png",
      "./img_A03.png",
      "./img_A04.png",
      "./img_A05.png"
    );
    if (Math.random() < 0.5) imglist.push(
      "./img_B01.png",
      "./img_B02.png",
      "./img_B03.png"
      );
    if (Math.random() < 0.1) imglist.push(
      "./img_C01.png"
      );
    var selectnum = Math.floor(Math.random() * imglist.length);
    var output = "<img src=" + imglist[selectnum] + 
                 " width=\"640\" height=\"480\">";
    document.write(output);
  </script>
</body>

当選確率の計算
当選確率の計算は少し面倒です
 箱から取り出す段階だけを見ると当選確率 1/N ですが、実際の当選確率を計算するには箱に入れた・入れなかった全ての場合を考える必要があります

まず、箱に入っている候補の数 N で場合分けして、その N の発生確率を求め、発生確率/N でそれぞれの場合での 1/N の当選確率を求めます
 発生確率の和が 1 になっていることを確認します



次に、グループごとに箱に入っている時の各 N における 1/N の当選確率の和を求めると実際の当選確率が分かります
 当選確率の和が 1 になっていることを確認します



コード例と同じ候補数・箱に入れる確率だった場合、グループ A は 16 %、B は 6.2 %、C は 1.4 % くらいの当選確率です
 表中の表示桁数がバラバラなのは単なる手抜きなので、気にしないでください


自動的についてくる余白をなくす CSS 設定

HTML をブラウザで表示すると、ブラウザの枠と表示される要素との間に自動的に余白(要素の外側余白:margin + 要素の内側余白:padding)が設定されます
 OBS の「カスタム CSS」のデフォルト設定で余白を無視することができるので、HTML ファイル内で CSS を設定することは必須ではありませんが、動作確認のためにブラウザで表示したい場合などは余白をなくす設定をしておいた方が良いと思います



CSS コード例
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
<head>
  <style type="text/css">
    <!--
    body{
      margin: 0px;
      padding: 0px;
    }
    -->
  </style>
</head>


OBS の設定

ソースで「ブラウザ」を追加してプロパティの設定を行います

  • 今回の例では HTML ファイルがローカルにある前提なので「ローカルファイル」にチェックを入れて作成した HTML ファイルを選択します
  • 「幅」と「高さ」は任意の値を入力、基本的には画像と同じサイズかと思いますがレイアウトに都合の良い値を設定
  • 「表示されていない時にソースをシャットダウン」は任意、シャットダウンすると非表示の間はメモリに優しいくらいの効果だと思いますが、画像だけなので大きな違いはないように思います
  • 「シーンがアクティブになったときにブラウザの表示を更新」のチェックは必須、これで表示・非表示を切り替えるたびに画像がランダムで表示されるハズです


おまけ1 私が実際に使っているHTML

私が実際に使っているものを公開します

私が配信の最後に表示している画像では "Thank you for watching" という文字を入れているのですが、ランダム表示をする時は複数の画像全てに文字を入れるのが大変です
 そこで、文字は HTML で表示して、画像はそのままの画像を表示することにしました

ただし、この場合はランダムで表示されるどの画像でも、文字の位置は同じになることに注意です

Typoman の配信で私が実際に使っているHTML
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
<html>
<head>
  <style type="text/css">
    <!--
    body{
        margin: 0px;
        padding: 0px;
        position: static;
    }
    .text-background{
        position: absolute;
        top: 450px;
        left: 0px;
    }
    .text{
        position: absolute;
        top: 455px;
        left: 550px;
        font-size: 32px;
        font-family: "メイリオ";
        text-shadow: 0px 0px 8px #fff, 0px 0px 3px #000;
    }
    -->
  </style>
</head>
<body>
  <script type="text/javascript">
      var imglist = new Array(
          "./carrying_lei.png",
          "./catch_love.png",
          "./escape_skip.png",
          "./noise_escape.png",
          "./rev_lift.png",
          "./turn_skip.png",
          "./hand.png"
      );

      var selectnum = Math.floor(Math.random() * imglist.length);
      var output = "<img src=" + imglist[selectnum] + " width=\"960\" height=\"540\">";
      document.write(output);
  </script>

<svg width="960" height="60" viewBox="0 0 960 60" class="text-background">
<rect x="0" y="0" width="960" height="60" fill="#fff6"></rect>
</svg>

<div class="text">Thank you for watching</div>

</body>
</html>


おまけ2 OBS プラグイン

Source Switcher というプラグインを使用することで、複数の画像の中から一つをランダムで表示することができるようです
 ただし、この場合は画像ごとに表示される確率は同じになるように思います

参考
ソースを1つにまとめて自由に切り替えることができるOBSプラグイン

1 件のコメント: