Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

2D raycasting C# help

Discussion in '2D' started by ShottyMonsta, May 23, 2014.

  1. ShottyMonsta

    ShottyMonsta

    Joined:
    May 23, 2014
    Posts:
    25
    I've created a script which I attach to an empty game object, the idea of the script is to cast 2 rays which will hit the ground in my game, I will then use the location of the 2 hit's and the origin of the game object to draw a triangular mesh. The mesh is to represent a vision cone from an enemy which travels along the top of the screen.

    Here is the error
    (it's occuring on line 42: "vertexTwo.x = hitPointLeft.transform.position.x;")

    ERROR:
    "NullReferenceException: Object reference not set to an instance of an object
    rayCast.generateMesh () (at Assets/Scripts/Cloud Monster/rayCast.cs:42)
    rayCast.Update () (at Assets/Scripts/Cloud Monster/rayCast.cs:34)"


    Here is the script:


    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class rayCast : MonoBehaviour {
    5.  
    6.     //Set up public ints for angle to rayCast at
    7.     public int leftAngle = 0;
    8.     public int rightAngle = 0;
    9.     //Create two vector2's to represent the directions of the two rayCasts;
    10.     Vector2 directionLeft = new Vector2 ();
    11.     Vector2 directionRight = new Vector2 ();
    12.     //Create two rayCast2D's to represent the collision locations of the rayCasts which will be updated each frame
    13.     RaycastHit2D hitPointLeft = new RaycastHit2D ();
    14.     RaycastHit2D hitPointRight = new RaycastHit2D ();
    15.  
    16.  
    17.     //Set the directions up
    18.     void Start () {
    19.         //Always keep the y values at -100 (i.e. well below the stage),
    20.         //then we can just update the x values to change where the cone is "looking"
    21.         directionLeft.x = this.transform.rotation.x - leftAngle;
    22.         directionLeft.y = this.transform.rotation.y - 100;
    23.         directionRight.x = this.transform.rotation.x + rightAngle;
    24.         directionRight.y = this.transform.rotation.y - 100;
    25.     }
    26.  
    27.     //Update the left/right hitPoint variables with the new collision location
    28.     //After I've got this set up I'll add in updating the rayCast direction each frame as well.
    29.     void Update () {
    30.         //This puts the  if the rayCast is hitting something, then puts the coordinates of the collision into the rayCast2D objects
    31.         hitPointLeft = Physics2D.Raycast (this.transform.position, directionLeft);
    32.         hitPointRight = Physics2D.Raycast (this.transform.position, directionRight);
    33.         //Run the generateMesh function to update the mesh position
    34.         generateMesh ();
    35.     }
    36.  
    37.  
    38.     void generateMesh () {
    39.         Debug.Log (hitPointLeft.transform);
    40.         //Create a vector3 to represent the 2nd vertex of the triangle
    41.         Vector3 vertexTwo = new Vector3();
    42.         vertexTwo.x = hitPointLeft.transform.position.x;
    43.         vertexTwo.y = hitPointLeft.transform.position.y;
    44.         vertexTwo.z = 0; //z = 0 because we're 2D
    45.            
    46.         //Create a vector3 to represent the 3rd vertex of the triangle
    47.         Vector3 vertexThree = new Vector3();
    48.         vertexThree.x = hitPointRight.transform.position.x;
    49.         vertexThree.y = hitPointRight.transform.position.y;
    50.         vertexThree.z = 0;  //z = 0 because we're 2D
    51.            
    52.         //Create a vector3 array to store the vertex locations
    53.         Vector3[] meshVerts = new Vector3[3];
    54.         meshVerts[0] = this.transform.position;
    55.         meshVerts[1] = vertexTwo;
    56.         meshVerts[2] = vertexThree;
    57.            
    58.         //Apply the vertex array to the mesh
    59.         Mesh visionCone = new Mesh();
    60.         visionCone.vertices = meshVerts;
    61.         visionCone.RecalculateBounds();
    62.            
    63.         //Add the mesh to a meshFilter attached to the game object
    64.         this.gameObject.GetComponent<MeshFilter> ().mesh = visionCone;
    65.         Graphics.DrawMeshNow(this.gameObject.GetComponent<MeshFilter>().mesh, this.transform.position, this.transform.rotation);
    66.     }
    67.  
    68.     //This will be run each frame and will remove the previous frames mesh
    69.     //STILL NEEDS DOING!
    70.     void garbageCollection () {
    71.  
    72.     }
    73. }
     
    Last edited: May 26, 2014
  2. ShottyMonsta

    ShottyMonsta

    Joined:
    May 23, 2014
    Posts:
    25
    Anyone got any ideas?
     
  3. Pyrian

    Pyrian

    Joined:
    Mar 27, 2014
    Posts:
    301
    Are those raycasts getting hits?
     
  4. ShottyMonsta

    ShottyMonsta

    Joined:
    May 23, 2014
    Posts:
    25
    Yes, I've tried logging the RaycastHit2D.point to the debug log and it would appear they are getting hits (the vector2 for the hit point changes as the various components of my scene move around indicating that the ray casts are hitting something).

    I've also used debug.drawRay() to check that my rays are casting in the correct direction, so I'm 99% sure that my rays are hitting stuff.

    I'm fairly sure my problem is actually in generating the mesh from the point data, I have tried logging the mesh vertex locations and it's showing that the mesh has recieved the vertices correctly, so it would appear the mesh is just not rendering to the screen. I've heard about normals, so I've rotated the camera around to see if the normals were pointing the wrong way but still not seeing any rendered mesh :-(

    Help me! :D



    UPDATE:

    I've removed the mesh renderer and mesh filter from the game object. I'm now adding them to the object when the script initializes.

    I then found the following post which seems to be similar to the problem I'm having (http://answers.unity3d.com/questions/140070/mesh-created-in-code-is-not-visible.html), I've basically copied and pasted the guys code into my own, replacing his hard coded vertex locations with my own procedural ones. I've left the .uv and .triangle properties the same as his own because I didn't understand the documentation for them...

    Now when I run my scene I'm seeing a purple mesh flicker around, it's not reflecting the shape I had envisioned which is making me think my rays are not firing where I think they are. But at least I'm making some progress.

    Here is my updated script:

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class rayCast : MonoBehaviour {
    5.    
    6.     //Set up public ints for angle to rayCast at
    7.     public int leftAngle = 0;
    8.     public int rightAngle = 0;
    9.     //Create two vector2's to represent the directions of the two rayCasts;
    10.     Vector2 directionLeft = new     Vector2 ();
    11.     Vector2 directionRight = new Vector2 ();
    12.     //Create two rayCast2D's to represent the collision locations of the rayCasts which will be updated each frame
    13.     RaycastHit2D hitPointLeft;
    14.     RaycastHit2D hitPointRight;
    15.    
    16.    
    17.     //Set the directions up
    18.     void Start () {
    19.         //Always keep the y values at -100 (i.e. well below the stage),
    20.         //then we can just update the x values to change where the cone is "looking"
    21.         directionLeft.x = this.transform.rotation.x - leftAngle;
    22.         directionLeft.y = this.transform.rotation.y - 100;
    23.         directionRight.x = this.transform.rotation.x + rightAngle;
    24.         directionRight.y = this.transform.rotation.y - 100;
    25.         //Add the mesh to a meshFilter attached to the game object
    26.         this.gameObject.AddComponent<MeshRenderer>();
    27.         this.gameObject.AddComponent<MeshFilter>();
    28.     }
    29.    
    30.     //Update the left/right hitPoint variables with the new collision location
    31.     //After I've got this set up I'll add in updating the rayCast direction each frame as well.
    32.     void Update () {
    33.         //This puts the  if the rayCast is hitting something, then puts the coordinates of the collision into the rayCast2D objects
    34.         hitPointLeft = Physics2D.Raycast (this.transform.position, directionLeft);
    35.         hitPointRight = Physics2D.Raycast (this.transform.position, directionRight);
    36.         //Run the generateMesh function to update the mesh position
    37.         generateMesh ();
    38.     }
    39.    
    40.    
    41.     void generateMesh () {
    42.         //Create a vector3 to represent the 2nd vertex of the triangle
    43.         Vector3 vertexTwo = new Vector3();
    44.         vertexTwo.x = hitPointLeft.transform.position.x;
    45.         vertexTwo.y = hitPointLeft.transform.position.y;
    46.         vertexTwo.z = 0; //z = 0 because we're 2D
    47.        
    48.         //Create a vector3 to represent the 3rd vertex of the triangle
    49.         Vector3 vertexThree = new Vector3();
    50.         vertexThree.x = hitPointRight.transform.position.x;
    51.         vertexThree.y = hitPointRight.transform.position.y;
    52.         vertexThree.z = 0;  //z = 0 because we're 2D
    53.        
    54.         //Create a vector3 array to store the vertex locations
    55.         Vector3[] meshVerts = new Vector3[3];
    56.         meshVerts[0] = this.transform.position;
    57.         meshVerts[1] = vertexTwo;
    58.         meshVerts[2] = vertexThree;
    59.        
    60.         //Apply the vertex array to the mesh
    61.         Mesh visionCone = new Mesh();
    62.         visionCone.vertices = new Vector3[] { this.transform.position, vertexTwo, vertexThree };
    63.         visionCone.uv = new Vector2[] { new Vector2(0, 0), new Vector2(0, 1), new Vector2(1, 1) };
    64.         visionCone.triangles = new int[] { 0, 1, 2 };
    65.         visionCone.RecalculateBounds();
    66.         visionCone.RecalculateNormals();
    67.  
    68.         this.gameObject.GetComponent<MeshFilter>().mesh = visionCone;
    69.  
    70.     }
    71.    
    72.     //This will be run each frame and will remove the previous frames mesh
    73.     //STILL NEEDS DOING!
    74.     void garbageCollection () {
    75.        
    76.     }
    77. }
     
    Last edited: May 26, 2014
  5. CoreyNW

    CoreyNW

    Joined:
    Jan 21, 2014
    Posts:
    17
    Did you try using a draw line to visually see the ray being cast?
     
  6. ShottyMonsta

    ShottyMonsta

    Joined:
    May 23, 2014
    Posts:
    25
    yes, I've actually made several big steps forward. I've got it displaying the mesh to the screen correctly, but it seems as though it's been translated and scaled down! I've no idea why the game object the script is attached to is translating because as you can see I've not entered any translations in my code... confused!

    Here is the updated code:

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class rayCast : MonoBehaviour {
    5.    
    6.     //Set up public ints for angle to rayCast at
    7.     public int leftAngle = 0;
    8.     public int rightAngle = 0;
    9.     //Create two vector2's to represent the directions of the two rayCasts;
    10.     Vector3 directionLeft;
    11.     Vector3 directionRight;
    12.     //Create two rayCast2D's to represent the collision locations of the rayCasts which will be updated each frame
    13.     Ray leftRay;
    14.     Ray rightRay;
    15.     RaycastHit hitPointLeft;
    16.     RaycastHit hitPointRight;
    17.  
    18.     //Set the directions up
    19.     void Start () {
    20.         //Always keep the y values at -100 (i.e. well below the stage),
    21.         //then we can just update the x values to change where the cone is "looking"
    22.         directionLeft = this.transform.rotation.eulerAngles;
    23.         directionLeft.y -= 90;
    24.         directionLeft.x -= 30;
    25.         directionRight = this.transform.rotation.eulerAngles;
    26.         directionRight.y -= 90;
    27.         directionRight.x += 30;
    28.         //Add the mesh to a meshFilter attached to the game object
    29.         this.gameObject.AddComponent<MeshRenderer>();
    30.         this.gameObject.AddComponent<MeshFilter>();
    31.     }
    32.    
    33.     //Update the left/right hitPoint variables with the new collision location
    34.     //After I've got this set up I'll add in updating the rayCast direction each frame as well.
    35.     void Update () {
    36.         directionLeft.x -= 1;
    37.         directionRight.x += 1;
    38.         leftRay = new Ray (this.transform.position, directionLeft);
    39.         if (Physics.Raycast (leftRay, out hitPointLeft)) {
    40.            
    41.         }
    42.         rightRay = new Ray (this.transform.position, directionRight);
    43.         if (Physics.Raycast (rightRay, out hitPointRight)) {
    44.  
    45.         }
    46.         Debug.DrawRay (this.transform.position, directionLeft);
    47.         Debug.DrawRay (this.transform.position, directionRight);
    48.         //Run the generateMesh function to update the mesh position
    49.         generateMesh ();
    50.     }
    51.    
    52.    
    53.     void generateMesh () {
    54.         //Create a vector3 to represent the 2nd vertex of the triangle
    55.         Vector3 vertexTwo = hitPointLeft.point;
    56.  
    57.         //Create a vector3 to represent the 3rd vertex of the triangle
    58.         Vector3 vertexThree = hitPointRight.point;
    59.        
    60.  
    61.         //Apply the vertex array to the mesh
    62.         Mesh visionCone = new Mesh();
    63.         visionCone.vertices = new Vector3[] { new Vector3 (0, 0, 0), vertexTwo, vertexThree };
    64.         visionCone.uv = new Vector2[] { new Vector2(0, 0), new Vector2(0, 1), new Vector2(1, 1) };
    65.         visionCone.triangles = new int[] { 0, 1, 2 };
    66.         visionCone.RecalculateBounds();
    67.         visionCone.RecalculateNormals();
    68.  
    69.         this.gameObject.GetComponent<MeshFilter>().mesh = visionCone;
    70.  
    71.     }
    72.    
    73.     //This will be run each frame and will remove the previous frames mesh
    74.     //STILL NEEDS DOING!
    75.     void garbageCollection () {
    76.        
    77.     }
    78. }
     
    Last edited: May 26, 2014
  7. Pyrian

    Pyrian

    Joined:
    Mar 27, 2014
    Posts:
    301
    Is it a child object?
     
  8. ShottyMonsta

    ShottyMonsta

    Joined:
    May 23, 2014
    Posts:
    25
  9. Pyrian

    Pyrian

    Joined:
    Mar 27, 2014
    Posts:
    301
    Could the translations and scaling you're seeing be related to the parent object being translated or scaled? That will also apply to child objects.
     
  10. ShottyMonsta

    ShottyMonsta

    Joined:
    May 23, 2014
    Posts:
    25
    No because no translation is being applied to the parent object, not via script nor in any other way :-(

    You could test this by creating a new empty scene, placing a new cube object to act as the ground (you'll need to scale its x to be nice and wide so the rays have enough ground to hit), then you can create a totally empty game object above the ground and attach the script to it. Then click play and see what happens!


    UPDATE:

    Fixed it, here's the updated code:


    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class rayCast : MonoBehaviour {
    5.    
    6.     //Set up public ints for angle to rayCast at
    7.     public int coneAngle = 0;
    8.     public int lookDistance = 0;
    9.     public int lookSpeed = 0;
    10.     public string direction = "left";  
    11.     int distanceTravelled = 0;
    12.     //Create two vector2's to represent the directions of the two rayCasts;
    13.     Vector3 directionLeft;
    14.     Vector3 directionRight;
    15.     //Create two rayCast2D's to represent the collision locations of the rayCasts which will be updated each frame
    16.     Ray leftRay;
    17.     Ray rightRay;
    18.     RaycastHit hitPointLeft;
    19.     RaycastHit hitPointRight;
    20.  
    21.  
    22.     //Set the directions up
    23.     void Start () {
    24.         //Always keep the y values at -100 (i.e. well below the stage),
    25.         //then we can just update the x values to change where the cone is "looking"
    26.         directionLeft = this.transform.rotation.eulerAngles;
    27.         directionLeft.y -= 90;
    28.         directionLeft.x -= coneAngle;
    29.         directionRight = this.transform.rotation.eulerAngles;
    30.         directionRight.y -= 90;
    31.         directionRight.x += coneAngle;
    32.     }
    33.    
    34.     //Update the left/right hitPoint variables with the new collision location
    35.     //After I've got this set up I'll add in updating the rayCast direction each frame as well.
    36.     void Update () {
    37.         if (direction == "left") {
    38.             directionLeft.x -= lookSpeed;
    39.             directionRight.x -= lookSpeed;
    40.             distanceTravelled -= lookSpeed;
    41.         }
    42.         else if (direction == "right") {
    43.             directionLeft.x += lookSpeed;
    44.             directionRight.x += lookSpeed;
    45.             distanceTravelled += lookSpeed;
    46.         }
    47.         if (distanceTravelled <= -lookDistance) {
    48.             direction = "right";
    49.         }
    50.  
    51.         else if (distanceTravelled >= lookDistance) {
    52.             direction = "left";
    53.         }
    54.  
    55.         leftRay = new Ray (this.transform.position, directionLeft);
    56.         if (Physics.Raycast (leftRay, out hitPointLeft)) {
    57.            
    58.         }
    59.  
    60.         rightRay = new Ray (this.transform.position, directionRight);
    61.         if (Physics.Raycast (rightRay, out hitPointRight)) {
    62.            
    63.         }
    64.  
    65.         Debug.DrawRay (this.transform.position, directionLeft);
    66.         Debug.DrawRay (this.transform.position, directionRight);
    67.         //Run the generateMesh function to update the mesh position
    68.         generateMesh ();
    69.     }
    70.    
    71.    
    72.     void generateMesh () {
    73.         //Create a vector3 to represent the 2nd vertex of the triangle
    74.         Vector3 vertexTwo = hitPointLeft.point;
    75.        
    76.         //Create a vector3 to represent the 3rd vertex of the triangle
    77.         Vector3 vertexThree = hitPointRight.point;
    78.  
    79.         GameObject newCone = new GameObject ("Cone");
    80.         newCone.transform.position = new Vector3 (0, 0, 0);
    81.         newCone.gameObject.AddComponent<MeshRenderer> ();
    82.         newCone.gameObject.AddComponent<MeshFilter> ();
    83.         newCone.gameObject.AddComponent<PolygonCollider2D> ();
    84.         newCone.gameObject.AddComponent<visionCollision> ();
    85.         newCone.gameObject.AddComponent<Rigidbody2D> ();
    86.         newCone.gameObject.GetComponent<Rigidbody2D> ().gravityScale = 0;
    87.  
    88.        
    89.         //Apply the vertex array to the mesh
    90.         Mesh visionCone = new Mesh();
    91.         visionCone.vertices = new Vector3[] { this.transform.position, vertexTwo, vertexThree };
    92.         visionCone.uv = new Vector2[] { new Vector2(0, 0), new Vector2(0, 1), new Vector2(1, 1) };
    93.         visionCone.triangles = new int[] { 0, 1, 2 };
    94.         visionCone.RecalculateBounds();
    95.         visionCone.RecalculateNormals();
    96.  
    97.         newCone.gameObject.GetComponent<PolygonCollider2D>().points = new Vector2[] {  this.transform.position, vertexTwo, vertexThree };
    98.         newCone.gameObject.GetComponent<PolygonCollider2D>().isTrigger = true;
    99.         newCone.gameObject.GetComponent<MeshFilter>().mesh = visionCone;
    100.  
    101.         Destroy (newCone, 0.01f);
    102.     }
    103.  
    104.     void generateCollider () {
    105.         //Create a vector3 to represent the 2nd vertex of the triangle
    106.         Vector2 vertexTwo = hitPointLeft.point;
    107.         //Create a vector3 to represent the 3rd vertex of the triangle
    108.         Vector2 vertexThree = hitPointRight.point;
    109.         //Apply the vertex array to the mesh
    110.         this.gameObject.GetComponent<PolygonCollider2D> ().points = new Vector2[] { new Vector2 (this.transform.localPosition.x, this.transform.localPosition.y), vertexTwo, vertexThree };
    111.         this.gameObject.GetComponent<PolygonCollider2D> ().isTrigger = true;
    112.     }
    113.  
    114.     //This will be run each frame and will remove the previous frames mesh
    115.     //STILL NEEDS DOING!
    116.     void garbageCollection () {
    117.  
    118.     }
    119. }
     
    Last edited: May 27, 2014