Search Unity

Instantiate object on face of an other object [RESOLVE]

Discussion in 'Scripting' started by Yearl, Aug 28, 2015.

  1. Yearl

    Yearl

    Joined:
    Jun 26, 2015
    Posts:
    33
    Hi everybody !

    I can't find any answer for that ...
    I have a mountain mesh in my scene, and i want trees and rocks appears on his surface.

    My conditions are Y axis have to detect the height of the mountain at random X and Z.

    Only answers i could find was with a terrain mesh, but my mountain isnt a terrain and will never be a terrain.

    I suppose it's easy, but i block on it, anyone have solution ?
     
  2. gorbit99

    gorbit99

    Joined:
    Jul 14, 2015
    Posts:
    1,350
    You could start a raycast, at the top of the world, so its higher up than anything else in the scene. The point of the hit will be the placd.
     
  3. Yearl

    Yearl

    Joined:
    Jun 26, 2015
    Posts:
    33
    Thanks, any basic code for this ?

    I actually try to set up raycast but i don't really understand how it works :/
     
  4. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    raycast is like a laserpointer

    use Random.Range() to pick a random point in a 2d plane at a height well above the top of your mountain, i.e.

    Code (csharp):
    1.  
    2. Vector3 myRandomPoint = new Vector3(Random.Range(0f, maxWidth), 1000, Random.Range(0f, maxDepth));
    3.  
    (assuming mountain has dimensions 0-maxwidth, 0-maxdepth, <1000)
    then use a raycast "down"

    Code (csharp):
    1.  
    2. RaycastHit hit;
    3. if(Raycast(myRandomPoint, Vector3.down, out hit))
    4. {
    5. // do stuff with hit.point which is where the laserpointer hit the mountain
    6. }
    7.  
     
  5. georetro

    georetro

    Joined:
    Jan 18, 2013
    Posts:
    218
    Code (csharp):
    1. Physics.Raycast(Vector3 origin, Vector3 direction, RaycastHit hitInfo, float distance, int LayerMask);
    This is the basics of a Raycast. The parameters are very self explanatory. The origin is where the Raycast will be shot from, the direction is the way in which the Ray will move, the hitInfo stores information surrounding the colliders the Ray has hit. The next two parameters are optional: distance is the length of which the Ray spans, if you leave this then by default it is of infinite length, the LayerMask is used to selectively ignore colliders which the Ray hits.

    Here is an example:

    Code (csharp):
    1. public float height;
    2.  
    3. void Update()
    4. {
    5.      Ray positionRay = new Ray(transform.position, Vector3.down);
    6.      RaycastHit hit;
    7.  
    8.      if(Physics.Raycast(positionRay, out hit, height)
    9.      {
    10.           if(hit.collider.tag == "ground")
    11.           {
    12.                 DeployShoot();
    13.           }
    14.      }
    15. }
    16.  
    Here we check to see if we have hit a collider, with tag "ground", with our Ray. If we have then we call a method called DeployShoot(). Also this example can be found in the Unity tutorials, I used it because it is a simple but great example
     
    Last edited: Aug 28, 2015
  6. Yearl

    Yearl

    Joined:
    Jun 26, 2015
    Posts:
    33
    Ok thanks for answers,
    so if I put a layer int in "layermask" value, raycast will collide only with this layer, right ?
     
  7. georetro

    georetro

    Joined:
    Jan 18, 2013
    Posts:
    218
    @Yearl Yeah. If you wanted to make it so the Ray ignored a particular layer you would do this:

    Code (csharp):
    1. int layerMask = 1 << 8; // This bitshifts the index of the layer 8 to get a bitmask
    2. layerMask = ~layerMask; // The ~ operator inverts the bitmask so the layer is ignored
     
  8. Yearl

    Yearl

    Joined:
    Jun 26, 2015
    Posts:
    33
    Ok thanks, but right now have another problem ..

    Here's my script :

    On the instantiate of ground (can be plain, hill, or mount)
    Code (CSharp):
    1.  
    2.             int tempManyDecor = 1;
    3.             gameObject.GetComponent<InstantiateDecors>().ActiveInstanceDecors(zones[z], tempManyDecor);
    Done on each ground with a "for".

    And second one intantiate details (tree or rock)
    Code (CSharp):
    1.     public List<GameObject> woodDecors;
    2.  
    3.     public void ActiveInstanceDecors(GameObject thisZone, int howMany)
    4.     {
    5.         for(int d = 0; d < howMany; d++)
    6.         {
    7.             /*float minWidth = thisZone.transform.position.x-(thisZone.transform.localScale.x/3);
    8.             float maxWidth = thisZone.transform.position.x+(thisZone.transform.localScale.x/3);
    9.             float minDepth = thisZone.transform.position.z-(thisZone.transform.localScale.z/3);
    10.             float maxDepth = thisZone.transform.position.z+(thisZone.transform.localScale.z/3);*/
    11.  
    12.             Vector3 myRandomPoint = new Vector3(thisZone.transform.position.x,
    13.                                                 3000,
    14.                                                 thisZone.transform.position.z);
    15.  
    16.  
    17.             RaycastHit hit;
    18.             if(Physics.Raycast(myRandomPoint, Vector3.down, out hit))
    19.             {
    20.                 if(hit.collider.gameObject.layer == 12)
    21.                 {
    22.                     Debug.Log("Yay"+hit.collider.gameObject.name);
    23.                     GameObject tempDecor = (GameObject)Instantiate(woodDecors[0]);
    24.                     tempDecor.transform.parent = hit.collider.gameObject.transform;
    25.                     tempDecor.transform.position = hit.point;
    26.                     tempDecor.transform.localScale = new Vector3(0.05f,0.05f,0.05f);
    27.                 }
    28.             }
    29.         }
    30.     }
    31. }
    Then instantiate work, but only on my mounts !
    Don't know why ...

    Image ref (cones on mounts are mesh test for tree or rock) :

    http://postimg.org/image/ioh4388kt/



    EDIT: all ground are on same layer.
     
  9. georetro

    georetro

    Joined:
    Jan 18, 2013
    Posts:
    218
    @Yearl I'm a bit confused as to what exactly you want to achieve here as there is nothing wrong with the code you have.
     
  10. gorbit99

    gorbit99

    Joined:
    Jul 14, 2015
    Posts:
    1,350
    I would compact it down a little, and instead of this:
    Code (CSharp):
    1. GameObject tempDecor = (GameObject)Instantiate(woodDecors[0]);
    2. tempDecor.transform.position = hit.point;
    I would simply do this:
    Code (CSharp):
    1. GameObject tempDecor = (GameObject)Instantiate(woodDecors[0], hit.point, Quaternion.identity);
     
  11. Yearl

    Yearl

    Joined:
    Jun 26, 2015
    Posts:
    33
    Yeah thanks, always forgot to use all values of Instantiate().

    Sorry I'm not good to explain something :S

    I just find why it doesn't work with plains and hills .. I have some other colliders upper than ground boudaries, but mountains pass on it.

    I tried your solution to ignore a layer, but don't work .. I want to ignore layer 9 so I did :

    Code (CSharp):
    1. RaycastHit hit;
    2.             int layerMask = 1 << 9;
    3.             layerMask = ~layerMask;
    4.             if(Physics.Raycast(myRandomPoint, Vector3.down, out hit, layerMask))
    5.             {
    6.                 if(hit.collider.gameObject.layer == 12)
    7.                 {
    8.                     Debug.Log("Yay"+hit.collider.gameObject.name);
    9.                     GameObject tempDecor = (GameObject)Instantiate(woodDecors[0], hit.point, Quaternion.identity);
    10.                     tempDecor.transform.parent = hit.collider.gameObject.transform;
    11.                     tempDecor.transform.localScale = new Vector3(0.05f,0.05f,0.05f);
    12.                 }
    13.             }
    Where i'm wrong ?
     
  12. georetro

    georetro

    Joined:
    Jan 18, 2013
    Posts:
    218
    Well you did not state the distance in the Physics.Raycast parameter. This would be the code for the Raycast if you wanted an infinite Ray:

    Code (csharp):
    1. if(Physics.Raycast(myRandomPoint, Vector3.down, out hit, Mathf.Infinity, layermask))
     
  13. Yearl

    Yearl

    Joined:
    Jun 26, 2015
    Posts:
    33
    OK great !! Thanks, still working now !
    Thanks again to spend time on my case, bye !
     
  14. georetro

    georetro

    Joined:
    Jan 18, 2013
    Posts:
    218
    Glad I could help :) Best of luck to you