Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion docs/backend.md
Original file line number Diff line number Diff line change
Expand Up @@ -492,14 +492,15 @@ Node版との差分(意図的な改善):
|---|---|---|---|
| `bell` | 鈴の緒(`omikujiMachine.js`) | 房をつかんで左右に振る | 玉が絵馬・水車・ドミノ階段をリレーして狐に直撃 |
| `slingshot` | 弾き玉(`omikujiSlingshot.js`) | 御神玉をつまんで引き絞り、放す | 木札の櫓に直撃して崩れ、木札か玉が狐に当たる |
| `pinball` | 弾き盤(`omikujiPinball.js`) | 右端の御神玉を下に引いて、放す | 玉が天辺の弧を回って盤面へ、バンパーに弾かれながら中央の穴の狐へ落ちる |

インターフェース(詳細は `omikujiMachines.js` の冒頭コメント):
`GEO`(論理座標系)/ `FOX`(寝床)/ `HINT`(案内文)/ `TIMELINE`(フォールバック時刻)/
`wakeLabels`(狐を起こすボディ)/ `grabFilter`(指でつまめるもの)/ `build` /
`createRitual`(儀式の完了判定)/ `fallbackRitual`(「うまくできないとき」)/
`onRitualDone` / `nudge`(詰まったときの押し)/ `createSettleDetector`(任意)。

確認用に `?scene=slingshot` のようにクエリで装置を固定できる。
確認用に `?scene=slingshot` `?scene=pinball` のようにクエリで装置を固定できる。

#### 弾き玉(slingshot)の設計

Expand All @@ -519,6 +520,41 @@ Node版との差分(意図的な改善):
45点を掃引し、狐への到達と静止までの秒数、無操作で装置が動かないことを確認する。
GEO を触ったら必ず回す。

#### 弾き盤(pinball)の設計

- 右端のレーンにある御神玉(プランジャー)を**下に引いて放す**。引きはレーンに
沿った縦方向だけに正規化し、支点を上に通り過ぎた瞬間に切り離す。射出速度は
[17, 21]px/step に収める。弱すぎると天辺の弧まで登り切れずレーンに落ち戻り、
速すぎると薄い壁(レーン壁 8px・弧 20px)を突き抜ける。
- 天辺の弧は静止セグメントで近似する。弧の右端は盤面の外(x>480)まで出す。
レーンの中に端が残ると、登ってきた玉が端に下から当たって跳ね返り、盤面へ出られない。
- **レーンの蓋(一方通行)**。玉が盤面へ出た瞬間、レーンの口に蓋を閉じる
(`collisionFilter.mask` を 0 → 全部に切り替える)。跳ね返ってきた玉がレーンに
落ち戻ると、井戸の底で止まって狐から遠く、静止検知まで 10 秒近くかかった。
蓋は左下がりのくさび形にする。平らな板だと天辺を右へ戻ってきた玉が板の上に
載って右上の隅で止まった。
- ポップバンパーは衝突した瞬間に玉を中心から外向きへ**一定速度**(9px/step)で弾く。
反発係数で表現すると速度が発散したり減衰したりして安定しない。弾く向きに僅かな
乱れ(±0.35rad)を混ぜて、同じ引きでも毎回違う軌道になるようにする(乱数は
`build(Matter, { rnd })` で注入でき、検証はシード付き)。
- 床は中央の穴へ向かう**2枚の斜面(台形)**。薄い板だと板の下や外側へ落ちた玉が
床で止まって穴に入らなかった。右の斜面はレーン壁の手前で止める(レーンに
食い込むと、井戸に引き下げた玉が斜面の上で止まって放てない)。
- 左右のスリングショット(三角)は壁に張り付け、下の頂点を斜面の上に載せる。
壁との間に隙間があると、そこへ落ちた玉が斜面の上で詰まった。
- バンパーは玉の軌跡(`--trace`)を見て道筋の上に置く。強く放った玉は弧を回りきって
左壁に着く(42,182)、中くらいは弧を離れて斜めに落ちる(100,240)、弱いと
右上から中央へ落ちる(290,270)。
- 玉が止まったら(`createSettleDetector`)物音で狐が起きる。詰まりの押し(8s)、
起こし(14s)、フェイルセーフ(20s)。押しはまだ跳ね回っている玉には触らない
(長いラリーの途中で速度を書き換えると不自然)。止まった玉は静止検知が先に
起こすので押しはほぼ保険。起こしの 14s は掃引の最遅到達(11.0s)に余裕を足したもの。
- ヘッドレス検証は `web/scripts/simulate-omikuji-pinball.js`。引き 11 段階 × シード
(既定 6、`--seeds 30` で 330 点)を掃引し、狐への到達秒数・バンパー回数・
無操作で装置が動かないことを確認する。狐に届かず静まった場合は、止まった場所が
穴の中でなければ失敗にする(どこかの棚に載ったまま終わる演出を見逃さない)。
GEO を触ったら必ず回す。

### デプロイ

- `omikujiGo` は HTTP 関数として dev/prod 両ワークフローでデプロイ(`sanpaiGo` と同型。
Expand Down
5 changes: 3 additions & 2 deletions web/components/omikujiMachines.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// TIMELINE : { nudgeMs, wakeMs, failsafeMs } 詰まり時のフォールバック時刻
// wakeLabels : fox-sensor に触れたら狐が起きるボディのラベル
// grabFilter : 指でつまめるものの collisionFilter(MouseConstraint 用)
// build(Matter) : 世界を組む。{ engine, world, ...handles }
// build(Matter, opts?): 世界を組む。{ engine, world, ...handles }。opts.rnd で乱数を注入可(検証用)
// pulseAt(built): 儀式完了の波紋を出す論理座標 { x, y }
// createRitual(Matter, built): { step(dragging) → 儀式完了で true }
// fallbackRitual(Matter, built, ritual): 「うまくできないとき」の代替操作。
Expand All @@ -26,8 +26,9 @@
// 抽選の正しさは装置に依存しない(狐の最終着地は omikujiFox.js)。
const bell = require("./omikujiMachine");
const slingshot = require("./omikujiSlingshot");
const pinball = require("./omikujiPinball");

const ALL = { bell, slingshot };
const ALL = { bell, slingshot, pinball };
const IDS = Object.keys(ALL);

function byId(id) {
Expand Down
Loading
Loading