音ゲーを0から作ろうとしたら健康になれた話


<br />
こんにちは、Watanabe Jin(@Sicut_study)です。

![IMG_3545.JPEG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/d98d946f-9f86-8d77-006c-3533943b6fef.jpeg)

突然ですが、みなさんは健康でしょうか？
私は今年27歳になったのですが、健康診断が大荒れしています。

![IMG_3534.JPEG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/2b9cc1f2-bdf7-06e9-6a06-5539f6367a71.jpeg)

4年前に視力が右2.0、左1.8あったのですが、**<font color="blue">右0.7、左0.5まで落ちてしまいました**</font>
このままのペースで進むと10年後には視力が-0.5になってしまいます。
<br />

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/5887a06d-3a83-5321-7b9d-24682e499228.png)

このままのペースで低下すると2030年には視力が-0.7になってしまいます。
**おそらくエンジニアとして毎日パソコンに向かっているのが原因です。**

以前、アイトレーニングを1ヶ月1時間やるチャレンジをして努力をすれば視力が上がることがわかっています。
(検証動画を実際に投稿しました)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/12d0926c-a213-fae2-1675-3089e1de3bc0.png)

アイトレーニングは効果があるのですが、毎日1時間やるのは面白みがなく辛かったです。
そこで思いつきました。
<font color="red">**視力検査とリズムゲームを組み合わせたら退屈な視力検査も楽しめるのではないか？**</font>

![名称未設定のデザイン (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/c25600b1-2621-2194-4753-b53d4b17aa95.png)

そこで今回は、次回の健康診断で無双するために、<font color="red">**健康になるリズムゲームをReactで実装してみたいと思います。**</font>

# 「リズムゲーム」を開発してみよう

![IMG_3546.JPEG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/3974b5ed-8277-1750-bed2-ae7a64bae3af.jpeg)

まずはネットでReactを使ってリズムゲームを作っている前提を調べました。
**調べた感じでは参考になりそうな記事がなかったので、0から設計していきます。**

MPV(Minimum Viable Product)を3つに分けて実装していく方針を立てました。

#### MVP1 : ランドルト環が出現する(矢印キーで判定する)

まずはランドルト環を出現させて、正しい方向の矢印キーを押すとポイントが手に入る基本の部分を実装していきます。

![IMG_3537.JPEG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/2765ea2a-5a9d-97b0-a6f1-153bfa7ed66f.jpeg)

`setInterval`を活用して一定時間だけ出現、時間に合わせてサイズを変更するアニメーションをつけました。

```tsx
  useEffect(() => {
    if (isStarted) {
      const timings = [1000, 5000, 15000]; // 1秒、5秒、15秒で出す
      const timeouts: Array<number> = [];

      timings.forEach((timing) => {
        const timeoutId = setTimeout(() => {
          setCircleSize(0); // 最初は円が見えない
          setIsCircleVisible(true);

          const startTime = performance.now();
          const animationId = requestAnimationFrame(function animate(time) {
            const progress = (time - startTime) / 1000;
            setCircleSize(progress * 100);

            if (progress < 1) {
              requestAnimationFrame(animate); //徐々に円を大きくする
            } else {
              setTimeout(() => {
                setIsCircleVisible(false);
              }, 2000); // 2秒でさいだいになｒ
            }
          });

          return () => {
            cancelAnimationFrame(animationId);
          };
        }, timing);

        timeouts.push(timeoutId);
      });

      return () => {
        timeouts.forEach((timeoutId) => clearTimeout(timeoutId));
      };
    }
  }, [isStarted]);
  ```
<br />

<font color="blue">**スタートボタンを押すと、徐々にランドルト環がでてくるようにできました。**</font>

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/19009516-5f15-e9ec-3e25-f79480c6d5ee.gif" width="800px" />

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/41d2e2f6-cdb3-d5e4-9545-d7c21565f792.png)

#### MVP2 : 音楽に合わせて出現する

MVP1でそれっぽいゲームができたので次は音楽に合わせて出していきます。
今回は「シャイニングスター」という曲を使います。

https://maou.audio/14_shining_star/

どのタイミングで出せばいいのかわからないので、ChatGPTに聞いています。

```
リズムゲームのタイミングを計算するには、曲のテンポ（BPM: Beats Per Minute）を知る必要があります。一般的に、BPMに基づいてリズムゲームのノーツが配置されます。「シャイニングスター」の場合、BPMを測定し、そのBPMに基づいて秒数を計算します。

まずは「シャイニングスター」のBPMを調べ、そこから適切なタイミングを割り出します。少々お待ちください。

「シャイニングスター」のBPMを150と仮定して、1番のリズムゲームのノーツ配置に最適なタイミングを計算しました。以下の秒数に合わせてノーツを配置すると、曲に合ったリズムゲームが作れると思います。

タイミング（秒）:

0.0
0.4
0.8
```

BPMを解析して教えてくれました。ここまでできるのがすごすぎる。
あとはこのリズムに合わせていい感じにランドルト環を表示します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/331e9baa-ef7a-df1f-6804-973aba63a800.gif" width="800px" />

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/969194af-f9b4-bc31-5180-15526f39d14e.png)


視力も選べるようにしたので、その日の気分難易度選ぶことができます。

