2024.10.01
自社の社内情報を未来の“ゴミ”にしないための備え 「情報量が多すぎる」時代がもたらす課題とは?
Unityでチャットに使えるモバイルキーボードを実現する(全1記事)
リンクをコピー
記事をブックマーク
中地:「Unityでチャットに使えるモバイルキーボードの実現」と題して発表を始めたいと思います。よろしくお願いいたします。
メチャクチャ緊張しているので、すごく噛んだら申し訳ないです。最初に自己紹介をします。UnityとかVRのエンジニアをやっている、なかじと申します。Twitter(@nkjzm)をやっているので、よかったらフォローしてください。「日本VR学会認定 上級VR技術者」で、専門学校でVRを教えたり、VRのPodcastをやっていたり、VR関係のことをけっこういっぱいやっている人です。
略歴に書いたんですが、僕は実は新卒で入った会社がサイバーエージェントで、久しぶりにこういう機会に関われてうれしいなと思います。
そのそのつながりで今やっていることを紹介したいんですが、『ALTDEUS: Beyond Chronos』というタイトルの開発をしています。このゲームは、VRを使ったアドベンチャーゲームで、物語にすごく入り込めるところが推しのゲームなんですが、マシンアクションパートがあったり、かわいい女の子がVRライブをしてくれたり、盛りだくさんのゲームです。
こちらが「Oculus Quest」と「Oculus Rift」向けに好評発売中で、なんと本日(※取材当時)「Steam」版が発売しました。発売してすぐに、Steamの全カテゴリでトップ2位や、VRカテゴリでトップワンを取っていて、すごく注目されているゲームなので、ぜひ遊んでみてください。PlayStation VR版も今度出ます。
ここから本日の内容に入るのですが、本日はモバイルキーボードを気持ちよく実装する方法について話していこうと思います。左の「よくある実装」と書いてあるGIF画像を見てください。Unityで普通にチャットを実現すると、こんな感じになると思っています。
下のほうにテキストエディタが入っていて、ネイティブの入力フィールドが持ち上がって、Sendボタンを押すと送信される流れだと思うのですが、今回紹介する右の例を見ると、きちんと右のほうにチャット欄が上がって、Unity側のテキストのInputFieldを使って送信ができています。やってみて大変だったので、今回紹介してみようと思いました。
左下に書いてある『ワンナイト人狼オンライン』というゲームは、業務委託で関わったもので、最近リリースされたんですが、このアプリで使用したものを今回紹介します。
アジェンダはこんな感じです。最初に、キーボードの高さにチャット欄を調整するところを紹介していきます。後半はけっこう細かい話が続くんですが、これは1人でやるとけっこう大変なので、ぜひ参考にしてもらいたいと思っています。
キーボードの高さは、iOSに関してはけっこうそのまま取得できます。UnityEngineの中に、TouchScreenKeyboardというクラスがあるので、その中のareaというメソッドを取得すると、Unityの矩形を表すクラスのRect型で矩形を取得できます。
ただ、このメソッドのドキュメントに、すごく悲しいことに「AndroidではRectは0です」と、Androidには対応していないとリファレンスに書いてあります。なのでAndroidに関しては、ここはbaba-s(@baba_s_)さんのスクリプトで対応しています。
一部抜粋したんですが、こんな感じになっています。見てもらうとよくわからない、けっこう難しい処理が書いてあると思うんですが、黄色で書いてあるAndroidJavaObjectというクラスを使うと、Androidのメソッドやインスタンスを呼び出せるので、それを使ってがんばってネイティブ側の情報を取得しています。
なので、Androidに関してはけっこう大変だったんですが、baba-sさんが簡単にできるライブラリを公開してくれていたので、それを使って比較的簡単にできました。
次に、キーボードをチャット欄に反映させるというところを紹介していきます。これは3段階あります。普通に考えたらuGUIに反映させたらいいという話です。GIF画像があるんですが、キーボードが出てきたら全体の相対位置を変えて、チャット欄を良い感じに上にずらせばいいだけです。
だけど、その仕組みをやったことがない人だとちょっと難しいです。右の図はStretchにしているので、全体に引き伸ばしているうちのBottomだけを上げればいいんですが、Rect Transformの場合、ここに書いてある値がそのままスクリプトや内部で保持されているわけではありません。
下に「Debug表示で実際の値が見られる」と書いたんですが、Debug表示に切り替えるとわかると思いますが、実際はけっこう複雑で、いろいろな値によって右のようなViewが構成されているので、読み解くのがもしかしたら大変かもしれません。なので今回は、chatContainerの全体の大きなuGUIの枠の中の.sizeDeltaに対して値を入れることで、今GIF画像のマウスでやっているような動きを実現しています。
ほかにも気をつけるところがあって、解像度の調整をする必要があります。これは何かというと、先ほど取得したキーボードの値です。キーボードの値は、端末の解像度の単位で返ってくるんですが、uGUIの場合、Canvasの解像度で制御されていることが多いと思います。Canvasの右下に書いてあるCanvas Scalerを使っている人がけっこういると思います。
これはReferenceResolutionといって、その解像度を基準にしていい感じに縦・横を伸ばすことで、どの端末で見てもだいたい同じぐらいの大きさでUIが表示されるというものです。ただ、これを使うと、端末の解像度とuGUI上の解像度の単位が変わるので、それらを合わせる必要があることを考慮する必要があります。
技術的なコードが左に書いてあるんですが、まずresolutionHeightですね。Canvasの解像度を取得して、rateで端末の解像度とCanvasの解像度の比を求めて、それをきちんとキーボードのHeightと掛け合わせることで、uGUI上で扱える値にする処理を書く必要があります。
これをチャット内に反映させるところにもSafeAreaの罠があります。さっき紹介したキーボードの高さは、SafeAreaの領域を含むんですね。下の図の、緑の枠で囲まれた部分がSafeAreaなんですが、その下の部分の領域まで含んだ高さになっています。ただ、SafeAreaの部分は入力ができない部分なので、そこのUI要素を上にずらすことが多いんですね。
なので下に隙間があるんですが、そこにさらにキーボードの高さ分空けてしまうとSafeAreaが2回分含まれてしまうことになり、その分ズレるという問題が発生します。そこを考慮する必要があるのに意外とハマりました。
そんな感じでキーボードの高さは実現できたので、続いてネイティブの入力フィールドを非表示にする処理に移ります。
これは変数が用意されていて、さっきのTouchScreenKeyboardに.hideInputというものがあります。これも引っかかりやすいポイントがあって、InputFieldを使うのがけっこう多いと思うんですが、InputFieldの場合、HideMobileInputというプロパティが用意されていて、これで毎回上書きされちゃうので、上で設定しても反映されないことがよくあります。
今回はネイティブの入力フィールドを隠す方法をお話ししたんですが、下の注意事項にあるとおり、ネイティブのコピー&ペースト機能が使えなくなったり、Androidだと疑似的な実装なので、動作が不安定になったりするなど、デメリットがあります。なので、別にこれはそのまま使う実装でもぜんぜん良いとは思いますが、これを隠してUnityのInputFieldを表示したほうが、フォントなどをゲームの世界観に合わせやすいと思います。
続いて、ネイティブボタンのOKボタンを取得するところです。何で必要かというと、これはAndroidのスクリーンショットなんですが、キーボード外の入力は拾えないという問題があります。画面の中央部分の赤いSendというボタンを押しても、そのSendボタンの判定が取れないという問題があります。
ポジションなどを取って、離すタイミングが取れるんじゃないかいろいろやったんですが、無理でした。なので、右下の青いネイティブのOKボタンを使って、送信するようにしました。これもけっこうやり方があったんですが、ソフトモバイルキーボードのクラスの中の.statusという値を監視することで、実現できました。
使っている値は大きく2つで、DoneボタンになったらOKを押したタイミングで、そのイベントが飛んできて、画面外をタップしてキーボードを閉じた段階でLostFocusが入ってくるかたちです。
最後にキーボードのハンドリングです。キーボードは1回入力を終えたり、Unity領域をタップしたり、OKボタンを押したりすると閉じちゃうんですが、チャットの場合は開きっぱなしにしたいですよね。右のGIFを見てもらうと、打ったあとにきちんとキーボードが開きっぱなしになっていると思います。それを実現するための知見です。
やっていることは、いろいろなタイミングでのキーボード再表示と再フォーカスです。チャットを送信した瞬間にキーボードを1回出しているんですが、それだけじゃ不十分です。UnityのSendボタンが用意されているんですが、あれはタップした瞬間の判定が取れなくて、離した瞬間にボタンが押されたという判定を取っているので、タップした瞬間にキーボード自体を閉じ始めちゃうんですね。なのでそこのタイミングでもう1回キーボードを出しました。
ほかにも複雑なのが、Sendボタンを押したあとに横に指をずらして離す場合ですね。ユーザーの求めていることは、キーボードを閉じずに、テキストはまだ編集できるという状態だと思うので、そういうボタンを押しかけて押さなかったときも考慮する必要があって、けっこう大変でした。
処理も、キーボードを開く処理と、フォーカスをきちんとテキストのInputFieldに戻す処理の2つがあるので、けっこう考慮するところがいっぱいあって大変だと思いました。
今回、考慮するところがけっこうあったし、ネイティブの挙動なので、毎回試して実装を変えて、ビルドして、確認するのがすごく大変でした。今回紹介したこのサンプルプロジェクトをGitHubのUnlicenseで公開しているので、モバイルのキーボードで悩む人がいたら、これを参考にしてもらえるとうれしいです。
ご清聴いただきありがとうございました。
司会者:ありがとうございました。
コメントは私が読み上げますね。「Rect Transformは魔界」など、みなさん苦労しているようなコメントが多くありました。
中地:そうですね。今回は省いたんですが、uGUI上では、LeftやAnchorsやPivotなどとわかりやすい概念になるんですが、それをスクリプトで扱おうとすると、それらがどういう関係で構築されているのかを理解する必要があるので、やったことがない人だと、ここがすごく苦労すると思います。
司会者:なるほど。ありがとうございます。SafeAreaの対応についてもコメントでいくつかいただいていましたね。
中地:ちょっと補足です。SafeAreaのこのスクリーンショットなんですが、UnityのDevice Simulatorというものを使っていて、エディタ上でSafeAreaのエミュレーションができるので、これを使うと対応がずいぶん楽になると思います。
司会者:ありがとうございます。ではお時間になりましたので、これでLTを締めたいと思います。なかじさんありがとうございました。
中地:ありがとうございました。
2024.10.29
5〜10万円の低単価案件の受注をやめたら労働生産性が劇的に向上 相見積もり案件には提案書を出さないことで見えた“意外な効果”
2024.10.24
パワポ資料の「手戻り」が多すぎる問題の解消法 資料作成のプロが語る、修正の無限ループから抜け出す4つのコツ
2024.10.28
スキル重視の採用を続けた結果、早期離職が増え社員が1人に… 下半期の退職者ゼロを達成した「関係の質」向上の取り組み
2024.10.22
気づかぬうちに評価を下げる「ダメな口癖」3選 デキる人はやっている、上司の指摘に対する上手な返し方
2024.10.24
リスクを取らない人が多い日本は、むしろ稼ぐチャンス? 日本のGDP4位転落の今、個人に必要なマインドとは
2024.10.23
「初任給40万円時代」が、比較的早いうちにやってくる? これから淘汰される会社・生き残る会社の分かれ目
2024.10.23
「どうしてもあなたから買いたい」と言われる営業になるには 『無敗営業』著者が教える、納得感を高める商談の進め方
2024.10.28
“力を抜くこと”がリーダーにとって重要な理由 「人間の達人」タモリさんから学んだ自然体の大切さ
2024.10.29
「テスラの何がすごいのか」がわからない学生たち 起業率2年連続日本一の大学で「Appleのフレームワーク」を教えるわけ
2024.10.30
職場にいる「困った部下」への対処法 上司・部下間で生まれる“常識のズレ”を解消するには