UnityでプラットフォームごとにUIの判定エリアを変える


この記事はクラスター Advent Calendar 2020の16日目です。前回はulaphさんによる「SwiftでViewの状態をenumで管理する」でした。C#からSwiftへ軽やかに転身していてカッコいい。

はじめに

こんにちは。クラスター株式会社でデザイナーとして主にUIデザインをやっています。

バーチャルSNS cluster(クラスター)

Unityでマルチプラットフォームに対応したUIを作る場合、同じにできる機構はなるべく共通になるよう努めます。とは言え、無闇矢鱈にすべてを共通化するわけではありませんし、プラットフォームごとの対応が簡単に出来るものは対処しておきたいです。マウスイベントやタップ判定などを行う判定のエリアもその1つです。

プラットフォームごとの判定エリアのサイズ

一般的にマウスカーソルデバイス……ここではPCですが、これのホバーやクリックを判定するエリアのサイズは、UIの見た目と一致していることがほとんどです。

一方スマートフォンでは操作する指よりもUIが小さいため、判定エリアのサイズは見た目以上のサイズになっているのが一般的です。例えばiOSのソフトウェアキーボードは入力する内容を予測して動的に判定エリアのサイズが変化しています。すごい。

参考: ソシオメディア | iPhone の当たり判定を検証した

入力を予測して……はさすがに困難を極めるので、プラットフォームごとでオン/オフする程度の簡単な対処を考えてみました。

Unity UIでボタンを組む

自分がUnityでよく組むタイプのボタンです。Unityのプリセットのようにコンポーネントを1つのオブジェクトにまとめ過ぎず、ビジュアルの責任も適度に分けたほうがデザインの柔軟性があり、かつメンテナンス性も高いです。

ボタンの判定エリアを広げる

操作時にフィードバックを返すTargetGraphic以下に、Imageコンポーネントをアタッチして、アルファ値を0にしたTargetAreaというゲームオブジェクトを配置しています。このオブジェクトのサイズをボタンよりも広げ、Raycast Targetをオンにすることで判定エリアを広げています。

PCプラットフォームでTargetAreaを削除する

プラットフォームを判別する方法を調べると2つ出てきました。

  1. プラットフォーム依存コンパイル - Unity マニュアル
  2. RuntimePlatform - Unity スクリプトリファレンス

2のRuntimePlatformで以下のよう書かれています。

プラットフォーム別コンパイルを使用するほうが、実行時にチェックする必要がないため軽くて高速なコードを生成できます。

使用しているデバイスが途中で変わる……などということは起きないので、スマートフォン向けに追加したTargetAreaをPCの場合はプラットフォーム依存コンパイルを使って削除するのが簡単そうです。

Unityが用意してくれているUNITY_STANDALONEを使います。囲んだコードが、すべてのPCプラットフォームでコンパイルに含まれます。

DestroysSelfWhenStandalone.cs
using UnityEngine;

public class DestroysSelfWhenStandalone: MonoBehaviour
{
    void Start()
    {
#if UNITY_STANDALONE
        Destroy(this.gameObject);
#endif
    }
}

プラットフォームを切り替えて実行してみる

PCプラットフォームに切り替えて実行した時のみTargetAreaが削除されました。

まとめ

共通化はUnityの大きな利点の1つではありますが、プラットフォームに向けたこういうちょっとした最適化は今後も積み重ねていきたいものです。

心残りが1点。そもそも対象のゲームオブジェクトを環境ごとでビルドに含めない方法を取れれば良かったなと思います(スマートフォン側には虚無のスクリプトが残ることに)。自分で調べた範囲ではその方法は見つけられませんでした。残念。

次回は2tatuki4さんによる「ワールド制作でメモリが大変なことになった時に見るやつを書く」です。お楽しみに!