イケメンに絆されて入社したらScrollViewに囚われた話

## はじめに
こんにちは！
CYBIRDエンジニア Advent Calendar 10日目担当の@shiso_cです。
9日目は@kazurasakaさんの[JSTQB社内勉強会についてのあれそれ](https://qiita.com/kazurasaka/private/48d5849dc7778b8a254c)でした。
社内でこういう機会があるのは良いですよね。勉強へのモチベーションも上がりそうです！


### 軽く自己紹介
私は新卒２年目で現在は「[イケメン源氏伝](https://ikemen.cybird.ne.jp/title/genji/original/)」という恋愛ゲームのクライアントサイドを担当しています。
入社前からCYBIRDの[イケメンシリーズ（通称：イケシリ）](https://ikemen.cybird.ne.jp/)が好きで、ゲーム開発経験も無いままこの業界に飛び込んで、今日までなんとかやってきました。

そんな私がここ数ヶ月囚われ続けた（でも１ユーザーとしては地味に嬉しい）改修をしたので、そのことを書いていこうかなと思います。

### この記事について
この記事は私がスクロールの軽量化に初挑戦した記録をまとめたものです。
イケメンは出てきませんし、ソースコードも出てきません。
エンジニアとしての苦悩とユーザーとしての喜びを感じていただけますと幸いです。

## 本題に入る前に…Question！
突然ですが問題です！
**Q：今年８月にリリース２周年を迎えたイケメン源氏伝ですが、現時点（執筆時１１月末）で実装されているカードの総数は何枚でしょうか？**

正解は…

$\huge{493枚}$

年が明ける頃にはきっと５００枚超えてますね…:flushed:
この数字、後から出てきますのでざっくりとでも覚えておいてください。

## スクロールを軽くしたい！
さて、ここからが本題です。
事の発端は「カード所持数が多い場合にチーム編成画面・マイページ設定画面の動作が重い」という不具合修正依頼から始まります。

いわゆる**軽量化**というやつですね。
私もイケシリ含めいろいろなアプリゲームで遊んでいますが、やはりサクサク動く方がユーザーとしては嬉しいですよね。

源氏伝のカード一覧がどのくらい重いかと言うと…
![scroll0.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294759/92fe7bc6-8bf1-36a6-54e7-46e2e61e2696.gif)
GIFなのでわかりづらいですが、ちょっと引っかかる感じがしますよね？
これはUnityエディタ上で撮影したものですが、端末性能によってはもっとひどいと思います。

しかし進行不能になるわけでもなければ、カードの所持数が少ない場合には然程影響しないため、後回しにされてきました。

とはいえ、源氏伝も２周年を迎え、カード枚数も増えてきました。
このままではアプリの動作は重くなる一方です。

というわけで、**ScrollViewの軽量化**に挑戦することになりました。

## UnityのScrollView
UnityでScrollViewを実装するのはとっても簡単で、Hierarchy上から挿入するだけで大方必要な要素は揃っています。
![スクリーンショット 2021-12-01 17.33.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294759/0d4ec436-cb63-184b-d7cd-ad9f56dd11e0.png)
さらに**LayoutGroup**などの自動レイアウト用のコンポーネントと組み合わせるとあっという間に綺麗なスクロールが作れてしまう優れもの。

そんなScrollViewが重くなってしまう原因として、次のことが挙げられます。
**・スクロールしている要素の一つ一つが重い
・表示している要素が多い**

UIオブジェクトはCanvas内に配置されますが、Canvasに含まれるUIが一つでも変更されると、全要素の再計算が起こるので、スクロール内に配置する要素次第で、負荷の大きさも変わってきます。
つまり、一つ一つの要素が重かったり、要素数が多いとそれだけ負荷が大きいのです。

## 対策①：要素の一つ一つを軽くする
まずはこちらから取り組んでみました。
というのも、要素の軽減だけで済めばScrollViewそのものの大幅な修正なく改善できそうだったからです。

さっそく中身を見てみましょう！
源氏伝のカード一覧で表示しているセルの構成はざっくりとこんな感じ↓
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294759/3e18261a-56ac-7dde-acf5-dd1b6c3f26dd.png)
**①カードセル（Button）
②サムネイル（Image）
③魅力値（Image、Text）
④ストーリーアイコン（Image、Text）**
さらにそれぞれにコントロール用のスクリプトがアタッチされています。

ではこの中のどれが動作を重くしているのでしょうか…

調べてみると、どうも**Text**が重そうな感じがしました。
（本当はプロファイラとか使いこなして原因特定できると良かったのですが、私はまだプロファイラとお友達になれていないのでここでそれなりに苦戦します）

Google先生曰く、**TextのBestFitは処理負荷が重い**らしいです。
あとは、**ContentSizeFitter**も使いすぎは良くないみたいですね。（GetComponentでサイズ取得するらしい）
というわけで、元の表示が崩れないようにしながら重そうな処理をことごとく外してみました。

すると、なんということでしょう…！
軽くなるではありませんか……！！

![scroll1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294759/afe992cc-2315-372f-6efe-0b11121fe829.gif)

ここで喜んだのも束の間、この実装では一定条件下でバグることがわかったので、このままでは使えませんでした…無念😢

### 敗因：原因不明のバグ
実は↑のGIFには続きがありまして、一度戻ってからもう一度アクセスするととんでもなく重くなるんです…
![scroll3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294759/45592ae0-518a-829f-24bd-130979680c94.gif)
調べてみると、この改修を行う前からあった源氏伝側のバグのようで、今までは根本的なスクロールの重さが目立っていたために露見していなかったようでした。

なので今回の実装でどうこうなったという話ではなく、軽いスクロールを作るという観点においては**重そうな処理を取り除くというアプローチは有効**と言って良いと思います！

そして肝心のこのバグについてですが……原因特定できませんでした😭
試しにカード枚数を減らしてみるとこの現象は起きなかったので、おそらく何かしらのバグがカード枚数分積み重なっているのではないかなーとは思うのですが、憶測の域を出ません。

しかし、カード枚数を減らすと発現しないというのも一つの収穫で、対策②ならばどうにかできそう！
というわけで、方針を変えることにしました。

## 対策②：要素数を減らす
そもそも根本的に表示しているカードが多いので、減らしてしまえば小さいバグの積み重なりで起きていた現象も起きないわけですね。（最初からこっちでやれば良かった…）

要素数を減らす方法として挙げられるのが以下の方法です。
**・オブジェクトを使い回す
・表示範囲外のオブジェクトを非表示にする**

今回は前者のオブジェクトを使い回す方法を試してみました。

ここで今までお世話になっていた便利機能**LayoutGroup**とのお別れです。
オブジェクトを一部しか生成しないので、ScrollContentのサイズが必要分取れなくてスクロールできないんですね。
というわけで、ここは手動でやります。

具体的には、
**・スクロールに必要な範囲を計算して、ScrollContentの高さを決める
・必要分だけオブジェクト（カードセル）を生成する
・スクロール位置が変化したら、カードセルの情報と表示位置を書き換える**
というような挙動のScrollViewを作ります。

実装に関しては以下の記事を参考にさせていただきました。
・[[Unity uGUI] スクロールビューの基本と軽量なスクロールリストビューの作り方](https://qiita.com/k7a/items/7db3a41e39923fd8a3b3)
・[UnityのuGUIで無限にスクロール出来るスクロールビューを作る](https://tsubakit1.hateblo.jp/entry/2015/01/21/233000)

ついでに便利なアセットもあるようです。
・[【Unity】最適化されたスクロールビューをEnhancedScrollerで作る！](https://www.stmn.tech/entry/2017/08/27/233055)

そんなこんなで、完成したカード一覧がこちら！
![scroll2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294759/bfc5a6dc-e082-13c3-922c-ecff4c79726a.gif)
とっても軽くなりました！やったー🙌

<p>
  <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294759/fa6738fd-4f0f-548a-d423-0489a8cd4cc3.png" width="250">
  <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294759/1c238757-42cf-6b17-dbce-5e684b7f5c28.png" width="250">
</p>
ScrollContentの中身を見ると一目瞭然ですね！（←before, after→）
左の画像はほんの一部しか写っていませんが、ここに４９３個並んでいます！


## おわりに
この改修中、プライベートで遊んでいるいろんなゲームでスクロールの挙動を観察してしまい、文字通りScrollViewに囚われておりました笑（タイトル回収）

軽量化と一口に言っても、原因も対処法も様々で、最良の方針を定めるまでが結構大変なんじゃないかなと思っています。
なかなか先が見通しづらいタスクではあるので、しんどい時もあるのですが、これが改善された時の喜びも知っているのでちゃんとやりがいもありますよ。
ちなみに今現在も別の軽量化問題に当たっております！しんどいですね笑！

今回の改修も含めて、ユーザーの皆様へ提供できるのはもう少し先の話にはなってしまうのですが、少しでも良いものをお届けできるように日々精進して参りますので、楽しみにお待ちいただけますと幸いです🙇‍♀️

明日のCYBIRDエンジニア Advent Calendar 2021 11日目は、@naotwuさんの「PHPでのサーバー間通信について」です！
お楽しみに☺️