Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
12 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
0
Question by Un_Faced · Aug 26, 2018 at 11:27 PM · click objects

how to click in only one object at a time?

I have two objects (in an isometric view) in a way that one is in top of another. when I click on the object that is on top, te object behind seems to detect the click aswell, and that´s a problem (in my game). Is there a way to make the detect only the oject on the top? as it were "opaque".

I use void OnMouseDown() to detect the click in both GameObjects scripts.

thanks in advance!

Comment
Add comment · Show 8
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 rainChu · Aug 27, 2018 at 12:39 AM 0
Share

The general idea is to have a single object responsible for handling of clicks, and to have it perform the test for what you clicked on. Ins$$anonymous$$d of every object grabbing the mouse, this guy grabs the mouse and then gives it to a single object. I'll answer your question to describe the specific process for doing this, but to do that, I need to know more about what you want to click. Are you trying to click a 3D object, as with a Collider, or a UI element?

avatar image Un_Faced rainChu · Aug 27, 2018 at 12:45 AM 0
Share

I´m clicking 3D objects

avatar image Piyush_Pandey · Aug 27, 2018 at 06:56 AM 0
Share

You can use Raycast for detecting clicks ins$$anonymous$$d of On$$anonymous$$ouseDown. I will suggest that you use RaycastAll with a particular layer and length. Then you can decide which object to act upon from the raycast result. The reason for raycastall is, in your project you might later need to do task even when something is behind the front clicked object. It will come in handy.

avatar image rainChu Piyush_Pandey · Aug 27, 2018 at 11:21 AM 0
Share

I agree that RaycastAll is more future proof, but one of the tenets of producing code for a project is to not program future proofing for features that aren't planned. The code for plain old Raycast is much simpler to implement, and takes care of sorting distances for you. If you then later decide that you need to click on multiple objects, porting that function isn't hard at all. It's the rest of the codebase, that's designed to work with only one object, that's going to need the most refactoring. And that's going to need refactoring even if you use RaycastAll, because it's only going to be tested to work with one object.

avatar image malkere · Aug 27, 2018 at 11:56 AM 0
Share

"seems to"? That should be impossible shouldn't it? I don't work in isometric, but a mouseclick is just a raycast. Whatever it hits it hits, it doesn't keep going. Have you used debug.log on both scripts, etc.?

avatar image rainChu malkere · Aug 27, 2018 at 12:03 PM 0
Share

Wow, you're right. I should have tested this. I assumed that On$$anonymous$$ouseDown would just be called on all behaviours under the cursor in an undefined order.

avatar image Un_Faced malkere · Aug 27, 2018 at 02:44 PM 0
Share

yes, I used Debug.Log on both and i got both messages in the console

avatar image misher · Aug 27, 2018 at 12:29 PM 0
Share

On$$anonymous$$ouseDown is really old and bad practice, if you need some complex selection/clicking behaviour, you should go with centralised raycasting, otherwise you can simply attach button component or event trigger component to your object (and add raycaster component to the camera)

2 Replies

· Add your reply
  • Sort: 
avatar image
0

Answer by rainChu · Aug 27, 2018 at 11:54 AM

Edit: OnMouseDown should be called for only the topmost object, rendering this answer not a proper solution for your problem. I've left the code below though, because it still has benefits over OnMouseDown such as being able to be adapted for clicking on objects besides the topmost, and passing them data such as the hit normal or mouse depth.


