Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
2
Question by Stardog · Dec 02, 2013 at 01:20 AM · raycastonmouseenteronmouseexit

Replacing OnMouseEnter/Exit/Down/etc with Raycasting

OnMouseDown/etc won't work in scenes with multiple cameras and one being Orthographic.

I think I've solved some of them (still need to add a LayerMask), but I'm not sure how do the OnMouseEnter/Exit properly. The issue is just sending the message once.

I was thinking just store the hoveredGO at all times, and check if it changes, but I'm not sure how to get the OnMouseExit to work doing this:

     public GameObject hoveredGO;
 
     void Update()
     {
         RaycastHit hitInfo = new RaycastHit();
         Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
 
         // OnMouseDown
         if (Input.GetMouseButtonDown(0))
         {
             if (Physics.Raycast(ray, out hitInfo))
             {
                 hitInfo.collider.SendMessage("OnMouseDown", SendMessageOptions.DontRequireReceiver);
             }
         }
 
         // OnMouseUp
         if (Input.GetMouseButtonUp(0))
         {
             if (Physics.Raycast(ray, out hitInfo))
             {
                 hitInfo.collider.SendMessage("OnMouseUp", SendMessageOptions.DontRequireReceiver);
             }
         }
 
         // OnMouseOver
         if (Physics.Raycast(ray, out hitInfo))
         {
             hitInfo.collider.SendMessage("OnMouseOver", SendMessageOptions.DontRequireReceiver);
         }
 
         // OnMouseEnter
         if (Physics.Raycast(ray, out hitInfo))
         {
             if (hitInfo.collider.gameObject != hoveredGO)
             {
                 hitInfo.collider.SendMessage("OnMouseEnter", SendMessageOptions.DontRequireReceiver);
                 hoveredGO = hitInfo.collider.gameObject;
             }
         }
     }
Comment
Add comment · Show 2
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image kromenak · Dec 02, 2013 at 01:56 AM 0
Share

All in all, I think your implementation is looking good, and re$$anonymous$$ds me quite a bit of the way we handle touch input on mobile devices.

To handle On$$anonymous$$ouseExit, you can check whether the raycast is still hitting hoveredGO on the next frame, which it looks like you are basically doing in On$$anonymous$$ouseEnter. I think that if hitInfo.collider.gameObject != hoveredGO, you can check if hoveredGO != null & send a message to hoveredGO with On$$anonymous$$ouseExit. The only caveat here is if hoveredGO changes because something else moved in front of it, and whether you care about that.

Couple other things I noticed:

1) You can probably just call Physics.Raycast a single time and use the result for all calculations, since you have to call it every frame to deal with On$$anonymous$$ouseOver anyway.

2) Depending on your game, you could run into issues with compound colliders and rigidbodies. Usually, if a raycast hits a rigidbody, you'll want to send the message to the parent rigidbody ins$$anonymous$$d of any individual collider in the rigidbody.

3) Really small thing, but I don't think you actually need to create a new RaycastHit object, since Physics.Raycast will "new" it for you.

Not submitting as an answer because I'm not sure if this is correct, but hope it helps!

avatar image Stardog · Dec 02, 2013 at 05:52 AM 0
Share

Yes, I based it on a script that makes On$$anonymous$$ouseDown work for touch. It helps, thank you.

3 Replies

· Add your reply
  • Sort: 
avatar image
4
Best Answer

Answer by Josh707 · Dec 02, 2013 at 03:36 AM

The way you have it now works, but I'd write it a little differently - All you need to do is have a way to remember what the mouse was doing in the previous frame, be it with a boolean or anything. I just chose to use an enum because the names make it simple to look at.

 public GameObject hoveredGO;
 public enum HoverState{HOVER, NONE};
 public HoverState hover_state = HoverState.NONE;
         
 void Update () {
     RaycastHit hitInfo = new RaycastHit();
     Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
             
     if(Physics.Raycast(ray, out hitInfo)){
         if(hover_state == HoverState.NONE){
             hitInfo.collider.SendMessage("OnMouseEnter", SendMessageOptions.DontRequireReceiver);
             hoveredGO = hitInfo.collider.gameObject;
         }
         hover_state = HoverState.HOVER;       
     }
     else{
         if(hover_state == HoverState.HOVER){
             hoveredGO.SendMessage("OnMouseExit", SendMessageOptions.DontRequireReceiver);
         }
         hover_state = HoverState.NONE;
     }
             
     if(hover_state == HoverState.HOVER){
         hitInfo.collider.SendMessage("OnMouseOver", SendMessageOptions.DontRequireReceiver); //Mouse is hovering
         if(Input.GetMouseButtonDown(0)){
             hitInfo.collider.SendMessage("OnMouseDown", SendMessageOptions.DontRequireReceiver); //Mouse down
         }
         if(Input.GetMouseButtonUp(0)){
             hitInfo.collider.SendMessage("OnMouseUp", SendMessageOptions.DontRequireReceiver); //Mouse up
         }
             
     }
 }


