この記事は GRIPHONE Advent Calendar 2020 6日目の記事です。
クライアントエンジニアの米倉です。
今回は、PC(WebGL)とスマホに対応したゲーム用ボタン実装の紹介ということで、マジカミで使用したボタンの実装例を紹介したいと思います。
PC環境とスマホ環境でのUIの違い
PC環境とスマホ環境での違いの一つに、「マウスカーソル」の概念があります。当たり前と言われれば当たり前ですが、Windows OSやWebページなどPC上で操作するUIにはマウスを乗せたときのインタラクションが付いていることが多いです。
一方スマホでは指がカーソル代わりであり、画面のどこに指を置かれているかは意識する必要がありません。(押したときのインタラクションは、PCと同様に備わっていることが多いです。)
昨今はPCやスマホ、コンシューマー機のどれでも遊べるマルチプラットフォームのゲームが多く、UIを実装するにあたってなるべく共通なインタラクションを提供することが求められています。
マジカミでもWebブラウザ/スマホのマルチプラットフォーム展開をしており、開発初期にどのようなボタン状態があると好ましいかを検討しました。
ボタンの状態定義
UnityのButtonコンポーネント
まず、Unityの標準Buttonコンポーネントに存在する状態は以下です。
- Normal
- Highlighted
- Pressed
- Disabled
![](https://storage.googleapis.com/gpn-techblog-media/1/2020/12/image.png)
上記のUnity標準Buttonコンポーネントをベースに、マジカミがPC画面上で動作することを踏まえ、WindowsやMac OS、Webサイトデザインなどを参考にして基本的なボタンを以下の6つの状態に定義しました。
押すことができるだけの基本的なボタン
- Default系
- Default – Default : 通常時
- Default – Hovered : マウスが乗っているとき
- Default – Pressed : 押したとき
- Disabled系
- Disabled – Default : ボタン無効状態の通常時
- Disabled – Hovered : ボタン無効状態でマウスが乗っているとき
- Disabled – Pressed : ボタン無効状態で押されたとき
UnityのButtonクラスとの違いは、ボタンの有効/無効時の切り分けとマウスオーバーの状態の有無になります。
選択状態を持ったボタン
上記の基本的なボタンの状態を拡張して「選択可能なボタン」の場合は追加で以下のような6つの状態の定義を持ちます。(トグルボタンと呼ばれたりします。)
- SelectedDefault系(選択された状態で、有効時)
- Selected – Default – Default
- Selected – Default – Hovered
- Selected – Default – Pressed
- SelectedDisabled系(選択された状態で、無効時)
- Selected – Disabled – Default
- Selected – Disabled – Hovered
- Selected – Disabled – Pressed
これ以上状態を追加すると大変なことになりそうですが、ボタンの状態は基本的にここまで用意できていれば大丈夫です。
ボタンのインタラクションの期待値
マジカミにおけるボタンのインタラクションは、デザイナーから以下のようになっていてほしいと期待値が上がってきていました。(以下は実際に実装されたボタンになりますが、当時はPSDファイルなどでデザイン案をいただきました)
①通常時
![](https://storage.googleapis.com/gpn-techblog-media/1/2020/12/image-6.png)
②マウスオーバー時
![](https://storage.googleapis.com/gpn-techblog-media/1/2020/12/image-7.png)
③押下時
![](https://storage.googleapis.com/gpn-techblog-media/1/2020/12/image-8.png)
④無効時
![](https://storage.googleapis.com/gpn-techblog-media/1/2020/12/image-5.png)
上記の期待値をどのように実装していけばいいか検討していきます。
ボタン要素の分解
上記のインタラクションはそれぞれその見た目になる画像を割り当てれば実現できそうですが、それだと汎用性に欠けるため、より柔軟に構築/変化させられるように分解していきます。
![](https://storage.googleapis.com/gpn-techblog-media/1/2020/12/image-1.png)
上図のボタンを見てみると、色を変えたい要素は以下のように分解できます。
1.アイコン、ボタン画像など(Imageコンポーネント)
画像ファイル自体は白一色で書き出し、Colorプロパティで色付けして使います
![](https://storage.googleapis.com/gpn-techblog-media/1/2020/12/image-10.png)
![](https://storage.googleapis.com/gpn-techblog-media/1/2020/12/image-9.png)
![](https://storage.googleapis.com/gpn-techblog-media/1/2020/12/image-11.png)
2.テキスト(TextMeshProなどTextコンポーネント)
文言や値の変わるものはこちら
![](https://storage.googleapis.com/gpn-techblog-media/1/2020/12/image-4.png)
上記のように、ちょっと複雑そうに見えるボタンもImageとTextでおおよそ動的に構成できそうなことがわかります。
実装例
あとは、各ImageやTextがボタンの状態に従って自身の色を変更するようなコンポーネントを作っていくだけです。
(ここでは、選択状態を持たないボタンである「SimpleButton」について紹介します)
①各要素に共通の状態を持たせるベースクラスを用意(ButtonElementBase)
![](https://storage.googleapis.com/gpn-techblog-media/1/2020/12/image-12.png)
②上記のクラスを継承し、SimpleButtonに必要な状態を付け加えた要素のベースクラスを用意
![](https://storage.googleapis.com/gpn-techblog-media/1/2020/12/image-15.png)
④上記のベースクラスを継承し、画像やテキストの各状態の色を反映するクラスを用意
![](https://storage.googleapis.com/gpn-techblog-media/1/2020/12/image-16.png)
![](https://storage.googleapis.com/gpn-techblog-media/1/2020/12/image-19.png)
⑤SimpleButton本体から、各子要素に状態を伝播するクラスを実装
![](https://storage.googleapis.com/gpn-techblog-media/1/2020/12/image-17.png)
![](https://storage.googleapis.com/gpn-techblog-media/1/2020/12/image-20.png)
⑥完成!
![](https://storage.googleapis.com/gpn-techblog-media/1/2020/12/button_gif.gif)
![](https://storage.googleapis.com/gpn-techblog-media/1/2020/12/image-21.png)
最後に
今回はPCとスマホに対応したボタンの実装例について紹介しました。
マルチプラットフォームが求められる昨今のゲーム開発において、特にUI周りの配慮はユーザーの遊びやすさに直結するため、早い段階でしっかり検討していくことが大切だと思います。
皆さんのゲーム開発の一助になれば幸いです。
ご覧いただきありがとうございました。