はしのした


2024-11-24 ぷよレイヤーズブリッジ8

※ 当イベントは無事終了しました。

原点回帰? の8回目。遊びにおいで!

  はじめに

ぷよ・魔導・DS関連のコスプレ歓迎交流会「ぷよ橋」こと「ぷよレイヤーズブリッジ」は、特に初期(第1回第3回第4回)には浅草橋駅近くの秋葉原ハンドレッドスクエア倶楽部にて頻繁に開催してきました。 今回は久しぶりに浅草橋に戻ろうか、と考えていたところ、同じ建物に2号店がオープンしているではないですか! ということで、5年半ぶりのいつもの場所で、ちょっとだけ趣向を変えた形で、第8回のぷよ橋の開催を宣言します。

フロア自体はステージ常設で、声優イベントや VTuber イベント、トークショーなどでの利用が想定されているみたいです。 ただ、控室・メイクスペースが充実しているのは、コスプレ歓迎交流会としてもありがたいポイント。 もちろんメインスペースにも十分な広さがあるので、コスプレはしないけど交流やゲームはしたいという人も、存分に楽しめるでしょう。

当イベントのコンセプトは、ぷよ・魔導・DSが好きなレイヤー同士、あるいはレイヤーと交流したいファンを含めた、幅広い交流の架け橋となることです。 また今回の開催では、競技としてぷよぷよを知ったプレイヤーと、キャラクターコンテンツとしてのぷよぷよを好むレイヤー・ファンとの間の交流の促進も、新たにコンセプトに加えます。

運営体制

今回の開催は、主催(総合委員長)SoLa4 と副主催(e スポーツ渉外委員長)ゆっきの、2人体制で運営いたします。 開催全般の諸事務は SoLa4 が、イベント開催申請やぷよプレイヤーへの告知活動等はゆっきが、それぞれ担当します。

  開催概要

  • 日時: 2024年11月24日(日) 9:00~20:00(途中入退場可)
  • 場所: 東京都台東区浅草橋5-3-2 秋葉原ハンドレッド2
    • JR・つくばエクスプレス 秋葉原駅昭和通り口から徒歩10分,電気街口から徒歩13分
    • JR・都営地下鉄 浅草橋駅西口から徒歩6分
    • これまでの会場と同じビルの 2F です。7F ではありませんのでご注意ください。
    • 当日は、浅草橋駅西口から現地への誘導を予定しています。
  • 参加費: コスプレ参加 2,500円,一般参加 2,000円
    • 学生とその保護者は、学割として1,000円引き
    • 会場の滞在時間が5時間以下の場合、半日参加として500円引き(学割と併用可)
  • 参加者枠: 35名程度
    • 高校生の参加は、保護者の参加か、保護者の許可を得ていることを条件とします。
    • 中学生以下の参加は、保護者の参加を条件とします。

開催前後の連絡には Discord を使用します。 まだサーバに参加していない方には、Discord のユーザ名をご申告いただきますので、ご承知おきください。

注意事項

今回のイベント告知、およびレポート投稿は、セガが運営するぷよぷよプレイヤー向けコミュニティサイトである「ぷよぷよキャンプ」でも行っています。 これに伴うセガへの許諾申請の範囲は、イベントの開催そのものと、イベント内での「ぷよぷよeスポーツ」「ぷよぷよ™テトリス®2」「ぷよぷよパズルポップ」の各タイトルの使用、ぷよぷよキャンプにおける諸投稿となります。 そのため、当イベント内でのコスプレなどの二次創作表現は許諾の範囲外となります。 コスプレなどは、あくまで各参加者が自己の責任のもとで、営利を目的としない範囲で行うものになりますので、ご理解ください。

参加者一覧

(敬称略)

SoLa4    ゆっき    某      柊夜     
來那星光けるぐ兼田ライ超鮫YSK
珈琲屋桔梗159753へーょまは
うさみみもぐらてぃおなもみライ麦
ムナパパなおしば  

今回は ぷよぷよキャンプでの告知 ・参加受付も併せて行いました。

スケジュール

  • 8:50 浅草橋駅集合(第1次)
  • 9:00 設営・着替え開始(設営は 7:00 過ぎから可能です)
  • 9:50 浅草橋駅集合(第2次)
  • 11:30~13:00 企画 (1) ぷよポップ団体戦
  • 13:15~13:30 全員集合写真撮影 (1)
  • 15:30~16:30 企画 (2) ビンゴ大会
    • ビンゴ大会終了後、ステージでは公式プロ大会の配信を投影予定
  • 18:30~18:45 全員集合写真撮影 (2)
  • 18:50 撮影終了・片付け開始
  • 19:30 更衣室終了
  • 20:00 完全撤収

イベント企画情報

今回、久しぶりにイベント企画が復活しました! 景品は基本的に主催陣の持ち込みにより行いました。

ぷよポップ団体戦

