Unityの開発でよく発生するのが「シミュレータでは問題ないのにAndroid実機でだけ意図しない挙動をする」問題です。
この記事では、UnityのEventSystemの中で発行される OnPointerDown
や OnPointerUp
の発行タイミングが、Unity Editorのシミュレータ環境とAndroid実機環境で異なったことにより発生した問題を解説します。
問題の内容
Joystick操作UIで、指を離したら自動的にスティック位置を指定の場所に戻す処理を行っていました。
そのトリガーとして OnPointerUp
の中に以下のような処理をいれていました:
public void OnPointerUp(PointerEventData eventData)
{
inputVector = Vector2.zero;
handle.anchoredPosition = Vector2.zero;
// activeAreasの中心に移動させる処理
RectTransformUtility.ScreenPointToLocalPointInRectangle(
stickRoot.transform.parent as RectTransform,
RectTransformUtility.WorldToScreenPoint(eventData.pressEventCamera, activeAreas.position),
eventData.pressEventCamera,
out Vector2 localPoint
);
(stickRoot.transform as RectTransform).anchoredPosition = localPoint;
}
このように OnPointerUp
時点で inputVector
をゼロクリアし、スティック位置を初期化する意図でした。
しかしAndroid実機では、たとえ指を離していない状態でも、OnPointerUp
が発行されてしまうことがありました。
現象
- Unityシミュレータ上:
- Drag中は
OnPointerUp
は発行されず、スティックが動作を継続
- Drag中は
- Android実機上:
- Drag中にもかかわらず
OnPointerUp
が発行されてしまい、 - スティックが初期位置に戻ってしまう
- Drag中にもかかわらず
原因
Android実機では OnPointerUp
が不定なタイミングで発行されることがあり、その結果 inputVector = Vector2.zero
、および位置リセットが実行されてしまいます。
実装側での対策
OnPointerUp
で直接リセット処理を行うのではなく、Update側で “一定時間入力がない” という条件に限定して位置リセットを行うように変更したことで解決しました。
具体的には、以下のように inputVector
がゼロの時間を計測し、条件を満たした場合のみ戻すようにしています:
if (inputVector == Vector2.zero)
{
if (inputZeroStartTime < 0f)
{
inputZeroStartTime = Time.time;
}
else if (Time.time - inputZeroStartTime > resetDelay)
{
stickRoot.transform.position = activeAreas[0].position;
inputZeroStartTime = -1f;
}
}
このようにすることで、意図しない OnPointerUp
発行があっても即座にスティックが戻ることはなくなります。
おわりに
Unityのタッチイベントは環境によって発行時点の振る舞いが異なるため、OnPointerUp
などに直接依存する実装は慎重に行う必要があります。
ドラッグ状態の維持確認や、別の条件(例:時間経過やタッチ継続の検知)で判断する実装が、より安定した挙動を保証してくれます。
他にもUnityや個人開発ネタを発信中です!
開発ノウハウやアプリ製作過程、Unity連携系のハマりポイントなど
より深探りした内容をブログにまとめています。
▶ https://syunpp.com
公開中のアプリ一覧はこちら!
実際にUnityで開発してリリース済みのアプリ一覧をまとめています。
▶ https://syunpp.com/公開中のアプリ一覧/
コメント