Search Unity

  1. Check out the Unite LA keynote for updates on the Visual Effect Editor, the FPS Sample, ECS, Unity for Film and more! Watch it now!
    Dismiss Notice
  2. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  3. Improved Prefab workflow (includes Nested Prefabs!), 2D isometric Tilemap and more! Get the 2018.3 Beta now.
    Dismiss Notice
  4. Want more efficiency in your development work? Sign up to receive weekly tech and creative know-how from Unity experts.
    Dismiss Notice
  5. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice
  6. Want to see the most recent patch releases? Take a peek at the patch release page.
    Dismiss Notice

Placing prefabs on other objects without raycasts?

Discussion in 'Extensions & OnGUI' started by FeastSC2, Jun 25, 2018.

  1. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    458
    Whenever building tools to place prefabs quickly in your scene, it's common to use raycasting on some collider to know where the prefab should be created. For example in 3D, we raycast on a terrain to place the prefab directly on top of the terrain.

    I wanted to use the same concept for 2D: I double click with my mouse and it places the prefab on a pre-existing prefab if there are any, if not it goes to Z:0.

    The problem I have is that I don't want my 2d prefabs to have a 2d colliders as these colliders are not used in my game. So how can I detect if there is a sprite where I'm clicking on without using raycasts (specifically without using colliders on the sprites in my scene).
     
  2. Madgvox

    Madgvox

    Joined:
    Apr 13, 2014
    Posts:
    455
    Without implementing your own mesh or shader raycasting, the best in-built method to pick objects is the appropriately named HandleUtility.PickGameObject.
     
    FeastSC2 likes this.
  3. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    458
    Since I would like to know about multiple gameobjects in the cursor's direction, as if a line was cast from the mouse cursor towards infinity in the direction of: from the sceneView camera to the cursor. Is there something else I can use that achieves this?

    Here's how I previously did this with raycast:

    Code (CSharp):
    1.         Ray worldRay = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
    2.         var result = Physics.RaycastAll(worldRay, 100000f);
     
  4. Madgvox

    Madgvox

    Joined:
    Apr 13, 2014
    Posts:
    455
    If you still want to avoid implementing your own mesh raycasting system, you could add temporary colliders with hideFlags to your objects and raycast against them.

    However for maximum flexibility you'll probably want to be able to raycast against meshes. I've actually implemented this for my own projects. It's not actually that difficult, mainly just porting to C# some algorithms made by way smarter people than I. :)

    This is the algorithm I used for broad-phase collision: http://www.realtimerendering.com/resources/RTNews/html/rtnv21n1.html#art9
    This is the algorithm I used for triangle intersection: https://www.cs.utah.edu/~aek/research/triangle.pdf

    Here's an example of it in action (this mesh has no collider):
     
    FeastSC2 likes this.
  5. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    458
    I ended up succeeding to make it for what I needed with the simple HandleUtility.PickGameObject. The answer simply was using what you suggested and the ignoreObjects argument.


    Code (CSharp):
    1.         List<GameObject> ignoreList = new List<GameObject>();
    2.         var obj = HandleUtility.PickGameObject(Event.current.mousePosition, false);
    3.         if (obj)
    4.         {
    5.             while (LayerHelper.IsLocked(obj.layer)) // Don't place prefab on GameObjects with locked layers
    6.             {
    7.                 ignoreList.Add(obj);
    8.                 obj = HandleUtility.PickGameObject(Event.current.mousePosition, false, ignoreList.ToArray());
    9.             }
    10.         }
    That's a very cool result you got there! I'll make sure to implement this when I create a 3d game myself : )
     
    Madgvox likes this.