現在配信中の「ぷよぷよパズルポップ」を使って、色々なルールで対戦しよう、という企画を行いました。 参加申請時に、事前にぷよぷよの実力を自己申告してもらい、それをもとにおおむね実力が等しくなるように参加者をチームに分けます。 各参加者は、くじ引きで選ばれたルールを使って対戦を行います。全員の対戦が終わった段階で、勝利数の多かったグループの勝ちです。

3チームでの対戦を1人2順、計18戦を行ったところ、なんと全チームが6勝で並びました。チーム代表者による決勝により勝敗を決めました。

ビンゴ大会

独自に用意したビンゴカードと抽選アプリを使い、ビンゴ大会を行いました。 カードは物理的にも用意しますが、当日会場で提示する特設ページにアクセスすることで、各自のスマートフォンなどからも参加できる形を取りました。 カードには2マス・4マスの大きなマスもありますので、皆さん好きなキャラのアイコンが大きく映ったカードを選んでいました!

ビンゴ大会で使用するアイコンの募集企画を行いました。皆様のご協力のおかげで、全枠満了となりました。 詳しくは別の記事にまとめています


2024-11-29 オンラインビンゴ!

ぷよ橋恒例のビンゴ企画をオンライン対応させたよ、という話。

  りきりきりきりきりきなんなん

ビーンゴー!(元ネタの曲知っている人どれくらいいるんだろ……)

ぷよ橋では、これまでにも数回ビンゴ企画を開いておりまして。 先日開催したぷよ橋8では、5年ぶりに企画を復活させたわけです。 ただ、今まで通りやるだけでは芸がないので、今回はビンゴカードをオンライン化して、各自のスマホのブラウザからもビンゴに参加できるようにしました! ちょうど仕事でも技術的に似たようなことやる必要あったし……

ということで、オンラインビンゴカードシステムをどう作ったか、記事にまとめておこうと思います。

全体的なアーキテクチャ

アーキテクチャ概要

今回のオンラインビンゴカードシステムの全体像を図示します。 簡潔に言えば、フロントエンドは JavaScript(JS)で、バックエンドは Ruby の CGI で、それぞれ書かれています。

司会者は抽選用のページに、参加者はカード表示用のページに、それぞれアクセスします。 ページから読み込まれる JS スクリプトには、抽選用・カード表示用・共通の3つの種類があります。 共通の JS は両方のページから読み込まれますが、残りの JS はそれぞれのページからのみ読み込まれます。 抽選用 JS は、司会者が抽選などの操作を行うと、バックエンドの抽選用 CGI スクリプトを呼び出します。 抽選用 CGI は、どの番号がいつ引かれたのかの情報を含んだルームデータを、テキストファイルとして書き出します。 カード表示用 JS はこのルームデータを読み取って、引かれた番号にマークをつけたり、ビンゴしたかどうかの判定を行います。

この設計は、ビンゴ実施中のサーバへの負荷を極力減らすことを意識したものになっています。 ルームデータへのアクセスの頻度は、参加者の人数に比例します。 しかし、このときサーバがすべきことは、数百バイトほどのテキストファイルを送ることのみです。 CGI スクリプトは、参加者側から呼び出されることはありません。

ただ、このことは同時に、参加者のカードデータをサーバに送ることはできないということも意味します。 司会者側の画面で参加者のリーチやビンゴの状況を確認する、などといった機能もあると楽しそうです。 しかしそこは、今回は設計の時点で割り切って諦めました。

フロントエンドの実装

まずは、フロントエンド部分の JavaScript について。 分量的には、カード表示用が計650行ほど、抽選用が350行ほど、共通が450行ほどで、計1,450行ほどです。 過去の回で使ってたスクリプトは計450行(抽選用300行、カード画像作成用150行)ほどだったので、3倍ほどに増えました……。 作らないといけない画面の数が増えたので、致し方ないところなのですが。

これまで作ってきた抽選ページ(や、ぷよ橋5で作った COOL24+24)は、特にフレームワークなども使わない、素の JavaScript を使っていました。 今回は、もう少しリッチな表現を求めて、Phaser というゲームフレームワークを採用しました。 GUI で開発ができるシーンエディタなどの有料機能もあるようですが、自力でコードを書く分には無料で使えます。 コードを書くのに十分なドキュメントやサンプル、リファレンスマニュアルもしっかり整備されています(ここが足りなくて利用を諦めたフレームワークもあります……)。 最低限の環境を整えるのも簡単で、基本的には 外部の JavaScript を読み込む HTML を用意して、適当な Web サーバ(Python 付属の簡易サーバ機能で十分)経由でブラウザに読ませるだけです。 そんな感じで、試行錯誤こそ必要だったものの、比較的すんなりと開発は進みました。