```tsx
        <select
          onChange={(e) => setSelectedSize(Number(e.target.value))}
          className="bg-gray-800 text-white p-2 rounded-lg"
        >
          <option value={100}>視力1.0</option>
          <option value={120}>視力0.9</option>
          <option value={140}>視力0.8</option>
          <option value={160}>視力0.7</option>
          <option value={180}>視力0.6</option>
          <option value={200}>視力0.5</option>
          <option value={220}>視力0.4</option>
          <option value={240}>視力0.3</option>
          <option value={260}>視力0.2</option>
          <option value={280}>視力0.1</option>
        </select>
```

#### MVP3 : 5ptで豪華演出になる

太鼓の達人の盛り上がった演出を取り入れてみようと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/5c4b83a9-e96c-ad1c-75ca-17baae6135b8.png)

やり方は簡単です。「5pt手に入ったら背景を映像に変えるだけです」

```tsx
  return (
    <div
      className="flex flex-col items-center justify-center min-h-screen text-white"
      style={{
        background: backgroundChanged
          ? "none"
          : "linear-gradient(to bottom right, #48c6ef, #6f86d6)",
      }}
    >
      {backgroundChanged && (
        <video
          autoPlay
          loop
          muted
          className="absolute inset-0 object-cover w-full h-full"
        >
          <source src="background.mp4" type="video/mp4" />
        </video>
      )}
      <audio ref={audioRef} src="song.mp3" />
      <div
        className="relative flex items-center justify-center z-10"
        style={{
          width: `${selectedSize}px`,
          height: `${selectedSize}px`,
        }}
      >
```

実際にどんな演出になっているかは最後の動画をご覧ください！

# 視力検査に必要なものを用意する

![IMG_3541.JPEG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/abebd69b-79b4-c416-a333-d0b59ee80468.jpeg)

**視力検査に必要な道具を作ります**
私の家には「黒いスプーンがありません」

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/aba7b2a5-f284-09be-471e-c6bde8835e86.png)

今の御時世、一家に一つはあるほうがよいのですが、今回はなかったので自作します。

![IMG_3542.JPEG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/409f5b53-c64f-4f55-a23d-5bed72dc7076.jpeg)

<font color="blue">**サングラスを改造して簡易的なものを作成しました**</font>

![IMG_3543.JPEG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/ca232ccf-0f77-3045-4a7d-ab51020430d3.jpeg)

![IMG_3544.JPEG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/8fadc3bc-ca8f-4898-cf38-69e6476fca81.jpeg)

### <font color="red">**イメージ通りにできました**</font>

ゲームには無線のコントローラーが必要なのですがなかったので、**発掘したキーボードを代用します**

![IMG_3552.JPEG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/cfa9ad35-3b81-e5cb-4b8b-48496f615a83.jpeg)

# 作成したゲームを遊んでみる

![IMG_3547.JPEG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/6d15d35c-8e08-3946-75a6-e75891e60638.jpeg)

それでは実際にプレイしていきます。
こちらは動画でみていただきたいので、以下をご覧ください！(3:33〜)

https://www.youtube.com/watch?v=RGN9MUcBdXE

<br />
<br />
<br />

![IMG_3548.JPEG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/d8a289e5-7cd0-b094-e30d-07d6d08b53b3.jpeg)

<br />

<div style="display: flex; align-items: center;">
  <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/36691d10-ae4e-345c-7c8a-90c677bbf67e.png" width="80px">
  <font>　ふう、いい汗をかけた。視力も少し良くなった気がする！</font>
</div>

<div style="display: flex; align-items: center;">
  <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/36691d10-ae4e-345c-7c8a-90c677bbf67e.png" width="80px">
  <font>　あとは毎日継続して遊んでいくだけだぞ！！</font>
</div>

<div style="display: flex; align-items: center;">
  <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/36691d10-ae4e-345c-7c8a-90c677bbf67e.png" width="80px">
  <font>　・・・</font>
</div>

<div style="display: flex; align-items: center;">
  <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/36691d10-ae4e-345c-7c8a-90c677bbf67e.png" width="80px">
  <font>　あっ</font>
</div>

![IMG_3551.JPEG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/5127db55-11c7-6784-3f19-493904fbfd28.jpeg)
<br />

<div style="display: flex; align-items: center;">
  <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/36691d10-ae4e-345c-7c8a-90c677bbf67e.png" width="80px">
  <font>　ゲーム遊んでたら視力悪くなるじゃん・・・</font>
</div>

![視力検査ゲーム VS 視力トレーニング.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/75f518e2-bafb-54cc-a739-992aa284d43a.png)

# おわりに

今回はいつもと違ったテイストでお送りしました。
プログラミングを学べば数時間程度で楽しく好きなものを作れますので、ぜひともみなさんも個人開発挑戦してみてください。

今回の記事は動画にもしていますのでよければご覧ください！

https://www.youtube.com/watch?v=RGN9MUcBdXE

ここまで読んでいただけた方はいいねとストックよろしくお願いします。
@Sicut_study をフォローいただけるととてもうれしく思います。

普段はTwitterでエンジニアに関する情報を発信していますのでよければ友達になってください👇

https://x.com/Sicut_study

また明日の記事でお会いしましょう！

# JISOUのメンバー募集中！
プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか？

興味のある方は、ぜひホームページからお気軽にご連絡ください！
▼▼▼

https://projisou.jp