UnityシミュレータとAndroid実機でOnPointerDown / OnPointerUpの発行タイミングが異なる件
Unity開発中に、Editorでは問題ないのに実機でだけ挙動が崩れるという現象はよくあります。
本記事では、OnPointerDown
や OnPointerUp
などの タッチイベント発行タイミングがUnity EditorとAndroid実機で異なることによって発生したUIのバグについて紹介します。
発生した問題
ジョイスティックUIの制御中、OnPointerUp
イベントの中でジョイスティックの位置を初期化する処理を記述していました。
public void OnPointerUp(PointerEventData eventData)
{
inputVector = Vector2.zero;
handle.anchoredPosition = Vector2.zero;
RectTransformUtility.ScreenPointToLocalPointInRectangle(
stickRoot.transform.parent as RectTransform,
RectTransformUtility.WorldToScreenPoint(eventData.pressEventCamera, activeAreas.position),
eventData.pressEventCamera,
out Vector2 localPoint
);
(stickRoot.transform as RectTransform).anchoredPosition = localPoint;
}
Unityのシミュレータ上ではこれで問題なかったのですが、Android実機ではスティック操作中にもかかわらず OnPointerUp が発行されてしまい、ジョイスティックが勝手に初期位置に戻るという問題が発生しました。
原因
Android実機では、特定状況下で OnPointerUp が予期せず発行されることがあるようです。
これにより、ユーザーが操作を継続しているにもかかわらず、ジョイスティックが「指を離した」と判断してリセット処理を実行してしまう状態になっていました。
修正後の実装(OKパターン)
OnPointerUp ではリセット処理を行わず、Update()内で「一定時間入力がない」場合にのみ位置をリセットするように変更しました:
void Update()
{
if (inputVector == Vector2.zero)
{
if (inputZeroStartTime < 0f)
{
inputZeroStartTime = Time.time;
}
else if (Time.time - inputZeroStartTime > resetDelay)
{
stickRoot.transform.position = activeAreas.position;
inputZeroStartTime = -1f;
}
}
else
{
inputZeroStartTime = -1f;
}
}
このようにすることで、Android実機で不意に OnPointerUp が発行されても、スティックが即座に戻ることを防止できます。
学びポイント
タッチイベント(特に OnPointerUp)の発行タイミングは、実行環境によって異なる
イベントハンドラに即座に副作用のある処理(位置リセットなど)を書くのはリスクがある
状態を追跡し、フレームごとに安定したロジックで処理する方が堅牢
補足:Unityのシミュレータ上では発生しない理由
Unity Editorでは OnPointerUp は通常マウスボタンを離したときのみ発行されますが、Androidでは一時的なフォーカスロストや通知ポップアップなどの影響で、明示的に指を離していなくても発生するケースがあります。
ブログでもUnityや個人開発ネタを発信中です!
開発ノウハウやアプリ制作過程、Unity連携系のハマりポイントなど
より深掘りした内容をブログにまとめています。
▶ https://syunpp.com
公開中のアプリ一覧はこちら!
実際にUnityで開発してリリース済みのアプリ一覧をまとめています。
▶ https://syunpp.com/公開中のアプリ一覧/
Discussion