Project Plateau
Project Plateau: four glass plates, one living valley, and the road back to camp.
翻訳待ち
No updates detected yet. GitHub releases will appear here.
Loading the full README. The saved excerpt is shown below.
就活の「お祈りメール」やライブの落選メールでモヤっとした気持ちを、ゲームでスカッと発散するアプリです。 • 就活のお祈りメールをもらってモヤっとしている学生 • ライブの抽選に落選してモヤっとしている学生 • タイトル画面: @ちゃんぐー_川口雄矢 • ゲーム画面: @こうた_奥川広大, @いぬぽん(メンター)Read the full README ↗
就活の「お祈りメール」やライブの落選メールでモヤっとした気持ちを、ゲームでスカッと発散するアプリです。
モバイルブラウザ
TITLE → 「スタート」 → MAIL_INPUT → 「ゲーム開始」 → GAME
src/scenes/MailInputScene.js がメール本文入力画面。ブロックの生成は一切行わず、
入力文字列をトリムしたものを onStartGame(mailText) で渡すだけに徹している。src/main.js の App.goTo() が onStartGame の戻り先として
GameScene.setMailText(mailText) を呼んでから mount() する
(ResultScene.setResult() と同じ「mount前にsetterで値を渡す」パターン)。GameScene._setupWall() が実際のブロック生成場所(空中の棒の上に積む)。
積む行は _buildRows() が返す「行(文字配列)の配列」に一本化してあり、
this.mailText が未設定(null)の場合(「遊び方」から直接ゲームへ進んだ
場合など)もランダムな文面を同じ手順で行分解する。つまり「1文字=1ブロック」の
経路は常に1本だけ。GameScene._splitIntoRows() が行の組み方を1箇所に集約している。
MAX_ROWS(現在6行)を超えて積み上がりそうな
文字数になったら、行数を増やさず折り返し幅(列数)だけを増やして横に広げる。Array.from() を使う。Block)で埋めている。行ごとに実際の文字数で中央寄せすると、
短い行の上に長い行が乗ったときに支えのないオーバーハングができて自重で
崩れてしまうため、必ず全行同じ列数・左詰めで配置している。MAX_MAIL_BLOCKS(現在100文字。MailInputScene側のMAX_MAIL_LENGTHと
揃えてある)を超える入力は先頭から切り詰めている(空白ブロックの分は
この上限に含めない)。row=0が最初の行)だが、
壁は下から積み上がるので、そのままだと最初の行が最下段になって上から下に
読むと逆順になってしまう。_spawnBlock() で高さを反転している。src/scenes/GameScene.js, src/game/Bar.js)Bar(幅8m・高さ0.3m・
奥行き1.2mの直方体、src/game/Bar.js)の上に積んである。棒はmass: 0の
完全固定ボディで、球が当たっても棒自体は動かない。棒が落ちる設計にすると、
乗っている壁が一撃で全部落ちて8球という球数設計が壊れるため。Blockにあった耐久値・破壊判定(HIT_DURABILITYなど)は撤去した。
ブロックは衝突では絶対に壊れず、棒の上面より1m下(CRUSH_FALL_Y)まで
落ちたら「粉砕された」扱いにしてfallingBlocksに移す。このゲームに
スコアは無く、代わりにGameScene._markCrushed()がそのブロックの
sourceIndex(元のメール本文での文字位置)をcrushedIndicesに記録する。
記録は1回きりで、その後はGameScene._resolveLandedBlocks()が回収するだけの
存在になる。爆弾が爆発したとき(_resolveBombs())も同様に記録する。FLOOR_Y = -20)に
当たり判定だけの床を敷き、そこに着いた時点でブロックを破棄している。
カメラ位置(0,9,28)・フォグ(35〜50)から計算すると、画面の一番下の視線が
y=-20に届くのはカメラから59.7m先(フォグの上限50mより外)なので、
この床は画面のどこからも絶対に見えない。GameScene._setupBar() が new Bar(..., this.wallWidth) を呼ぶ)。
短いと端のブロックが棒に乗らず開始直後に落ち、長いと端に何も乗っていない
余りが見えてしまう。文字数で壁の幅が変わるため、BAR_SIZE.x は既定値の
扱いになっている。GameScene._applyCameraFraming())。縦画面のように横方向の視野が狭い
ときは横幅基準の距離が、横長画面では高さ基準の距離が効く。画面回転時
(_onResize)にも引き直す。CAMERA_BASE_POSITION(0,9,28) /
CAMERA_BASE_LOOK_AT(0,7,0) からは向きと最短距離だけを取り出しており、
24文字のときはこの最短距離が下限として効くので従来の見え方と変わらない。
影の範囲とフォグもカメラ距離に追従させている。LAUNCH_ORIGIN は壁からの距離(z=25m)なので、カメラを引いても球の届く
距離には影響しない。ただし AimController の仰角レンジは壁の高さを前提に
実測した値なので、MAX_ROWS を増やして壁を高くしたら測り直しが必要(下記)。文字数が増えると列が増え、壁が横に広がり、収めるためにカメラが下がる。 その結果ブロックの文字は小さくなる。iPhone 14(390×844)の縦画面での実測値:
| 文字数 | 列 × 行 | 壁の幅 | カメラ距離 | 画面上の文字の高さ |
|---|---|---|---|---|
| 24 | 5 × 5 | 8.0m | 28.1m | 20.3px |
| 40 | 7 × 6 | 11.2m | 33.8m | 16.9px |
| 60 | 10 × 6 | 16.0m | 48.3m | 11.8px |
| 100 | 17 × 6 | 27.2m | 82.1m | 6.9px |
上限いっぱいの100文字では文字がほぼ読めない。 読みやすさを優先するなら
MAX_MAIL_BLOCKS を下げる(MailInputScene の MAX_MAIL_LENGTH も一緒に)。
20px を確保できるのは40文字弱まで。なお「文字数に応じてブロック自体を縮小する」
案は過去に試して、カメラを引いた分と相殺してかえって読みにくくなることを
実機確認済み。
src/game/AimController.js)MAX_ROWS = 6
なので文字数によっては6行(頂点 y≒11.9)になり、壁が約1m高くなる。28度は
もともと壁の頂点よりやや高く着弾する設定なので届く見込みだが、
実機で最上段に当たるか確認したい。本文に GameScene.BOMB_WORDS の語が含まれていると、その語を構成する文字の
ブロックが爆弾になる。語を増やすときはこの配列に足すだけでよい。1文字だけの
語も指定できる。現在の内訳は次の通り。
| 系統 | 語 |
|---|---|
| 抽選・チケット | 抽選 当選 落選 外れ 用意 希望 |
| 選考・就活 | 選考 不採用 見送 内定 残念 期待 厳正 慎重 検討 |
| 単体でも落選を連想させる字 | 縁 祈 選 残 |
単漢字ではなく語で持たせているのは、「抽選」「見送」のように隣り合うブロックが まとまって赤くなったほうが、何が爆弾なのかを目で読み取れるため。「結果」のように それ自体は中立な語は、手がかりが薄れるので入れていない。
語どうしは範囲が重なってよい。検出はフラグを立てるだけなので、'選' と '抽選'
の両方に当たっても二重には効かない。重ねて持つ意味はあって、たとえば '抽' が
爆弾になるのは「抽選」と続いたときだけになる。
同梱の EMAIL_TEXTS 10文面では全体の約18%が爆弾になり、どの文面にも必ず
1個以上の爆弾が出る。
Block.js の BOMB_* 系の配色)。文字はそのまま読める。collide を監視して Block.hitByBall を立てる
(BOMB_TRIGGER_SPEED = 1.5 未満のかすった接触は無視する)。
GameScene._resolveBombs() が毎フレームこれを見て爆発させる。GameScene._explode() が爆心から半径 EXPLOSION_RADIUS 以内の動的なボディ
(ブロックと飛んでいる球の両方)を外向きに押す。力は距離に応じて線形に弱まり、
外周でゼロになる。遮蔽は見ていない。EXPLOSION_RADIUS(どこまで巻き込むか)と EXPLOSION_IMPULSE
(どれだけ飛ばすか)の2つ。ブロックの質量は 1.5 なので、現在の力積 30 は
爆心でおよそ 20 m/s の初速にあたる。半径 6.0m は MAX_ROWS = 6 の壁の高さを
ちょうど覆う大きさ。This is the beginning of the README. Read the rest at the original. Read the full README ↗