using System; using System.Collections; using System.Reflection; namespace UnityEngine { internal class SendMouseEvents { struct HitInfo { public GameObject target; public Camera camera; public void SendMessage (string name) { target.SendMessage (name, null, SendMessageOptions.DontRequireReceiver); } public static implicit operator bool (HitInfo exists) { return exists.target != null && exists.camera != null; } public static bool Compare (HitInfo lhs, HitInfo rhs) { return lhs.target == rhs.target && lhs.camera == rhs.camera; } } static HitInfo[] m_LastHit = { new HitInfo (), new HitInfo () }; static HitInfo[] m_MouseDownHit = { new HitInfo (), new HitInfo () }; static RaycastHit2D[] m_MouseRayHits2D = {new RaycastHit2D()}; [NotRenamed] static void DoSendMouseEvents (int mouseUsed, int skipRTCameras) { HitInfo[] currentHit = { new HitInfo (), new HitInfo () }; Vector3 mousePosition = Input.mousePosition; Camera[] cameras = Camera.allCameras; // If UnityGUI has the mouse over, we simply don't do any mouse hit detection. // That way, it will appear as if the mouse has missed everything. if (mouseUsed == 0) { foreach (Camera camera in cameras) { // we do not want to check cameras that are rendering to textures, starting with 4.0 if (skipRTCameras != 0 && camera.targetTexture != null) continue; // Is the mouse inside the cameras viewport? Rect rect = camera.pixelRect; if (!rect.Contains (mousePosition)) continue; // Did we hit any gui elements? GUILayer layer = (GUILayer)camera.GetComponent (typeof (GUILayer)); if (layer) { GUIElement element = layer.HitTest (mousePosition); if (element) { currentHit[0].target = element.gameObject; currentHit[0].camera = camera; } } #if ENABLE_PHYSICS || ENABLE_2D_PHYSICS // There is no need to continue if the camera shouldn't be sending out events if ((int)camera.eventMask == 0) continue; #if ENABLE_PHYSICS // Did we hit any colliders? RaycastHit hit; if (camera.farClipPlane > 0.0f && Physics.Raycast (camera.ScreenPointToRay (mousePosition), out hit, camera.farClipPlane, camera.cullingMask & camera.eventMask & Physics.DefaultRaycastLayers )) { if (hit.rigidbody) { currentHit[1].target = hit.rigidbody.gameObject; currentHit[1].camera = camera; } else { currentHit[1].target = hit.collider.gameObject; currentHit[1].camera = camera; } } #endif #if ENABLE_2D_PHYSICS // Did we hit any 2D colliders? else if (camera.farClipPlane > 0.0f) { // Did we hit any 2D colliders? if (Physics2D.GetRayIntersectionNonAlloc (camera.ScreenPointToRay (mousePosition), m_MouseRayHits2D, camera.farClipPlane, camera.cullingMask & camera.eventMask & Physics2D.DefaultRaycastLayers) == 1) { currentHit[1].camera = camera; if (m_MouseRayHits2D[0].rigidbody) currentHit[1].target = m_MouseRayHits2D[0].rigidbody.gameObject; else currentHit[1].target = m_MouseRayHits2D[0].collider.gameObject; } } #endif else { // We did not hit anything with a raycast from this camera. But our camera // clears the screen and renders on top of whatever was below, thus making things // rendered before invisible. So clear any previous hit we have found. if (camera.clearFlags == CameraClearFlags.Skybox || camera.clearFlags == CameraClearFlags.Color) { currentHit[1].target = null; currentHit[1].camera = null; } } #endif } } // i=0: CameraGUILayer, i=1: 3D Objects for (int i=0;i<2;i++) SendEvents(i, currentHit[i]); } /// /// Old-style mouse events used prior to the new event system of 4.2. /// static void SendEvents (int i, HitInfo hit) { // Handle MouseDown, MouseDrag, MouseUp bool mouseDownThisFrame = Input.GetMouseButtonDown(0); bool mousePressed = Input.GetMouseButton(0); if (mouseDownThisFrame) { if (hit) { m_MouseDownHit[i] = hit; m_MouseDownHit[i].SendMessage("OnMouseDown"); } } else if (!mousePressed) { if (m_MouseDownHit[i]) { // For button like behavior only fire this event if same as on MouseDown if (HitInfo.Compare(hit, m_MouseDownHit[i])) m_MouseDownHit[i].SendMessage("OnMouseUpAsButton"); // For backwards compatibility we keep the event name OnMouseUp m_MouseDownHit[i].SendMessage("OnMouseUp"); m_MouseDownHit[i] = new HitInfo(); } } else if (m_MouseDownHit[i]) { m_MouseDownHit[i].SendMessage("OnMouseDrag"); } // Handle MouseOver, MouseEnter, MouseExit if (HitInfo.Compare(hit, m_LastHit[i])) { if (hit) hit.SendMessage("OnMouseOver"); } else { if (m_LastHit[i]) { m_LastHit[i].SendMessage("OnMouseExit"); } if (hit) { hit.SendMessage("OnMouseEnter"); hit.SendMessage("OnMouseOver"); } } m_LastHit[i] = hit; } } }