You need a mouse manager class. Instead of OnMouseDown, you want to poll for the mouse button in the Update function of a single mouse manager. I want to clarify that using Update should be avoided when possible, because it adds code that's called every frame. We're going to do this here because there's only ever going to be one MouseManager so the cycles it takes up is insignificant. Try a MouseManager similar to this:

 public class MouseManager : MonoBehaviour
 {
     [SerializeField] private Camera m_camera;

     private void Update( )
     {
         // If the mouse button is down, call TestMouseClick.
         // We're testing instantly. If you want to only check for when the mouse cursor was pressed
         // down on an object, then lifted up on that same object, just keep track of the GameObject
         // the cursor was pressed on, and call OnClick on mouse up.
         if ( Input.GetMouseButtonDown( 0 ) )
             TestMouseClick();
     }
 
     private void TestMouseClick( )
     {
         // Get a ray representing the mouse cursor from the current camera.
         // m_camera should be a reference to the game's main camera you're seeing the objects from.
         Ray ray = m_camera.ScreenPointToRay( Input.mousePosition );
 
         // Create a layer mask containing just the objects you want to click.
         // This is so that if there's a non-clickable collider, it won't obstruct
         // a clickable collider. If you want a collider to block mouse click,
         // add it here.
         int layerMask = LayerMask.GetMask( "Ground", "Environment" );
 
         // Perform the raycast.
         RaycastHit raycastHit;
         if ( Physics.Raycast( ray, out raycastHit, Mathf.Infinity, layerMask ) )
         { // If something was hit:
 
             // Get every MonoBehaviour sibling of the topmost collider under the mouse cursor which
             // is an IClickableObject
             var hitClickableObjects = raycastHit.collider.GetComponents<IClickableObject>();
 
             // Call OnClick in each of them. This is so that if multiple MonoBehaviours on the single
             // clicked GameObject exist, OnClick will be called for all of them.
             foreach ( var clickableObject in hitClickableObjects )
                 // We're passing RaycastHit.point to the method. You can obviously define
                 // the interface to better suit your needs.
                 clickableObject.OnClick( raycastHit.point ); 
         }
     }
 }

Of course, you also need an interface. If you've never worked with those before, they're similar to classes in some ways. Namely, you can use the interface as a reference to the object. The interface the above MouseManager expects looks like this:

 /// <summary>
 /// An object that can be clicked by MouseManager
 /// </summary>
 interface IClickableObject
 {
     /// <summary>
     /// The object was clicked by MouseManager.
     /// </summary>
     /// <param name="mousePosition3D">The postiion, including depth, of the point
     /// under the mouse cursor</param>
     void OnClick( Vector3 mousePosition3D );
 }

And finally, on every MonoBehaviour you want to catch mouse clicks in, just implement that interface:

 public class MyCoolBehaviour : MonoBehaviour, IClickableObject
 {
     // ... Other methods, fields, properties ...
 
     // Implement the interface.
     public void OnClick( Vector3 mousePosition3D )
     {
         Debug.Log( "I was clicked at the following position: " + mousePosition3D );
     }
 
     // ... Other methods, fields, properties ...
 }

Just attach the MouseManager to a single GameObject, such as on the one your game manager or app manager is on. Good luck!

Comment
Add comment · Show 1 · 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 Un_Faced · Aug 27, 2018 at 03:01 PM 0
Share

I tried to implement it, but I dont really know how. I am sorry. You took your time to make that code and help me, but I cannot truly understand it due to my lack of knowledge. I copied the

 interface IClickableObject
  {
      /// <summary>
      /// The object was clicked by $$anonymous$$ouse$$anonymous$$anager.
      /// </summary>
      /// <param name="mousePosition3D">The postiion, including depth, of the point
      /// under the mouse cursor</param>
      void OnClick( Vector3 mousePosition3D );
  }

on the game$$anonymous$$anager script, and I also made a new script for interfaces, and then replace On$$anonymous$$ouseDown() for OnClick but it doesnt work either. anyways thanks for answering

avatar image
0

Answer by malkere · Aug 28, 2018 at 12:35 AM

What you're reporting is impossible in the normal sense. You said you've got Debug.Log() reports from two GameObjects with one click, and you're using OnMouseDown so that means a single frame, a single raycast. I assume that means you've got a reference mix up somewhere. When you click the mouse it just sends a raycast out and will call OnMouseDown on whatever it hits. We'll need more info to figure out what else is wrong with your setup.

Creating a fresh scene and a simple OnMouseDown script, it doesn't matter how many objects you put behind or in front of one another, only the first collider receives the OnMouseDown call, I just double checked.

Can you post your script?

Try adding:

 Debug.Log("Hi " + transform.name);

To the OnMouseDown and make sure your GameObjects have different names. Something isn't as it should be, but you can always track it down.

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

91 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 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 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 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 avatar image avatar image avatar image

Related Questions

Accessing variable in another script? 2 Answers

How do i do to return in Main Menu with Canvas? 0 Answers

use mouse click to pause/stop a transform rotate script on gameobject 1 Answer

C# disable 2 diffirent scripts OnTriggerEnter 1 Answer

Check if the Door was clicked through pointer 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