ピン刺しゲーム
回転する円盤に針を刺し、他の針と衝突させずに 10 ステージのスピード勝負を制覇しよう
ピン刺しゲームとは?
ピン刺しは、スマホで人気の AA や Pin Out と同系統のカジュアルゲームです。画面中央で白い円盤が一定速度で回転しており、下から針を 1 本ずつ発射して、すでに刺さっている針に当てずに円盤に刺していきます。各ステージには発射本数が決まっていて、すべて成功すれば次のステージへ。1 度でも衝突するとその場でゲームオーバーになります。ルール自体は数秒で覚えられるほどシンプルですが、進むほど隙間は狭く回転は速くなり、タイミング判断と冷静さが試される本格的なミニゲームになります。本ツールはブラウザ内だけで完結し、登録もダウンロードも不要。PC ではマウスクリック、スマホでは画面タップで遊べます。
使い方
操作手順
- ページを開くとステージ 1 から自動的に開始し、円盤が回り始めます
- ゲームエリアをクリック(またはスペースキー/Enter キーを押す)して針を発射します
- 針は中心へ向かって飛び円盤に刺さります。すでに刺さっている針には当てないようにします
- そのステージの針をすべて安全に刺せばクリアとなり、自動で次のステージへ進みます
- 1 度でも衝突するとその場で失敗です。「このステージをやり直す」または「最初からやり直す」を選んでください(注意:失敗画面でスペース/Enter を押すと「最初からやり直す」が動作してステージ 1 に戻ります。「このステージをやり直す」にキーボードのショートカットはありません。同じステージを再挑戦したい場合はボタンをクリックしてください)
クリアのコツ
- 円盤は一定速度で回転するので、クリックの速さよりリズム重視。隙間の中央線を狙ってください。
- 隣の針が通り過ぎた瞬間に発射するのがコツです。針の飛行に約 120 ミリ秒かかるので少し早めに撃ちましょう。
- 連続クリックすると最大 3 発までキューに入って順に飛びます。3 発を超えた分は破棄されるので、前の針が刺さるまで連打しても無駄です。
- 後半ほど隙間が狭く回転も速くなります。無理に押し込むより、危ないと思ったら 1 発見送る方が安全です。
ステージ別の難易度
- ステージ 1〜3:針が多く隙間も広めで、操作リズムをつかむ段階。
- ステージ 4〜7:円盤上の針が増え、回転を予測する必要があります。
- ステージ 8〜10:円盤がほぼ埋まり、すべての針でタイミングを正確に合わせる必要があります。
活用シーン
技術的な仕組み
メインループは requestAnimationFrame で駆動されます。毎フレーム内部の rotation を固定の speed 値(度/フレーム)だけ加算し、刺さっているすべての針要素を走査して transform を rotate(baseAngle + rotation) に設定します。transform は合成レイヤーのプロパティなので、ブラウザは回転処理を GPU の合成スレッドに任せ、レイアウトや再描画を発生させません。そのため最終ステージで 15 本すべての針が同時に回転していても 60fps を維持できます。 当たり判定は「角度差をコード長に変換する」方式です。刺さっている針はそれぞれ円盤座標系での baseAngle で表されます(円盤に対する固定オフセットで、回転の影響を受けません)。新しく発射された針が中心に到達したとき、ワールド座標での角度は TARGET_ANGLE = 0 で、円盤座標系では normalizeAngle(0 - rotation) になります。次にこの新 baseAngle を既存の各 baseAngle と比較し、角度差 Δθ を 2R·sin(Δθ/2) の弦長(針先の点同士の中心間距離。R = 111px は各針先の点の中心から円盤中心までの距離)に変換します。値が 24px のしきい値を下回れば衝突と判定し、ラウンド終了です。 発射動作は小さな状態機械で制御します。shootLocked は飛行中の針をマークし、transitionend イベントとフォールバック用 setTimeout(180 ミリ秒)が同じ発射を二重に確定するのを防ぎます。CSS transition は 120ms で進行し、180ms の setTimeout は transitionend が稀に発火しない場合(例えば、トランジションが完了する前に DOM が変更された場合)の保険として用意されています。pendingShots は飛行中に出されたクリック要求をバッファし、最大 3 発までに制限します。3 発を超えたクリックは破棄され(キューには入りません)、これでテンポの良い連射感を保ちつつ、複数の針が同時に中心へ向かうのを防ぎます。失敗・クリアともに gameOver を true にし、メインループは動き続けますが rotation の更新だけ止まり、画面が止まったように見えます。 表示スケールについては、ゲーム本体は 420×720 の固定設計サイズを保ち、外側のラッパーがビューポートサイズからスケール係数を計算して transform: scale で適用します。現在の実装ではスケール上限を 1 としており、小さなビューポートは比例して縮小されますが、デスクトップのビューポートは元のサイズを維持し、それ以上拡大されることはありません。これにより当たり判定は常に設計座標系で行われ、ピクセル単位のしきい値も 1 セットで済むので、判定はどの画面でも同一になります。
- メインループ:requestAnimationFrame、毎フレーム rotation += speed、すべての針に transform: rotate(baseAngle + rotation) を適用。
- GPU アクセラレーション:回転には left/top ではなく transform を使用。ブラウザの合成スレッドが処理し、レイアウト/再描画は発生しません。
- 当たり判定:ワールド座標の 0° を円盤座標へ normalizeAngle(0 - rotation) で逆算し、弦長 2R·sin(Δθ/2) を 24px のしきい値と比較。
- 状態機械:shootLocked で二重確定を防ぎ、pendingShots は上限 3 発で超過分は破棄(キューには入らず)、gameOver 後は rotation 更新を停止。
- 確定コールバック:120ms の CSS 飛行、transitionend を主結算とし、180ms の setTimeout を transitionend が稀に発火しない場合の保険として併用。
- スケーリング:420×720 の固定設計座標系を採用し、ラッパーがビューポートサイズに応じて transform: scale を適用。スケール上限は 1 で、デスクトップは拡大せず元のサイズを維持。
- データ保存:localStorage にベストクリアステージのみを記録。アップロードもアカウントも順位表もありません。
サンプル
10 ステージの速度と針数の設定
ステージ 初期針数 発射本数 回転速度(deg/frame)
1 2 8 1.35
2 3 9 1.50
3 3 10 1.65
4 4 11 1.80
5 4 12 2.00
6 5 13 2.20
7 5 14 2.45
8 6 15 2.70
9 7 15 3.00
10 8 15 3.35典型的な 1 局:ステージ 5 で失敗
ステージ 5:初期針 4 本、発射 12 本。
第 1〜7 発:順調に隙間へ刺さり、残り 5 発。
第 8 発:前の針が刺さりきる前に焦って発射。
判定:新しい baseAngle は第 6 発から 8°、DOT_HIT_DISTANCE 未満。
結果:衝突し、ラウンド終了で「ゲームオーバー!」が表示。
「このステージをやり直す」を押せばステージ 5 から再挑戦できます。全ステージクリアの結果
クリアタイム:約 2 分 40 秒
累計発射:117 本
失敗回数:3
ベスト記録:ステージ 10
メッセージ:「全ステージクリア!」、ボタンは「もう一度遊ぶ」。
ベスト記録は localStorage に保存され、ページを再読み込みしても残ります。よくある質問
空いているところを撃ったのに失敗するのはなぜ?
針は瞬時に届くわけではなく、クリックから実際に円盤に接触するまで約 120 ミリ秒かかります。その間も円盤は回り続けているため、クリック時点では十分広かった隙間でも、飛行中に別の針が目標線まで回ってきて、新しい針が乗ってしまうことがあります。対策はシンプルで、隙間が線を通過した直後に発射し、回転分を見越しておくことです。
画面を押し続けて連射できますか?
高速にクリックすることはできます。最大 3 発までキューに入り順に発射されますが、前の針が飛行中の間は次の針が出ません。3 発を超えるクリックは直接破棄され、キューには入りません。後半のステージでは、連打を抑えて 1 本ずつ刺さってから次の発射タイミングを判断するのがおすすめです。
難易度はどのように上がっていきますか?
各ステージごとに回転速度・初期針数・発射本数が個別に設定されています。回転速度はステージ 1 の 1.35 deg/frame からステージ 10 の 3.35 deg/frame まで、約 2.5 倍に上昇します(3 倍には届きません)。初期針数も 2 から 8 まで増え、生き残っている隙間はどんどん狭くなります。後半は手の速さよりも落ち着きが効いてきます。
失敗したら最初から?それとも同じステージから?
どちらも可能ですが、操作方法に注意が必要です。「このステージをやり直す」ボタンを押すと、失敗したステージから針数も速度もそのままで再開します。「最初からやり直す」ボタン、および失敗画面でスペース/Enter キーを押すと、ステージ 1 に戻ります。「このステージをやり直す」にキーボードのショートカットはないので、反射的にスペースで続行しようとするとステージ 1 まで戻ってしまいます。ベスト記録は常に localStorage に残ります。
ゲーム画面が狭く見えるのはなぜ?
設計サイズは 420×720 で、スマホの縦持ち画面に合わせています。スマホでは自然にフルスクリーンになり、PC ではビューポートに合わせて等比スケールで縮小しますが、スケール上限は 1 にロックされているため、デスクトップで大きなウィンドウを使っても 420×720 を超えて拡大されることはありません。ウィンドウサイズが変わっても判定ルールは変わりません。
プレイデータはサーバーに送信されますか?
送信されません。ゲーム全体はブラウザ内で完結し、保存しているのは「ベストクリアステージ」という数字 1 つだけ。これは localStorage に保存されています。サイトデータを削除したりブラウザを変えたりすると消えます。順位表もなく、スコアや操作の記録もこちら側では一切収集していません。
スマホでプレイする際の注意点はありますか?
ブラウザの全画面モードを有効にしておくと、下方向のスワイプで誤ってリロードされるのを防げます。横画面でも遊べますが、縦画面比率の方がオリジナルの操作感に近いです。低スペック端末で多少のフレームドロップが出る場合は、他のタブや重いアニメーションを閉じてみてください。本ゲーム自体は 1 フレームあたりわずかな transform 計算しかしないため、端末への負荷は最小限です。