Phaser では、1つの画面(シーン)は Phaser.Scene を継承したクラスで定義します。 このクラスでは、コンストラクタ、および create() と update() の2つのメソッドを継承します。 コンストラクタでは、一意なシーン名を key に加えて継承元のコンストラクタを呼びます。 create() ではシーンの始めに1度だけ実行される処理、update() ではフレームごとに実行される処理を、それぞれ記述します。 ですので、基本的には create() でシーン上のオブジェクトを用意し、update() の中で入力のチェックとオブジェクトの操作を行えば、最低限動くものは作れることになります。

実際には、ボタンクリックなどの操作をきっかけに処理を行いたい場合があります。 この場合、オブジェクトにイベントリスナを設定することで対応できます。 具体的には、対象のオブジェクトの setInteractive() メソッドでクリック判定の領域を設定したあと、on() メソッドでイベントリスナを設定します。 今回はクリック可能なボタンが必要でしたので、ボタンを Phaser.GameObjects.Layer を継承したクラスとして、共通 JS の方で定義しています。 ボタンをクリックしたときにコールバックされる関数は、シーンのメソッドとして定義した上で、シーンに bind してからボタンのコンストラクタに渡しています。 (と、書いてて気づきましたが、on() メソッドの第3引数に context ってのがあったので、そこでシーンを指定してしまえば、bind は必要なかったかもしれません)

また、ちょっとしたアニメーションや色の変更など、毎回 update() の中で計算して動かすには面倒なものもあります。 これを楽にするための仕組みに Tween があります。 Tween をシーンに登録しておくと、経過時間をもとに一定の計算式でオブジェクトのプロパティを自動更新してくれます。 特に今回は、具体的なオブジェクトへの割り当てが必要ない、Number Tween というものを使いました。 経過時間を 0~1 の形で(あらかじめ指定した時間で割り算して)数えるとともに、フレームごとに onUpdate に登録したコールバックを呼び出してくれます。 また、指定した時間が経過すると、onComplete に登録したコールバックを呼ぶこともできます。 今回、カードを表示するシーンで、選ばれたマスをしばらく虹色で光らせたり、各ラインがビンゴにどれくらい近いかをアニメーションで表示したりといった処理に、この Number Tween を使いました。 その結果、このシーンでの update() の処理は、10秒おきにルームデータを読み込んだり、その結果を1秒おきに反映させたり(後述します)といった処理を書くだけになり、描画周りの処理が完全に分割できました。

カード情報の符号化

1度カードを作成したら、ブラウザをリロードなどしたときも同じカード情報で再開できることが望ましいです。 よって、カードが作成された時点で Cookie にカード情報を保存することにしました。 保存するカード情報は、各マスの番号をそのまま符号化するのも1つの手です。 しかし今回は、カードを再現するのに必要最小限の情報だけをアルファベット大文字(26種類)の文字列に符号化して、それをカード ID とすることとしました。 こうすれば、カード作成時と再開時とで、同じプログラムをそのまま使えます。 また、まさかこんな企画でズルをする人はいないと思いますが、原理上はズルもしにくくなるはずです。

具体的には、必要な情報は以下の通りとなります。

  • 巨大マスの配置される場所(16通り)
  • 巨大マスの番号(↑によって10通り or 20通り)
  • 乱数の種(2^32 通り)

巨大マスに関する情報はそれぞれ1文字で、乱数の種は7文字(∵ 7 x log2(26) ≒ 32.9)で、それぞれ符号化します。 カードの ID は9文字で表現されることになります。

バックエンドの実装

バックエンド部分は、約100行の Ruby スクリプトです。 ビンゴの進行状況はルームごとに管理され、ルームは数字4桁のルーム ID で識別されます。 入力はルーム ID と、そのルームに対して行う操作の種類です。 また、操作の結果として出力・更新されたルームデータを、そのまま出力します。

ルームデータは、以下に示すようなシンプルなテキストファイルです。

11234 1728190154
249 413
314 424
437 439
50 0

ルームデータの各行は、スペースで区切られた2つの数字からなります。 最初の行には、ルーム ID と、そのルームが開設された時刻(UNIX 時間で)が書かれます。 それ以外の行には、抽選された番号と、その時刻(ルームの開設時刻からの秒数)が書かれます。 ただし、ルームを閉鎖した場合には、両方に 0 が書かれます。

抽選操作が行われると、まだ選ばれていない数字を1つ選び、ルームデータの末尾に書き込みます。 このとき、抽選された時刻には、実際の時刻から少し(具体的には12秒)遅れた時間を記録しています。 カード表示用のページでは、1秒おきに現在時刻と抽選された時刻とを比較し、現在時刻が抽選された時刻になったとき初めて抽選結果を画面に反映させます。 これにより、カード表示用のページからルームデータを読み込む頻度を最小限(10秒に1回)に抑えつつ、抽選用のページで抽選された番号がわかるのと同時にカード表示用のページに反映させる、という動作を実現しています。

まとめ

ということで、ぷよ橋8で使われたオンラインビンゴカードシステムの紹介でした。 ソースコード一式はこちらに New BSD ライセンスで置いておきますので、無保証であることを承知いただけるのであれば、ご自由にお使いください。