スマホぶっ壊しシミュレータ（ご安全に！👉️）

:::note info
この記事は、10周年 :tada:  を迎えた [クソアプリ Advent Calendar 2024](https://qiita.com/advent-calendar/2024/kuso-app) の18日目です。
:::

まずは、こちらのデモ動画をご覧ください。

<iframe width="560" height="315" src="https://www.youtube.com/embed/epB3xlQoiGg?si=Tdm0VeI6876OIs_r" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

# これはなに？

**"スマホを落とした際に画面が割れる" 現象を体験できるwebアプリです。**

下記サイトにスマホからアクセスすることで、実際にお試しいただけます。

https://c6tower.github.io/smartphone-crash-simulator/?public

:::note warn
- 下記デバイス && chromeでのみ動作確認済みです
    - Pixel 8: バージョン 15
    - iPhone 13: iOSバージョン 18
- 効果音が上手く再生されない場合、画面を一度タップすることで解消されることがあります
:::

# 仕様

スマホを落とすと "画面がひび割れる" 演出が発生します。

<div style="float">

<img alt="drop smartphone" width=40% src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363036/883ca46a-78ad-ea7b-52a5-8c469d7071a4.png">

<img alt="crashed" width=40% src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363036/fe62645b-e402-c8a5-30d1-3ef68b7188b3.png">

</div>

画面のひび割れ演出は、 **ひび割れ効果音** と **ひび割れ描写** によって実現しています。
スマホへのダメージが大きいほど壮大な（？）効果音になり、スマホの蓄積ダメージが増えるにつれてひび割れ描写は拡大していきます。

詳細は後述しますが、スマホへのダメージは、落下時の高さと衝撃時の向きをもとに計算しています。
（~~なお、高さ計算や衝撃検知ロジックまわりに不具合があるため、そのうち修正します……~~ :see_no_evil:）

# 使用技術

## 全体構成

vue3 + vite + GitHub Pagesを用いたSPAにしています。

この選定について特に強い思想はないですが、viteを使ったvue3アプリケーションの開発体験は良かったです。
ドキュメントがわかりやすく、環境構築からGitHub Pagesへのデプロイまで手軽に対応できました。
hot reloadが爆速であることも嬉しいですね。

https://ja.vite.dev/guide/

https://zenn.dev/c6tower/scraps/d5b82f5b6d4166

## 加速度センサーとジャイロセンサー

スマホの落下・衝撃を検知するために [DeviceMotionEvent](https://developer.mozilla.org/ja/docs/Web/API/DeviceMotionEvent) を使いました。
[Accelerometer](https://developer.mozilla.org/ja/docs/Web/API/Accelerometer) も候補ではありましたが、実装時点（2024-12-07）では実験的な機能とのことで、不採用にしています。

また、 "衝撃時に画面が下向きならばダメージを加算する" 処理のために、 [DeviceOrientationEvent](https://developer.mozilla.org/ja/docs/Web/API/DeviceOrientationEvent) を使って、スマホの向きを取得しています。

なお、Androidでは特に問題なくセンサーを利用できますが、iOS（たしか13以降）ではユーザによる許可が必要なため、下記のような処理を挟んでいます。

```js
const requestPermission = async () => {
  try {
    if (typeof DeviceMotionEvent.requestPermission === 'function') {
      const response = await DeviceMotionEvent.requestPermission()
      if (response !== 'granted') {
        console.error("加速度センサーの使用が許可されませんでした。")
        return
      }
    }
    if (typeof DeviceOrientationEvent.requestPermission === 'function') {
      const response = await DeviceOrientationEvent.requestPermission()
      if (response !== 'granted') {
        console.error("ジャイロセンサーの使用が許可されませんでした。")
        return
      }
    }
  } catch (e) {
    console.error("センサーの使用許可を取得できませんでした。", e)
  }
}
```

余談ですが、加速度センサーを使った処理の動作確認をPC上で行う方法がわからず、加速度まわりの確認をする際は毎回デプロイする、というツラい作業をしていました……
GitHub Actionsによるデプロイは40sほどで完了していたので、そこまで大きな障壁にはなりませんでしたが……

なお、ジャイロセンサーまわりの動作確認は、chromeのdev toolsを使えたため幸せでした。

## 効果音の再生

特にスマホブラウザで音声を再生する場合、画面タップやボタンクリックなどのユーザ操作を一度発生させる必要があるようです。
PCでの動作確認時には気づくことができず、スマホでの動作確認時に少しハマりました。

以下、MDNの[HTMLAudioElement](https://developer.mozilla.org/ja/docs/Web/API/HTMLAudioElement)からの引用です。

> よくあるのが、ページを読み込んだらすぐに audio 要素を再生しようとすることです。現代のブラウザーは、既定の自動再生ポリシーによって、このようなことが起こらないようにブロックしています。

たしかに、 "ページ表示直後に爆音再生！" といった悪質なサイトを防ぐためにも、この仕様は必要そうですね……

今回は、アプリの性質上、注意書きがあっても違和感がないため、下記のようなボタンを設置することでユーザ操作を発生させる工夫を施しています。

<img width=40% src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363036/16aaf90f-809a-b642-9325-75a4d146fdb7.png">

## 画像の差し替え

> 蓄積ダメージが増えるにつれてひび割れ描写は拡大

この仕様は、背景画像を更新することで実現しています。
こちらも、PC上での動作確認時には問題がなかったのですが、スマホで確認する際に問題がありました。
画像切替時に背景画像が一瞬表示されなくなる問題に遭遇しました。

この問題は、下記のように切替時のアニメーションを設定することで解決しました。

```css
.background-container {
  transition: background-image 0.1s;
}
```

なお、事前にすべての画像を読み込む作戦もあるらしいですが、今回のケースでは機能しませんでした。

## 素材

ひび割れ効果音は、効果音ラボのものを利用しています。

https://soundeffect-lab.info/

faviconは、icooon-monoの素材を利用しています。

https://icooon-mono.com/

どちらも柔軟に使える良質な素材が多く、大変助かりました。

ひび割れ画像は……手書きです！
（~~css職人になって実装したい気持ちもありましたが、工数が足りませんでした~~ :innocent: ）
iPadで使えるPastelaというアプリを利用しました。
フリープランが充実しており、こちらも大変助かりました。

https://pastela.app/

# おわりに

久しぶりにフロントエンドを書いたら、不本意ながらクソコードを生み出してしまいました。
別途、クソコード改善記事でも書きつつリファクタしようかなと……

クソコードを味わいたい人は下記からどうぞ……

https://github.com/c6tower/smartphone-crash-simulator