1

My Unity app so far allows the user to draw box-shaped meshes by clicking and dragging in the 3D scene.

Now I'd like to enable the user to click on one of these created meshes and interact with it.

I'm taking my first baby steps with the interactivity. I'd like to show (log) some basic info of the box, like the area of its base, when the user clicks on it. And when the box has been clicked on, I'd like its material color to change, showing that it has been selected.

Is the interaction with procedurally created meshes any different than interaction with regular game objects in Unity? Not sure where to start, since I'm new to game object interaction too. So, any help is appreciated.

Santiago Diaz
  • 51
  • 1
  • 4

1 Answers1

0

From the documentation:

OnMouseDown is called when the user has pressed the mouse button while over the Collider.

This event is sent to all scripts of the GameObject with Collider. Scripts of the parent or child objects do not receive this event.

So two key points there, one is that your GameObject needs a collider to trigger the OnMouseDown message, and two is that it will only fire OnMouseDown for scripts attached to the GameObject that has the collider.

After you make the mesh, add a mesh collider and set the custom mesh as the collider's mesh. Up to you to figure out how you want to receive and handle the OnMouseDown event though, I don't know enough about your project architecture to really make a thoughtful contribution there.

:EDIT:

Okay, so if you want to make a mesh and get OnMouseDown events from it, then you need to have a script on that mesh (with a collider also on that mesh). The problem might be that you want to have functionality from the script that created the mesh, so what can you do? Well, you can make a forwarding function! Consider something like:

public class MouseDownForwarder : MonoBehaviour
{
    private System.Action callback;

    public void ForwardTo(System.Action callback)
    {
        this.callback = callback;
    }

    public void OnMouseDown()
    {
        callback?.Invoke();
    }
}

So this is a script, it's a MonoBehaviour so you attach it to a GameObject, and if callback isn't null then you invoke it whenever that script gets an OnMouseDown event. Then, whenever you make a mesh:

 public class MeshMakingScript
{
    public void MakeMesh()
    {
        GameObject meshGO = new GameObject("your procedural thing");
        // Set the mesh, collider, etc.
        var forwarder = meshGO.AddComponent<MouseDownForwarder>();
        forwarder.ForwardTo(this.MouseDownReceiver);
    }

    public void MouseDownReceiver()
    {
        // Your functionality goes here.
    }
}

Now this is pretty handy - you make your mesh, attach a collider, then you attach this forwarding function. You pass your own MouseDownReceiver, which is just a System.Action (which in turn is a function that returns void) and then whenever someone clicks on your procedural thing the MouseDownForwarder gets that event and invokes the callback you give it.

Now maybe you want to know which gameObject you instantiated is calling home, in which case you just add a template argument to your System.Action and have the forwarder pass a reference to itself:

public class MouseDownForwarder : MonoBehaviour
{
    private System.Action<GameObject> callback;

    public void ForwardTo(System.Action<GameObject> callback)
    {
        this.callback = callback;
    }

    public void OnMouseDown()
    {
        callback?.Invoke(this.gameObject);
    }
}

Now whenever the MouseDownForwarder fires it hands the gameObject it's attached to off to whoever gave it the callback. You would receive it like:

public class MeshMakingScript
{
    public void MakeMesh()
    {
        GameObject meshGO = new GameObject("your procedural thing");
        // Set the mesh, collider, etc.
        var forwarder = meshGO.AddComponent<MouseDownForwarder>();
        forwarder.ForwardTo(this.MouseDownReceiver);
    }

    public void MouseDownReceiver(GameObject proceduralGameObject)
    {
        // Your functionality goes here.
    }
}

You could make the callback in the MouseDownForwarder be an event, and multiple people can get notifications, etc., but this is how you bridge that connection :)

Chuck
  • 1,977
  • 1
  • 17
  • 23
  • Thanks Chuck. Here's the algorithm in summary: 1. An empty GameObject has a script called MouseTargetBehavior 2. MouseTargetBehavior handles Input.GetMouseButtonDown() and Input.GetMouseButton() events. 3. To handle Input.GetMouseButtonDown(), MouseTargetBehavior calls a class that will create a new GameObject, and adds the MeshFilter and MeshRenderer to that new GameObject. If I were generating all procedural meshes on the same GameObject, I could add a Collider object and a script that handles OnMouseDown. I don't know how to do this on GameObjects created at runtime. – Santiago Diaz May 31 '22 at 22:27
  • @SantiagoDiaz So first if you've got an empty GameObject then there's no collider to receive the OnMouseDown event. But if you're working that out some other way and you need to get OnMouseDown callbacks from another GameObject then I'll edit the answer to show you how to pass a delegate. Basically you'll add a script to your procedural mesh that calls a function on the OnMouseDown event, and your MouseTargetBehavior script will give that a reference to itself. Putting the kids in bed now but I'll work the example out for you in about 30-40 minutes :) – Chuck May 31 '22 at 23:37
  • @SantiagoDiaz - see the edit :) – Chuck Jun 01 '22 at 00:53