You click a button in your shop menu and your character also fires a shot, or walks to where you clicked, or places a building behind the panel. Clicks going through Unity UI into the game world is a classic problem, because UI input and game input are handled by separate systems. This guide explains how to block game input when the pointer is over UI, the Input System gotchas that make the usual fix fail, and cleaner alternatives.
Why Clicks Pass Through
The UI (uGUI) receives clicks through the EventSystem, which raycasts against UI elements. Your gameplay code reads the mouse button directly, with an input action or Mouse.current.leftButton. Neither system knows about the other. A click on a button is both a UI click and a raw mouse click, so both fire.
So the gameplay code needs to ask: “is the pointer over UI right now?” and ignore the click if so.
The Standard Fix: IsPointerOverGameObject
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
public class ClickToMove : MonoBehaviour
{
void Update()
{
if (!Mouse.current.leftButton.wasPressedThisFrame) return;
if (EventSystem.current != null && EventSystem.current.IsPointerOverGameObject()) return;
// world click: raycast from camera, move, shoot, place...
}
}
IsPointerOverGameObject() returns true when the pointer is over any UI element that has Raycast Target enabled. Check it right before acting on a world click, in every script that reads world clicks.
Despite the name, it only knows about objects the EventSystem raycasters hit. With the default setup that’s UI only (Graphic Raycaster on the Canvas). If you added a Physics Raycaster to the camera so 3D objects receive pointer events, those count too, which may not be what you want.
The Input System Callback Problem
With the Input System, many people read clicks in an action callback:
fireAction.action.performed += ctx =>
{
if (EventSystem.current.IsPointerOverGameObject()) return; // can be wrong here
Fire();
};
This often doesn’t work, and Unity logs a warning: “Calling IsPointerOverGameObject() from within event processing (such as from InputAction callbacks) will not work as expected; it will query UI state from the last frame”. Input callbacks run while input events are processed, before the UI module updates for this frame, so the answer is stale.
Two fixes:
- Poll in Update instead of using callbacks. Check
fireAction.action.WasPressedThisFrame()in Update, then callIsPointerOverGameObject(). By Update, the UI state is current. - Remember the press and handle it later. Set a flag in the callback and handle it in Update after the UI check.
void Update()
{
if (fireAction.action.WasPressedThisFrame() && !PointerOverUI())
Fire();
}
static bool PointerOverUI() =>
EventSystem.current != null && EventSystem.current.IsPointerOverGameObject();
Also make sure the EventSystem uses the Input System UI Input Module, not the old Standalone Input Module, when the project uses the Input System. The UI button not working guide covers that mismatch.
Touch Input
On mobile there can be several pointers. Passing a pointer ID checks a specific one. With the Input System UI module, the parameterless version generally works for the most recent pointer, but when you handle touches yourself, check per touch:
using UnityEngine.InputSystem.EnhancedTouch;
using Touch = UnityEngine.InputSystem.EnhancedTouch.Touch;
foreach (var t in Touch.activeTouches)
{
if (t.phase != UnityEngine.InputSystem.TouchPhase.Began) continue;
if (EventSystem.current.IsPointerOverGameObject(t.touchId)) continue;
// world tap at t.screenPosition
}
Enable Enhanced Touch once with EnhancedTouchSupport.Enable(). If your project combines a virtual joystick with world taps, this per-touch check stops joystick drags from also counting as taps. The mobile touch controls guide builds that joystick.
Raycast Target and What Counts as UI
Every UI Graphic (Image, RawImage, TextMeshPro text) has a Raycast Target checkbox. Only graphics with it ticked block the pointer.
- An invisible full-screen Image with Raycast Target on makes every click count as “over UI”, so world clicks never work. Look for stray transparent panels.
- Decorative text and icons don’t need Raycast Target. Turning it off means clicks pass to the button underneath correctly, and it saves raycast work.
- A panel background that should block clicks needs Raycast Target on, even if it’s nearly transparent.
- A CanvasGroup with Blocks Raycasts off makes all its children ignore the pointer. Use it to make hidden menus non-blocking without disabling them.
To see what’s under the pointer, select the EventSystem in Play Mode. Its Inspector preview shows the current pointer target. That’s the quickest way to find a mystery blocker.
Blocker Panels and Modal Menus
For modal menus (inventory, pause, dialogue), checking pointer position isn’t enough. Keyboard and gamepad gameplay inputs should also stop. Better options:
- Switch action maps. With the Input System, disable the “Gameplay” action map and enable a “UI” map when a menu opens. Gameplay actions then can’t fire at all. This is the cleanest approach.
- A full-screen blocker. Put a transparent Image behind the menu covering the screen, with Raycast Target on, so world clicks are all blocked while the menu is open. Clicking it can close the menu.
- A game state flag. Gameplay scripts check
GameState.InMenubefore acting.
If your pause menu sets timeScale to 0, some time-based actions stop anyway, but click handlers in Update still run. See the pause menu guide.
Alternative: Let UI Events Drive World Clicks
Another approach is to let the EventSystem handle world clicks too. Add a Physics Raycaster (or Physics 2D Raycaster) to the camera, and implement IPointerClickHandler on world objects or on a large invisible ground collider:
using UnityEngine;
using UnityEngine.EventSystems;
public class Ground : MonoBehaviour, IPointerClickHandler
{
public void OnPointerClick(PointerEventData e)
{
Vector3 worldPoint = e.pointerCurrentRaycast.worldPosition;
// move the player to worldPoint
}
}
Because the EventSystem sorts UI in front of world objects, a click on a button never reaches the ground. No extra checks needed. This works well for click-to-move and strategy games.
🔧 UI frameworks that handle this for you
Some UI and input tools on the Asset Store manage modal menus and input routing out of the box. See our recommended Asset Store tools.
Troubleshooting
IsPointerOverGameObject always returns false
There’s no EventSystem, the Canvas has no Graphic Raycaster, or you’re calling it in an input callback. Poll in Update instead.
IsPointerOverGameObject always returns true
An invisible Image with Raycast Target covers the screen. Find it via the EventSystem’s Inspector preview.
Warning: “Calling IsPointerOverGameObject() from within event processing…”
Move the check out of the InputAction callback and into Update.
Clicks pass through on mobile only
Use the touch ID overload or Enhanced Touch per-touch checks.
Keyboard actions still work behind the menu
Pointer checks only cover the mouse. Disable the gameplay action map while menus are open.
FAQ
Does this work with UI Toolkit?
UI Toolkit handles input through its own panels, and how it interacts with the EventSystem depends on your setup, so test it. A reliable check is calling Pick on the panel with the pointer position (converted to panel space) and seeing whether it returns an element.
Is IsPointerOverGameObject expensive?
No. It uses results the EventSystem already calculated this frame.
Should I disable action maps or check UI?
Disable maps for modal menus. Use UI checks for HUD elements that are always on screen.
Why do my buttons not respond at all?
That’s a different problem: missing EventSystem, wrong input module or a blocker on top. See the UI button guide.
Can text block clicks?
Yes, if Raycast Target is on. Turn it off on text that isn’t interactive.
Reader questions
Asked by readers of this article and answered by AI. Behavior can differ between Unity versions, so test in yours.




Leave a Reply