Search Unity

Invisible Boundaries / Walls

Discussion in 'Made With Unity' started by BrettFromLA, Mar 31, 2010.

  1. BrettFromLA

    BrettFromLA

    Joined:
    Jan 29, 2009
    Posts:
    244
    Need invisible walls to keep your player non-players on a path, within the playing area, or out of a lake? I've got two simple scripts you might like.

    The first I call "fence posts". Here's how it works:
    1) attach this script to a tall, skinny cube or cylinder
    2) place the fence posts in a row
    3) for each fence post, drag the "next" fence post into the first fence post's inspector variable

    At runtime, the script connects each fence post to the "next" fence post. Pretty simple!

    You can also rotate these fence posts to be ceilings or floors. Be careful about "connecting" 2 fence posts that are seriously askew; you'll wind up with a tetrahedron (3-sided pyramid) between them, taking up more volume than you probably want.

    Here's the script:


    Code (csharp):
    1. /*
    2. Object scale is important.
    3.    x = small
    4.    y = BIG
    5.    z = small
    6. (The object is shaped like a pole, standing up.)
    7.  
    8. It can be rotated any direction.
    9.  
    10. In the Inspector, drag in the next fence post that this post should connect to.
    11.  
    12. */
    13.  
    14. //PUBLIC INSPECTOR VARIABLES
    15.  
    16. public var go_next_fence_post : GameObject;
    17.  
    18.  
    19. //PRIVATE VARIABLES
    20.  
    21. private var v3_distance : Vector3;
    22. private var v3_nextend1 : Vector3;
    23. private var v3_nextend2 : Vector3;
    24. private var v3_nexthalflength : Vector3;
    25. private var v3_thisend1 : Vector3;
    26. private var v3_thisend2 : Vector3;
    27. private var v3_thishalflength : Vector3;
    28.  
    29.  
    30. //MONOBEHAVIOUR FUNCTIONS
    31.  
    32. function Awake() {
    33.     //hide this fence post
    34.     Destroy(GetComponent(MeshRenderer));
    35.  
    36.     //is there another fence post?
    37.     if (go_next_fence_post != null) {
    38.  
    39.         //get Vector3's that are half the length of the fence pole heights, with the same rotations
    40.         v3_thishalflength = transform.TransformDirection(Vector3.up * transform.localScale.y / 2);
    41.         v3_nexthalflength = go_next_fence_post.transform.TransformDirection(Vector3.up * go_next_fence_post.transform.localScale.y / 2);
    42.  
    43.         //get the Vector3 that's the distance  direction between these two fence posts
    44.         v3_distance = go_next_fence_post.transform.position - transform.position;
    45.     }
    46. }
    47.  
    48. function Start() {
    49.     //connect it to another fence post?
    50.     if (go_next_fence_post != null) {
    51.         //normalize the scale of this object and set its rotation to nothin'
    52.         transform.localScale = Vector3(1,1,1);
    53.         transform.rotation.eulerAngles = Vector3(0,0,0);
    54.        
    55.         //create the mesh filter
    56.         if (GetComponent("MeshFilter") == null) {
    57.             gameObject.AddComponent("MeshFilter");
    58.         }
    59.         var ms_mesh : Mesh = GetComponent(MeshFilter).mesh;
    60.        
    61.         //create the 4 vertices
    62.         ms_mesh.Clear();
    63.         ms_mesh.vertices = [v3_thishalflength, -v3_thishalflength, v3_distance + v3_nexthalflength, v3_distance - v3_nexthalflength];
    64.    
    65.         //create 4 triangles between the 2 fence posts, to cover the space between them thoroughly.  Create each triangle in 2 ways (like 0,1,2 and 0,2,1) so they're impenetrable from both sides
    66.         ms_mesh.triangles = [0,1,2, 0,2,1, 0,1,3, 1,3,1, 0,2,3, 0,3,2, 1,2,3, 1,3,2];
    67.        
    68.         //remove all colliders
    69.         Destroy(GetComponent(BoxCollider));
    70.         Destroy(GetComponent(SphereCollider));
    71.         Destroy(GetComponent(CapsuleCollider));
    72.         Destroy(GetComponent(MeshCollider));
    73.         Destroy(GetComponent(WheelCollider));
    74.         Destroy(GetComponent(RaycastCollider));
    75.  
    76.         //create a mesh collider in this shape
    77.         gameObject.AddComponent("MeshCollider");
    78.         GetComponent("MeshCollider").mesh = ms_mesh;
    79.  
    80.         //make sure these doen't interfere with OnMouseOver
    81.         gameObject.layer = LayerMask.NameToLayer("Ignore Raycast");
    82.        
    83.     }
    84. }
    (This is the same script I came up with in http://forum.unity3d.com/viewtopic.php?t=45404.)

    Notice that there are very few triangles, just 4 per fence post, so the performance hit is unnoticeable.
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

    For craters and other holes in the ground, I improved the fence post code with an edge-finding routine. It's pretty simple too:
    1) attach the script to a game object (like a cube or sphere, so you can see it)
    2) position one (or more) edge-finder objects inside each crater or pit, slightly below ground level
    3) in the Inspector set
    --> the number of horizontal raycasts you want (these will be evenly distributed throughout 360 degrees)
    --> the height of wall you want it to create, using the edge finder's position as the base and extending upwards
    --> the raycast length (for an 80-unit-wide crater, set this to a little more than 40)

    Note: if you have an oddly-shaped crater, you'll probably want to place multiple edge-finders and/or increase the number of raycasts.

    Here's the script:

    Code (csharp):
    1. /*
    2. This creates invisible walls around holes in the terrain.
    3.  
    4. Attach this script to an object.  Place one or more of the objects in a crater or other hole in the terrain, slighty below ground level.  During Awake() this script sends out multiple raycasts, horizontally, to find the edges of the hole.  It connects those points in an uneven "circle" and raises a wall straight upwards along the perimeter.
    5.  
    6. For irregularly shaped holes, place a few of the objects and/or increase the number of raycasts.
    7.  
    8. */
    9.  
    10. //PUBLIC INSPECTOR VARIABLES
    11.  
    12. public var i_numberofraycasts : int = 16; //number of vertical "fenceposts" to place; these are evenly distributed throughout 360 degrees on a horizontal plane
    13. public var i_wallheight : int = 30; //height of each fencepost (wall portion)
    14. public var i_raycastlength : int = 50; //maximum length each raycast will extend
    15.  
    16.  
    17. //PRIVATE VARIABLES
    18.  
    19. private var ms_mesh : Mesh;
    20. private var aj_triangles = new Array(); //int array
    21. private var aj_vertices = new Array(); //Vector3 array
    22.  
    23.  
    24. //MONOBEHAVIOUR FUNCTIONS
    25.  
    26. function Awake() {
    27.     var fl_rotation : float;
    28.     var i_raycasts : int;
    29.     var i_vertices_index : int;
    30.     var mr_meshrenderer : MeshRenderer;
    31.     var mr_meshrenderers;
    32.     var r_ray : Ray;
    33.     var rh_hit : RaycastHit;
    34.     var v3_edgepoint : Vector3;
    35.     var v3_rotation : Vector3;
    36.    
    37.     //hide this object and its children
    38.     mr_meshrenderers = GetComponentsInChildren(MeshRenderer);
    39.     for (mr_meshrenderer in mr_meshrenderers) {
    40.         Destroy(mr_meshrenderer);
    41.     }
    42.  
    43.     //normalize the scale of this object and set its rotation to nothin'
    44.     transform.localScale = Vector3(1,1,1);
    45.     transform.rotation.eulerAngles.x = 0;
    46.     transform.rotation.eulerAngles.y = 0;
    47.     transform.rotation.eulerAngles.z = 0;
    48.    
    49.     //create the mesh filter
    50.     if (GetComponent("MeshFilter") == null) {
    51.         gameObject.AddComponent("MeshFilter");
    52.     }
    53.     ms_mesh = GetComponent(MeshFilter).mesh;
    54.  
    55.     //find the edges of the hole; add a "fence post" at each point
    56.     i_vertices_index = 0;
    57.     v3_rotation = transform.TransformDirection (Vector3.forward);
    58.     for (i_raycasts = 0; i_raycasts < i_numberofraycasts; i_raycasts++) {
    59.         //rotate this game object and get the ray to cast
    60.         fl_rotation = i_raycasts * (360/i_numberofraycasts);
    61.         transform.rotation.eulerAngles.y = fl_rotation;
    62.         r_ray = new Ray (transform.position, transform.TransformDirection(Vector3.forward));
    63.        
    64.         //get the wall edge point
    65.         if (Physics.Raycast(r_ray, rh_hit, i_raycastlength)) {
    66.             v3_edgepoint = rh_hit.point;
    67.             v3_edgepoint = v3_edgepoint - transform.position; //they're IN this game object, so cancel out the position of it.  Otherwise, they'll wind up somewhere else.
    68.         } else {
    69.             v3_edgepoint = Vector3(Random.Range(0,0.2), Random.Range(0,0.2), Random.Range(0,0.2)); //dummy value
    70.         }
    71.        
    72.         //add a "fence post" (at the wall edge point) to the array of vertices
    73.         aj_vertices[i_vertices_index] = v3_edgepoint;
    74.         i_vertices_index++;
    75.         aj_vertices[i_vertices_index] = v3_edgepoint + (Vector3.up * i_wallheight);
    76.         i_vertices_index++;
    77.     }
    78.    
    79.     //create walls between each of the "fence posts"
    80.     for (i_raycasts = 0; i_raycasts < (i_numberofraycasts-1); i_raycasts++) {
    81.         doTriangles(i_raycasts, (i_raycasts*2) + 0, (i_raycasts*2) + 1, (i_raycasts*2) + 2, (i_raycasts*2) + 3);
    82.     }
    83.    
    84.     //create one more wall between the last and the first "fence posts"
    85.     i_raycasts = (i_numberofraycasts-1);
    86.     doTriangles(i_raycasts, (i_raycasts*2) + 0, (i_raycasts*2) + 1, 0, 1);
    87.  
    88. }
    89.  
    90. function Start() {
    91.     //assign the vertices  triangles for this mesh
    92.     ms_mesh.Clear();
    93.     ms_mesh.vertices = aj_vertices;
    94.     ms_mesh.RecalculateBounds();
    95.     ms_mesh.triangles = aj_triangles;
    96.    
    97.     //remove all colliders
    98.     Destroy(GetComponent(BoxCollider));
    99.     Destroy(GetComponent(SphereCollider));
    100.     Destroy(GetComponent(CapsuleCollider));
    101.     Destroy(GetComponent(MeshCollider));
    102.     Destroy(GetComponent(WheelCollider));
    103.     Destroy(GetComponent(RaycastCollider));
    104.  
    105.     //create a mesh collider in this shape
    106.     gameObject.AddComponent("MeshCollider");
    107.     GetComponent("MeshCollider").mesh = ms_mesh;
    108.  
    109.     //un-rotate this object
    110.     transform.rotation.eulerAngles.x = 0;
    111.     transform.rotation.eulerAngles.y = 0;
    112.     transform.rotation.eulerAngles.z = 0;
    113.  
    114.     //make sure these don't interfere with OnMouseOver
    115.     gameObject.layer = LayerMask.NameToLayer("Ignore Raycast");
    116.  
    117.     //clear out global variables so they don't waste memory
    118.     ms_mesh = null;
    119.     aj_triangles = null;
    120.     aj_vertices = null;
    121. }
    122.  
    123.  
    124. // PRIVATE FUNCTIONS
    125.  
    126. private function doTriangles(i_index_fp : int, i_1_fp : int, i_2_fp : int, i_3_fp : int, i_4_fp : int) {
    127.     //create 4 triangles between each consecutive pair of "fence posts", to cover the space between them thoroughly.  Create each triangle in 2 ways (like 0,1,2 and 0,2,1) so it's impenetrable from both sides
    128.     var i_index : int;
    129.     i_index = i_index_fp * 24;
    130.  
    131.     //triangle 1, version 1
    132.     aj_triangles[i_index + 0] = i_1_fp;
    133.     aj_triangles[i_index + 1] = i_2_fp;
    134.     aj_triangles[i_index + 2] = i_3_fp;
    135.    
    136.     //triangle 1, version 2
    137.     aj_triangles[i_index + 3] = i_1_fp;
    138.     aj_triangles[i_index + 4] = i_3_fp;
    139.     aj_triangles[i_index + 5] = i_2_fp;
    140.    
    141.     //triangle 2, version 1
    142.     aj_triangles[i_index + 6] = i_1_fp;
    143.     aj_triangles[i_index + 7] = i_2_fp;
    144.     aj_triangles[i_index + 8] = i_4_fp;
    145.    
    146.     //triangle 2, version 2
    147.     aj_triangles[i_index + 9] = i_1_fp;
    148.     aj_triangles[i_index + 10] = i_4_fp;
    149.     aj_triangles[i_index + 11] = i_2_fp;
    150.    
    151.     //triangle 3, version 1
    152.     aj_triangles[i_index + 12] = i_1_fp;
    153.     aj_triangles[i_index + 13] = i_3_fp;
    154.     aj_triangles[i_index + 14] = i_4_fp;
    155.    
    156.     //triangle 3, version 2
    157.     aj_triangles[i_index + 15] = i_1_fp;
    158.     aj_triangles[i_index + 16] = i_4_fp;
    159.     aj_triangles[i_index + 17] = i_3_fp;
    160.    
    161.     //triangle 4, version 1
    162.     aj_triangles[i_index + 18] = i_2_fp;
    163.     aj_triangles[i_index + 19] = i_3_fp;
    164.     aj_triangles[i_index + 20] = i_4_fp;
    165.  
    166.     //triangle 4, version 2
    167.     aj_triangles[i_index + 21] = i_2_fp;
    168.     aj_triangles[i_index + 22] = i_4_fp;
    169.     aj_triangles[i_index + 23] = i_3_fp;
    170. }
    It only runs once, when the scene is loaded, and it creates very few triangles (negligible performance hit). As for the raycasts,when the scene loads on my moderately slow computer it takes about 0.24 seconds to do 1500 (one thousand five hundred) raycasts.

    Love to hear your comments!
     
  2. magictroll

    magictroll

    Joined:
    Mar 30, 2010
    Posts:
    27
    Was looking for something like this! Thanks a million, I'll let you know if it works out ;)
     
  3. thellama

    thellama

    Joined:
    Mar 25, 2010
    Posts:
    360
    Great scripts, many thanks!
     
  4. propellerhed

    propellerhed

    Joined:
    Apr 1, 2010
    Posts:
    1
    A slightly more lo-fi way of doing this is to build the geometry you want to act as the invisible wall, ensure you assign a collider to when you import, then in the hierarchy just tick off 'Mesh Renderer'. The object will still be there but be invisible.
     
  5. BrettFromLA

    BrettFromLA

    Joined:
    Jan 29, 2009
    Posts:
    244
    Thanks for the comments! I really like hearing from anyone who uses (or even just likes) my scripts. :D
     
  6. Direni

    Direni

    Joined:
    Nov 24, 2009
    Posts:
    21
    Is this configured to work for only the player (ie the "walls" will not block other objects like rockets or rigid bodes)?

    If not is there a simple way to set that up?

    Thanks
     
  7. BrettFromLA

    BrettFromLA

    Joined:
    Jan 29, 2009
    Posts:
    244
    As programmed, the walls block everything. Layers and colliders don't work together, per http://forum.unity3d.com/viewtopic.php?t=44707. But I'm pretty sure you can use Physics.IgnoreCollision (collider1, collider2) in the wall-making code. collider1 is the wall piece, and collider2 will have to be every thing that should ignore the walls. (As far as I can tell. I haven't tested this.)

    When you get it working, post the solution back here!
     
  8. DigitalX

    DigitalX

    Joined:
    Aug 26, 2012
    Posts:
    10
    No offense but this is terrible. All you have to do is create a box and remove the mesh render which makes it invisilbe thats it, no need for coding. And it blocks everything.
     
    Last edited: Sep 18, 2012
  9. Fenrisul

    Fenrisul

    Joined:
    Jan 2, 2010
    Posts:
    618
    Well I don't think you're too swell either :O
     
  10. Ryebread04

    Ryebread04

    Joined:
    Apr 6, 2016
    Posts:
    4
    This is exactly what I was looking for but it doesn't seem to work on the version im using so I edited it to work (Unity 5.3.5)
    Feel free to comment anything I did wrong or if you know a better way of doing it

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class invisBarrier : MonoBehaviour
    5. {
    6.     //PUBLIC INSPECTOR VARIABLES
    7.     public GameObject go_next_fence_post;
    8.  
    9.     //PRIVATE VARIABLES
    10.     private Vector3 v3_distance;
    11.     private Vector3 v3_nextend1;
    12.     private Vector3 v3_nextend2;
    13.     private Vector3 v3_nexthalflength;
    14.     private Vector3 v3_thisend1;
    15.     private Vector3 v3_thisend2;
    16.     private Vector3 v3_thishalflength;
    17.  
    18.  
    19.  
    20.  
    21.     void Awake()
    22.     {
    23.         Destroy (GetComponent<MeshRenderer> ()); //hide this fence post
    24.  
    25.         if (go_next_fence_post != null) //is there another fence post?
    26.         {
    27.             //get Vector3's that are half the length of the fence pole heights, with the same rotations
    28.             v3_thishalflength = transform.TransformDirection(Vector3.up * transform.localScale.y / 2);
    29.             v3_nexthalflength = go_next_fence_post.transform.TransformDirection(Vector3.up * go_next_fence_post.transform.localScale.y / 2);
    30.  
    31.             //get the Vector3 that's the distance  direction between these two fence posts
    32.             v3_distance = go_next_fence_post.transform.position - transform.position;
    33.         }
    34.     }
    35.  
    36.  
    37.  
    38.  
    39.     void Start()
    40.     {
    41.         //connect it to another fence post?
    42.         if (go_next_fence_post != null)
    43.         {
    44.             //normalize the scale of this object and set its rotation to nothin'
    45.             transform.localScale = new Vector3(1,5,1); //Sets the scale of the barrier(Change the 5 to make it higher or lower)
    46.             transform.rotation = new Quaternion(0,0,0,0); //Sets the rotation
    47.  
    48.             //create the mesh filter
    49.             if (GetComponent<MeshFilter>() == null) {
    50.                 gameObject.AddComponent<MeshFilter>();
    51.             }
    52.             Mesh ms_mesh = GetComponent<MeshFilter>().mesh;
    53.  
    54.             //create the 4 vertices
    55.             ms_mesh.Clear();
    56.             Vector3[] vertices = {v3_thishalflength, -v3_thishalflength, v3_distance + v3_nexthalflength, v3_distance - v3_nexthalflength};
    57.             ms_mesh.vertices = vertices;
    58.  
    59.  
    60.             //create 4 triangles between the 2 fence posts, to cover the space between them thoroughly. Create each triangle in 2 ways (like 0,1,2 and 0,2,1) so they're impenetrable from both sides
    61.             int[] triangles = {0,1,2, 0,2,1, 0,1,3, 1,3,1, 0,2,3, 0,3,2, 1,2,3, 1,3,2};
    62.             ms_mesh.triangles = triangles;
    63.  
    64.  
    65.             //remove all colliders
    66.             Destroy(GetComponent<BoxCollider>());
    67.             Destroy(GetComponent<SphereCollider>());
    68.             Destroy(GetComponent<CapsuleCollider>());
    69.             Destroy(GetComponent<MeshCollider>());
    70.             Destroy(GetComponent<WheelCollider>());
    71. //          Destroy(GetComponent<RaycastCollider>()); //Not A Thing And Not needed?
    72.  
    73.             //create a mesh collider in this shape
    74.             gameObject.AddComponent<MeshCollider>();
    75.             GetComponent<MeshCollider>().sharedMesh = ms_mesh; //Not Needed?
    76.          
    77.             //make sure these doen't interfere with OnMouseOver
    78.             gameObject.layer = LayerMask.NameToLayer("Ignore Raycast");
    79.         }
    80.     }
    81. }
     
  11. soni_saurabh

    soni_saurabh

    Joined:
    Jun 3, 2020
    Posts:
    7
    i have a contoured surface (not a standard geometry) and i have given it a mesh collider. however my player falls off the edge.

    Capture.PNG