ポートフォリオには行かせない

https://github.com/ibuki3268/try_solo_ibuki

Next.js

TypeScript

VSCode

ポートフォリオに遷移するための利用規約に同意するゲーム

いぶき

推しアイデア

ミニゲームの数を作って色んな形の同意するゲームを作り難易度もばらけている

作った背景

ポートフォリオサイトを作るだけだと面白くないと思った結果こっちがメインになった

推し技術

Hooks useRef(メモリ参照保持)- 爆発音タイマー追跡

プロジェクト詳細

ポートフォリオには行かせない!

ポートフォリオに遷移していくものを利用規約に同意させないように妨害があるといった形のゲームです

使用技術

NEXT.js(TS) デプロイ先vercel ReactDOM tailwind/postcss ESLint Web Audio API

使って無理で諦めたもの NFC関係 NFCリーダー RC-S300 pccdデーモン/Node.js NFC通信関係

さんの要素 失敗は三回まで NFCができたらNFC1枚ごとに三回読み込ませて別のカードにしないとそれ以降は挑戦できないようにとか考えてた

利用規約一覧

article: "第1条", title: "利用者の姿勢について", items: [ "(1) 利用者は本ゲームを楽しむ姿勢で臨みます。", "(2) 利用者はクリア後に到達するポートフォリオが突貫のしょぼい物でも、苦言を呈さないと誓います。", "(3) 利用者は途中で不機嫌にならず、最後まで同意の姿勢を保ち、同意されない場合はプレイできません。", "(4) 利用者は必ず以後の利用規約を読みます。", ], }, { article: "第2条", title: "開発者への配慮について", items: [ "(1) 利用者は本ゲームを遊ぶ際、開発者の努力に敬意を払います。", "(2) 利用者は開発者も人間であることを理解し、些細な不具合や誤字脱字には目をつむります。", "(3) 利用者は開発者への連絡を行う場合、穏やかな文面を心がけます。", "(4) 利用者は文句がある場合でもピキることなく論理的に伝えます。", ], }, { article: "第3条", title: "不具合に対する姿勢について", items: [ "(1) 利用者は細かなバグや不具合があった場合、煽らずに開発者へ伝えます。", "(2) 利用者は脆弱性やセキュリティに関する指摘は、語気を抑えて伝えると誓います。", "(3) 利用者は再現手順が分かる場合、可能な範囲で補足情報を添えます。", "(4) 利用者は改善点の提案を行う際、代替案を添えて伝えます。", ], }, { article: "第4条", title: "体験の共有について", items: [ "(1) 利用者がゲーム体験をSNS等で共有する場合、開発者をクレジットします。", "(2) 利用者はクリアスクリーンショット等の共有時に、ハッシュタグを付けて応援します。", "(3) 利用者はネタバレ的な内容の共有の際には注意し、他のプレイヤーに配慮します。", "(4) 利用者は友人や知人への口コミを通じて、本ゲームの認知拡大に協力します。", ], }, { article: "第5条", title: "ゲームプレイについて", items: [ "(1) 利用者は本ゲームの難易度や結果に対し、キレてはいけません。", "(2) 利用者は仕様に文句があっても暴言を吐かないことを誓います。", "(3) 利用者は本ゲームをプレイ中、他者の睡眠を妨害しないよう配慮します。", "(4) 利用者は負けて悔しい場合でも、壁を殴ることなく再挑戦を誓います。", ], }, { article: "第6条", title: "個人情報の取扱いについて", items: [ "(1) 利用者が個人情報を入力する場合、その情報の責任は利用者が負います。", "(2) 利用者はふざけて個人情報を入力した場合自身の愚かさを悔います。", "(3) 利用者は本ゲーム内に入力した情報の削除要求を行うことができます。", "(4) 利用者は個人情報を入力する場所はないだろというツッコミをしないことを誓います。", ], }, { article: "第7条", title: "ゲームデータの扱いについて", items: [ "(1) 利用者が成績やスコアをSNSで共有する場合、その責任は利用者が負います。", "(2) 利用者のゲームデータは開発サーバーに保存される場合があります。", "(3) 利用者は保存するゲームデータなんてないだろと思いません。", "(4) 開発者はゲームデータの損失についての責任を負いません。", ], }, { article: "第8条", title: "不正行為について", items: [ "(1) 利用者はゲーム内での不正行為(チート等)を行いません。", "(2) 利用者は利用規約に違反する行為をしません。", "(3) 利用者は不正行為による処遇に異議を唱えないと誓います。", "(4) 利用者はこの利用規約にたどり着く前に規約に同意することを誓っているので異議は認められません。", ], }, { article: "第9条", title: "知的財産権について", items: [ "(1) 本ゲームの全著作権は開発者に帰属します。", "(2) 利用者は本ゲームを無許可で複製・配布しません。", "(3) 利用者は本ゲームのコードを逆解析・改変しません。", "(4) 利用者による実況動画等での利用は、開発者をクレジットすれば認めます。", ], }, { article: "第10条", title: "損害賠償について", items: [ "(1) 利用者は不正行為(チート)を用いた場合開発者に損害賠償としてハックを支払います。", "(2) 本ゲームは現状のまま提供され、明示的な保証はありません。", "(3) 利用者が本ゲーム利用時に受けた身体的・精神的損害の責任は負いません。", "(4) 利用者はこれらの条件に同意し、ゲームプレイをプレイし終えます。", ],

各ゲームの動き

19種類のゲームの動きについてすべてまとめています 細かい記載がないものは基本的に他のゲームの動きと近しいものです ※利用規約追加したのとクリアしたらライフが減るとかいうとんでもエラー吐いてリデプロイしてもどしたので一部写真と違います

1. 基本の同意 (BasicAgree)

image 同意するシンプルなもの 使用Hooks: なし(最小実装) onClick={onSuccess} だけで完全

2.逃げる同意 (EscapeButton)

image マウスから同意が逃げるため一定回数追いかけると停止し、同意できる useState: - attempts: number マウスオーバー回数(0→1→2→3→4→5) useRef:
doneRef: boolean ゲーム終了フラグ(二重実行防止) containerRef: HTMLDiv ゲーム領域 DOM 参照 lastMoveRef: number 最後の移動時刻 useMeo: - hint: string attempts に応じてメッセージ変更

3. タイミング同意 (TimingGame)

image ゲージに合わせてタイミングよく同意する useState: - position: number ゲージ位置(0~100) useRef: - directionRef: 1 | -1 ゲージの方向(上昇/下降) doneRef: boolean ゲーム終了フラグ intervalRef: Interval ゲージ更新用 interval timeoutRef: Timeout タイムリミット用 timeout useCallback: finish() success/failure 分岐

4. 連打同意 (RapidClick)

image 指定回数同意する useState count: number クリック回数 timeLeft: number 残り秒数 useRef: doneRef: boolean ゲーム終了フラグ countRef: number 最新のクリック数(useState の遅延対策) onSuccessRef: func onSuccess の最新参照 onFailureRef: func onFailure の最新参照

5.長押し (LongPress)

image 同意し続ける(指定時間)するとクリア判定になるのでそれまで押し続ける useState pressTime: number // マウスダウンからの経過時間 useRef startTimeRef: number // マウスダウン時刻 intervalRef: Interval // 進捗更新用 interval

6.クリッカー(Clicker)

image 指定回数クリックする

7.計算問題

image 計算問題の答えを入力して同意する useState:問題データ 選択肢

8.記憶力テスト

image 順番に光るためそれを記憶して同じ順で押し同意とする useState: step: number ユーザーの進捗(0/4 → 1/4 → ... → 4/4) revealing: boolean シーケンス再生中フラグ activeId: string|null   現在点灯中のタイル ID

useRef: doneRef: boolean ゲーム終了フラグ useMemo: sequence: string[] ランダム 4 色シーケンス(初回のみ再生) useEffect: の中で timeout の連鎖(再生シーケンス)

9.反射同意

image 色が変わった瞬間同意を押す 一度目の遷移時は規約を読む時間があり、白から緑色に変わった瞬間同意する 時間が短く判定がシビアになっている

10.二択同意

image 二択の選択肢が出てきて同意する 正解側の判定を押せばクリア

11.色合わせ

image 指定の色を押せばクリア

12.迷路ゲーム

image 初期化 プレイヤーが座標 (0, 0) から開始 矢印キー入力 ↑ ArrowUp:y座標を -1 ↓ ArrowDown:y座標を +1 ← ArrowLeft:x座標を -1 → ArrowRight:x座標を +1 移動可能性チェック移動できない場合: 迷路の範囲外へ移動しようとした 目標位置が壁(MAZE[y][x] === 1) 上記に該当しない → 移動実行 プレイヤー位置が (9, 9) に到達 → onSuccess() 呼び出し

13.文字探しゲーム

image お題で出された熟語を中から探して同意する

UseEffectでタイマーを動かしてその周辺の依存配列: [found, onFailure] found が true → タイマー停止 found が false → タイマーで秒数カウント

14.スロットマシン

image 三つのスロットを目押しして同じのを揃えられたら同意扱い useState: 状態管理 step number ユーザーの進捗(0/4 → 1/4 → 2/4 → 3/4 → 4/4(クリア)) revealing boolean シーケンス再生中フラグ(true: 観察中、false: ユーザー入力待機中) activeId string | null 現在点灯中のタイル ID(emerald, sky, rose, amber) useRef: 参照管理 doneRef boolean ゲーム終了フラグ(成功/失敗時に true に設定して多重判定を防止) sequence string[] ランダム 4 色シーケンス(初回マウント時のみ生成、以降不変) useEffect: シーケンス再生ロジック タイムアウトの連鎖により、シーケンスを順序通りに点灯再生。

記憶力とタイミング精度が必要

15.スライドパズル

image よくあるスライドしていくタイプのゲーム 1~15までを順番通りに揃えたら同意扱い

特徴的な実装 15パズル解法可能性保証:シャッフル時に「後戻り禁止」ルールを適用して、全ての初期状態が解可能であることを保証 空白タイルの移動可能性:4 方向(上下左右)から隣接するタイルのみスワップ可能 完成チェック:毎回のスワップ後に完成判定を実行

16.リズムゲー (RhythmGame)

image useRef: doneRef: boolean ゲーム終了フラグ gameStartRef: number ゲーム開始時刻 notesSequenceRef: Note[] 12 個のノーツ(時刻付き)
useState: hitNotes: Set くstring> クリック済みノーツ ID score: number スコア(0~240) timeLeft: number 残り時間(秒) gameActive: boolean ゲーム進行中フラグ judgeDisplay: string 「🟩 Perfect!」表示 useRef: judgeTimeoutRef: Timeout 判定表示 800ms タイムアウト

17.同意不同意グループ分け

image それぞれがグループ化されており正しいものにドラッグアンドドロップ ニュアンスがポジティブかネガティブかの主観的なものでグループは決めてある ※ローカルで開発してたのがエラーはいてリデプロイしなおしたので違うことになってます

18 .チェスボード

image ナイトの駒を四つ見つけてクリックすることで同意とする 背景色と近しくて見づらくなっているのは意図的 usestateとuserefで管理

19.

image

クリア画面

image

失敗画面

image AudioAPIで爆発音などの演出

NFCのカードリーダーも実装しようとしたんですけど接続か対応してないかで上手くいかなかったです https://github.com/ibuki3268/try_solo_ibuki/tree/NFC ここに戦った跡が残ってます pccdデーモンとNode.jsでサーバーを動かしてNFCの反応を読み取り、それをNEXTのプロジェクトに渡そうとしてたんですがうまくいきませんでした

以下 全ゲーム共通↓ なんか空白が消えないので下に持ってきました 気にしないで見てください

パターン使用理由
doneRef非同期実行時に二重実行防止
xxxRef = value で state 同時更新setState() の遅延対応
useEffect の cleanupinterval/timeout 削除
useRef で DOM参照getBoundingClientRect() などに必要
useMemo で一度だけ計算ゲーム初期化を一回限りに

いぶき

@ibuki