脱出速度を超えて宇宙へ進出するクソアプリ

[クソアプリ Advent Calendar 2022](https://qiita.com/advent-calendar/2022/kuso-app) 16日目の記事です。

# 作成したものはこちら

https://cosmic.vercel.app/

# 脱出速度とは

ざっくりまとめると、重力から脱出するために必要な速度のことです。
多用されるものに第一宇宙速度、第二宇宙速度、第三宇宙速度とやらがあるらしく、それぞれ

**第一宇宙速度: 地球の周りを地面に落下せずに飛び続けられる速度**
**第二宇宙速度: 地球の重力を振り払って、地球表面から脱出できる速度**
**第三宇宙速度: 太陽の重力を振り切って、太陽系から脱出できる速度**

らしいです。（細かい箇所誤りあったらすみません）

最近、水●の魔女にハマっている自分としてはワクワクする概念です。

宇宙はロマンの塊ですが、実際に行くのは難しいでしょう。
そこで気分だけでも味わえるWebアプリを作ってみました。

# いざから飛び立とう

内容はこんな感じです。

![cosmic.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521898/cd82cda6-6c73-0b14-74d5-c877b85ed70b.gif)

地球の周りをロケットがグルグル回っています。
ロケットのスピードの初期値は「秒速8km ≒ 第一宇宙速度」です。
gifでは1000倍速なのでグルグル回っていますが、画面を開いた直後はとてもゆっくり回っています。

というのも、地球の円周は約40,000kmであり、秒速8kmで飛んでいたとしても、40,000 / 8 = 5000秒、つまり1.4時間ほどかかるためです。
地球は大きいですね。

このままだととてもゆっくり動くだけでつまらないので、「ロケットを加速」ボタンで秒速を1kmずつ加速することができます。
また、ロケットの速度が秒速11.6km（つまり秒速12km以上）になると第二宇宙速度を超え、地球の重力を振り切ることができます。
そうすると速度が上がるにつれてロケットの飛行高度がどんどん上がってきます。

秒速400knほどになるとこのくらいロケットの高度が上がります。
かなり地球から旅立っていますね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521898/d32dbea1-bbd5-dd76-304a-6ab8c089a6ff.png)

加えて、ロケットの動きがゆっくり過ぎてつまらないので、倍速ボタンを設置しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521898/847758fc-fa54-9f7b-25a1-323f3ed618c0.png)
1000倍にするとロケットが分身するので、ぜひ確認してみてください。

このようにして地球を飛び出して宇宙を目指しましょう。
ぜひ画面上から消えるくらいスピードの世界に突入してみてください。

# 実装

今回はNext.jsを使用して開発しました。
アニメーションを使いたかったので、[Framer Motion](https://www.framer.com/motion/)を使用して動きを作りました。

まずは地球を回転させるコードです。
jsx部分に以下のようなコードを入れることで回転する地球画像を表示しています。
```javascript
<motion.div
  // 360°回転させる
  animate={{
    rotate: 360,
  }}
  transition={{
    // 60秒で一周回転させる。
    // 本来はstateとして一周の時間を状態として持つ
    duration: 60,
    // アニメーションを無限にループさせる
    repeat: Infinity,
    // アニメーションの動きを直線的な動きにする
    ease: 'linear',
  }}
>
  <Image src="/earth.png" alt="earth" width={300} height={300} />
</motion.div>
```

ロケット部分も同様のコードになっています。
正方形のdivの四隅にロケット画像を配置することで、回転しているように見せかけています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521898/85eb2a61-9e27-125c-873e-834264ca79a3.png)

また、ロケットのスピードや倍率を操作するボタンは以下のように実装しています。
（もう少し綺麗にしたい、、、）

```javascript
// 倍速設定
const [timeSpeed, setTimeSpeed] = useState(1);
// ロケットのスピード
const [speed, setSpeed] = useState(8);
// 地球は1周約40,000kmで、画面上での地球一周の時間は距離 / 速度 / 倍率
const distance = 40000;
const [duration, setDuration] = useState(distance / speed / timeSpeed);

// 1日は86400秒で画面上での地球の改善速度は86400秒 / 倍率
const oneDay = 86400;
const [earthDuration, setEarthDuration] = useState(oneDay / timeSpeed);

// ロケットの飛行高度
const [rocketHeight, setRocketHeight] = useState(400);

...省略

<input
  type="button"
  value="ロケットを加速"
  onClick={() => {
    // ボタンを押すと秒速1km追加
    const newSpeed = speed + 1;
    setSpeed(newSpeed);
    setDuration(distance / newSpeed / timeSpeed);
    // 第二宇宙速度を超えると高度を上げる
    if (newSpeed > 11.2) {
      setRocketHeight(389 + newSpeed);
    }
  }}
/>
<input
  type="button"
  value="1倍速"
  onClick={() => {
    const newTimeSpeed = 1;
    setTimeSpeed(newTimeSpeed);
    setDuration(distance / speed / newTimeSpeed);
    setEarthDuration(oneDay / newTimeSpeed);
  }}
/>
...省略
```

# 作ってみて
やはり宇宙はスケールが大きいことを実感しました。
何十年後でも宇宙旅行ができるようになることを待ち遠しく思います。

# 改善点
最大の問題として、ロケットを加速させたり倍率を変更すると、地球やロケットが再描画されてしまうため、最初の初期位置に戻ってしまいます。
再描画時点でのrotateの情報を引き継ぎたいのですが、ちょっとわからなかったので暇があれば今後改善していきたいポイントです。

# 参考
- [Framer Motion](https://www.framer.com/motion/)