You don't need to use this, but the key here is just having a way to remember what the mouse was doing in the previous frame like the other person commented, so you can check if it only just entered or exited, or is staying over the object.

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Stardog · Dec 02, 2013 at 05:52 AM 0
Share

I think this is basically right, with just some adjustment. Thanks!

avatar image Josh707 · Dec 02, 2013 at 06:06 AM 0
Share

Cool, no problem!

avatar image
0

Answer by roisym · Jul 06, 2016 at 09:02 PM

This is what I used for multi-touch raycasting in a 2D game. It supports many types of messages. Since I'm very new to programing, I'm interested in any comments and advice on my code.

What I notice in both codes proposed above is that OnMouseDown, OnMouseOver, etc. messages are used. According to this post: http://answers.unity3d.com/questions/1064394/onmousedown-and-mobile.html its not good too use OnMouse events in mobile development (Unity has to dance through fiery hoops in every frame to make it work). Therefore IMO its better to use custom messages.

 public class TouchInput2D : MonoBehaviour {
 
     public LayerMask touchInputMask;
     private Camera cam;
     private List<GameObject> touchList = new List<GameObject>();
     private List<GameObject> touchListOld = new List<GameObject>();
     private RaycastHit2D hit;
     
     void Start ()
     {
         cam = this.GetComponent<Camera>();
     }
     void Update () 
     {
 #if UNITY_EDITOR || UNITY_STANDALONE
         if (Input.GetMouseButton(0) || Input.GetMouseButtonDown(0) || Input.GetMouseButtonUp(0))
         {
             touchListOld.Clear();
             touchListOld.AddRange(touchList);
             touchList.Clear();
      
             hit = Physics2D.Raycast(cam.ScreenToWorldPoint(Input.mousePosition), Vector2.zero, 1f, touchInputMask);
             if (hit.collider != null)
             {
                 GameObject recipent = hit.transform.gameObject;
                 touchList.Add(recipent);
                 
                 if (Input.GetMouseButtonDown(0))
                 {
                     recipent.SendMessage("OnTouchDown", hit.point, SendMessageOptions.DontRequireReceiver);
                 }
                 if (Input.GetMouseButtonUp(0))
                 {
                     recipent.SendMessage("OnTouchUp", hit.point, SendMessageOptions.DontRequireReceiver);
                 }
                 if (Input.GetMouseButton(0) && Input.GetMouseButtonDown(0) == false &&touchListOld.Contains(recipent) == false)
                 {
                     recipent.SendMessage("OnTouchEntered", hit.point, SendMessageOptions.DontRequireReceiver);
                 }
                 if (Input.GetMouseButton(0))
                 {
                     recipent.SendMessage("OnTouchStay", hit.point, SendMessageOptions.DontRequireReceiver);
                 }
             }
             foreach (GameObject g in touchListOld)
             {
                 if (!touchList.Contains(g) && g != null)
                 {
                     g.SendMessage("OnTouchExit", hit.point, SendMessageOptions.DontRequireReceiver);
                 }
             }
         }
 #endif
 
 #if UNITY_IOS
         if (Input.touchCount > 0)
         {
             touchListOld.Clear();
             touchListOld.AddRange(touchList);
             touchList.Clear();
             
             Touch[] currentTouches = Input.touches;
             for (int i = 0; i < Input.touchCount; i++)
             {
                 hit = Physics2D.Raycast(cam.ScreenToWorldPoint(currentTouches[i].position), Vector2.zero, 1f, touchInputMask);
                 if (hit.collider != null)
                 {
                     GameObject recipent = hit.transform.gameObject;
                     touchList.Add(recipent);
                     
                     if (currentTouches[i].phase == TouchPhase.Began)
                     {
                         recipent.SendMessage("OnTouchDown", hit.point, SendMessageOptions.DontRequireReceiver);
                     }
                     if (currentTouches[i].phase == TouchPhase.Ended)
                     {
                         recipent.SendMessage("OnTouchUp", hit.point, SendMessageOptions.DontRequireReceiver);
                     }
                     if (currentTouches[i].phase == TouchPhase.Stationary || currentTouches[i].phase == TouchPhase.Moved)
                     {
                         recipent.SendMessage("OnTouchStay", hit.point, SendMessageOptions.DontRequireReceiver);
                     }
                     if (currentTouches[i].phase == TouchPhase.Moved && currentTouches[i].phase != TouchPhase.Began && touchListOld.Contains(recipent) == false)
                     {
                         recipent.SendMessage("OnTouchEntered", hit.point, SendMessageOptions.DontRequireReceiver);
                     }
                     if (currentTouches[i].phase == TouchPhase.Moved)
                     {
                         recipent.SendMessage("OnTouchMoved", hit.point, SendMessageOptions.DontRequireReceiver);
                     }
                     if (currentTouches[i].phase == TouchPhase.Canceled)
                     {
                         recipent.SendMessage("OnTouchExit", hit.point, SendMessageOptions.DontRequireReceiver);
                     }
                 }
             }
             foreach (GameObject g in touchListOld)
             {
                 if (!touchList.Contains(g) && g != null)
                 {
                     g.SendMessage("OnTouchExit", hit.point, SendMessageOptions.DontRequireReceiver);
                 }
             }
         }
 #endif
     }
 }
 
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by unity_8o0VCZu0dFDNEw · Dec 25, 2020 at 05:54 PM

 using UnityEngine;
 
 internal class test : MonoBehaviour
 {
 
 
     public GameObject hoveredGO;
     public enum HoverState { HOVER, NONE };
     public HoverState hover_state = HoverState.NONE;
 
     public bool colour_Changed = false;
 
     private void Awake()
     {
         hoveredGO = gameObject;
     }
 
     void Update()
     {
         RaycastHit hitInfo = new RaycastHit();
         Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
 
         if (Physics.Raycast(ray, out hitInfo))
         {
             if (hover_state == HoverState.NONE && hitInfo.collider.gameObject == hoveredGO)
             {
                 colour_Changed = true;
 
                 gameObject.GetComponent<Renderer>().material.color = Color.red;
 
                 hitInfo.collider.SendMessage("OnMouseEnter", SendMessageOptions.DontRequireReceiver);
                 hoveredGO = hitInfo.collider.gameObject;
             }
             hover_state = HoverState.HOVER;
         }
         else
         {
             if (hover_state == HoverState.HOVER && colour_Changed == true)
             {
                 hoveredGO.SendMessage("OnMouseExit", SendMessageOptions.DontRequireReceiver);
 
                 gameObject.GetComponent<Renderer>().material.color = Color.blue;
 
                 colour_Changed = false;
             }
             hover_state = HoverState.NONE;
         }
 
         if (hover_state == HoverState.HOVER)
         {
             hitInfo.collider.SendMessage("OnMouseOver", SendMessageOptions.DontRequireReceiver); //Mouse is hovering
             if (Input.GetMouseButtonDown(0) && hitInfo.collider.gameObject == hoveredGO)
             {
                 hitInfo.collider.SendMessage("OnMouseDown", SendMessageOptions.DontRequireReceiver); //Mouse down
 
                 gameObject.GetComponent<Renderer>().material.color = Color.yellow;
             }
             if (Input.GetMouseButtonUp(0) && hitInfo.collider.gameObject == hoveredGO)
             {
                 hitInfo.collider.SendMessage("OnMouseUp", SendMessageOptions.DontRequireReceiver); //Mouse up
 
                 gameObject.GetComponent<Renderer>().material.color = Color.green;
             }
 
         }
     }
 
 
 }
 

However, this script can be used with more object without the problem that when you have 2 or more different gameobjects with the first script it becomes both objects red also if your mouse is only on one of this.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

22 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

How to detect mouse leaving / entering the game window? 1 Answer

OnMouseEnter/Exit not working when pressing button to advance scene 2 Answers

OnMouseExit Problems vs. RaycastAll 2 Answers

Can't seem to get OnMouseExit and Destroy(GameObject) to work properly 1 Answer

Instantiate object OnMouseOver, then delete the instantiated object OnMouseExit. 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges