Unity開発において、Editorではうまく動作するのに、Android実機でだけ挙動が崩れるという現象はよくあります。
本記事では、OnPointerDown
/ OnPointerUp
の発行タイミングがUnity EditorとAndroid実機で異なることで発生したバグと、その解決方法を紹介します。
発生した問題
ジョイスティック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[0].position),
eventData.pressEventCamera,
out Vector2 localPoint
);
(stickRoot.transform as RectTransform).anchoredPosition = localPoint;
}
Unity シミュレータ上では問題なく動作していましたが、Android実機では操作中にもかかわらず OnPointerUp が発行され、スティックが勝手に戻ってしまうという不具合が発生しました。
環境別の挙動
環境 挙動
Unity Editor 指を離したときだけ OnPointerUp が発行される(想定通り)
Android 実機 指を離していないのに OnPointerUp が発行されることがある(想定外)
原因
Android実機では、一時的なフォーカスロストや通知のポップアップなどの影響で、ユーザーが指を離していなくても OnPointerUp が発行されることがあります。
そのため、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[0].position;
inputZeroStartTime = -1f;
}
}
else
{
inputZeroStartTime = -1f;
}
}
教訓
OnPointerUp のようなイベントに即座に副作用のある処理を書くのは避けるべき
入力状態を別で管理し、安定したフレーム単位のロジックで制御する方が安心
実機テストは必須。Unity Editorだけではわからない挙動差が存在する
補足:なぜUnity シミュレータ上では問題なかったのか?
Editorではマウスイベントに基づくため、明示的にマウスボタンを離さない限り OnPointerUp は発行されません。一方、実機では予期せぬトリガーでイベントが飛ぶケースがあります。
ブログでもUnityや個人開発ネタを発信中です!
開発ノウハウやアプリ制作過程、Unity連携系のハマりポイントなど
より深掘りした内容をブログにまとめています。
▶ https://syunpp.com
公開中のアプリ一覧はこちら!
実際にUnityで開発してリリース済みのアプリ一覧をまとめています。
▶ https://syunpp.com/公開中のアプリ一覧/