【Unity】アイテム画面を開いているときのクリックで剣を振ってしまう問題の対処(Input System)
Unity 6でアクションゲームを作っていて、アイテム画面を開いてアイテムボタンをクリックしたときに、プレイヤー(クエリちゃん)が剣を振ってしまう問題が出ました。原因と、EventSystem.current.IsPointerOverGameObject()を使った対処をまとめます。
起きていたこと
マウスの左クリックで剣を振るゲームです。ポーズ・アイテム・レシピのボタンがあり、アイテムボタンを押すとアイテムダイアログが開きます。このボタンやダイアログ上をクリックしたときにも、クエリちゃんが剣を振っていました。
原因
攻撃の入力は、Input Systemの「Attack」アクション(マウス左クリックに割り当て)で受け取っています。UIのButtonのクリックは、EventSystemが別の仕組みで処理します。そのため、同じクリックに、ボタンの反応と攻撃の両方が反応していました。PlayerControllerには、クリックの位置にUIがあるかどうかを調べる処理がありませんでした。

// PlayerController.cs(修正前)
void Update()
{
// 攻撃
if (_attack.WasPressedThisFrame())
{
// Attackアクション(マウス左クリックなど)で攻撃する
_mobAttack.AttackIfPossible();
}
// 移動などの処理が続く
}
対処:UI上のクリックは攻撃しない
EventSystem.current.IsPointerOverGameObject()は、ポインタがUIの上にあるときにtrueを返します。攻撃のif文の条件に、これがfalseのときだけ攻撃する、という条件を足します。

// PlayerController.cs(修正後)
using UnityEngine.EventSystems;
void Update()
{
// 攻撃
// UI(アイテムダイアログやボタンなど)の上でのクリックは攻撃として扱わない
if (_attack.WasPressedThisFrame() && !EventSystem.current.IsPointerOverGameObject())
{
// Attackアクション(マウス左クリックなど)で攻撃する
_mobAttack.AttackIfPossible();
}
// 移動などの処理が続く
}
returnで処理を打ち切る書き方もありますが、Updateの中でreturnすると、後ろの移動・ジャンプ・重力の処理まで止まってしまいます。止めたいのは攻撃だけなので、if文の条件に入れています。
動作確認
攻撃が実行されたときだけConsoleにログが出るように、一時的にDebug.Logを入れて確認しました。フィールドをクリックしたときは攻撃のログが出て、アイテムボタンをクリックしたときは出ませんでした。確認が終わったら、Debug.Logは外しています。
注意点
IsPointerOverGameObject()がtrueになるのは、Raycast Targetが有効なUIの上にポインタがあるときだけです。背景ImageなどのRaycast Targetがオフだと、その上のクリックは攻撃になります。逆に、画面全体を覆う透明なImageがあると、どこをクリックしても攻撃できなくなります。
アイテムダイアログの外(フィールド側)のクリックは、この方法では防げません。ダイアログを開いている間は一切攻撃させたくない場合は、ダイアログの開閉状態を見て入力を止めます。
タッチ入力では、指ごとのfingerIdを渡すIsPointerOverGameObject(int)を使います。
もう一つ、Unityがスクリプトの変更を取り込まず、古いコードのまま動いていることがありました。修正したのに動きが変わらないときは、Unityのメニューの「Assets > Refresh」(Cmd+R)でコンパイルし直してから確認します。
まとめ
Input Systemで入力を受け取っていても、UIの上のクリックは別に判定する必要があります。攻撃のif文の条件にEventSystem.current.IsPointerOverGameObject()を加えるだけで、アイテムボタンの上のクリックでは剣を振らなくなりました。
参考
ポーズ画面のときにゲームオブジェクトを操作させない方法は、Pause(ポーズ)の作成でも紹介しています。











ディスカッション
コメント一覧
まだ、コメントがありません