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

Use raycastall to get the script with a certain class from a gameobject

Discussion in 'Scripting' started by Joris Albertus, Jun 21, 2016.

  1. Joris Albertus

    Joris Albertus

    Joined:
    Jun 21, 2016
    Posts:
    10
    So i want to use a raycastall in order to get a value from a script inside every object it hits, although i dont want to have to specify the name of the script which includes the class that holds the values im after, because it would be very confusing to have 5 different scripts with the same name attatched to different game objects to hold the values

    The raycastall is arranged so that it goes through every single hit inside a for loop after the raycastall has been activated, although i cant get it to take/find the class inside the current object with the information inside. Also keep in mind that i have multiple scripts inside most objects with the information im after.

    Thanks for any help, and im using c#
     
  2. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    can you provide the code? I've read what you've written a couple of times and it's not making a huge amount of sense; there also isn't a question, so I'm not sure what you're asking for help on... what is it not doing that you want it to do?
     
  3. Joris Albertus

    Joris Albertus

    Joined:
    Jun 21, 2016
    Posts:
    10
    The thing i want help on is getting the two variables, which are both located in a class named "ObjectData" inside a script attatched to the object that the raycast collided with, maybe this picture will clear it out
    test2.png
    I marked everything i couldnt get working in black inside the script, i know how to do the blue text, and the objects inside the picture
    Also, as described above, i dont want to have to refer to a script, but rather a class inside a script, so i dont end up with a lot of scripts named the same thing attatched to different objects in order to give them the data the raycast all needs
     
  4. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    I think this is the bit that is causing my confusion... if you want to attach something to a gameobject it pretty much has to either be a component (i.e. script), or be inside a component. You can't attach a "normal" class to a gameobject without a monobehaviour inheriting script (i.e. component) to hold it.


    Code (csharp):
    1.  
    2. // not tested this, but it should give the idea :D
    3. // normal c# class
    4. public class ObjectData
    5. {
    6.     public float a;
    7.     public string b;
    8.    
    9.     // constructor
    10.     public ObjectData()
    11.     {    }
    12. }
    13.  
    14. // unity component to be attached to the gameobject
    15. public class DataHolder : MonoBehaviour
    16. {
    17.     public ObjectData myData;
    18.    
    19.     void Start()
    20.     {
    21.         myData = new ObjectData();
    22.         myData.a = Random.Range(0f, 10f); // or whatever
    23.         myData.b = (Char)Random.Range(97, 122); // or whatever
    24.     }
    25. }
    26.  
    27. /// when raycasting (following on from your pseudo code example in the pic)
    28. // access the component
    29. DataHolder dh = hit[i].GetComponent<DataHolder>();
    30. // since myData is public directly access class and it's variables
    31. Debug.LogFormat("{0}, {1}", dh.myData.a, dh.myData.b);
    32.  
    Of source the question is then: why hold the data in "ObjectData" as a normal c# class if it has to reside inside a component, why not just have the variables you need inside "DataHolder"... but that might be driven more by whatever it is you're doing.
     
  5. awest

    awest

    Joined:
    Jul 12, 2014
    Posts:
    8
    If the class is in a script attached to the object then you already have a bunch of scripts with the same name on different objects. No?

    I assume the script has a reference like this.

    Code (csharp):
    1. public ObjectData objectData;
    The script with the class instance (objectData) is holding the information. not the class itself so you have to get the script component with the instance.

    Code (csharp):
    1.  var data = gameObject.GetComponent<Script>().objectData.var;
     
  6. Joris Albertus

    Joris Albertus

    Joined:
    Jun 21, 2016
    Posts:
    10
    Although, wouldnt this mean that i have to create a component called "DataHolder" for every single object with different data inside it? Like say for example the circle in the example image had the value "a" as 5, while the square had it as "1", wouldnt i have to create 2 different DataHolders, with the same name, but attatched to different gameobjects?
    Im going to have a lot of different values for different objects, so optimization both for the computer and for me is key.

    EDIT: Also, somehow objectData doesnt contain the definition of a and b?
     
    Last edited: Jun 21, 2016
  7. Joris Albertus

    Joris Albertus

    Joined:
    Jun 21, 2016
    Posts:
    10
    Although, thats what im trying to get away from, because if every objectData script has the same name, it will be really hard to separate them in the editor.
    I want basically to be able to name the file/script "circleObjectData", and then have the class "objectData" inside of it, which contains all of the information, and the raycastall will be able to find those values regardless of the name of the component/script which holds them, basically making it a lot easier if i apply the wrong objectData on a object, and if i want to edit a specific script with objectData.
     
  8. awest

    awest

    Joined:
    Jul 12, 2014
    Posts:
    8
    Are you making the different scripts for just organizational purposes?

    Wouldn't it be easier to have one script ObjectData that also has a name or type property? Or you could use Unity's tag system.

    If you're looking for optimization then you should be making flexible, reusable code rather than a bunch of different scripts that have repeated code.

    Depending on what your doing the script could even auto-populate the variables based on the type.
     
  9. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    two different instances of the same class attached to two different gameobject, yes. Two "different" DataHolders, not so much.

    do you mean "initialisation of a and b"? they're primitive datatypes so they dont need to be "defined". In the example I've just chosen to go with a simple empty constructor and initialise the variables "remotely" since they're declared as public. Private variables initialised inside a constructor also works, just different syntax.

    Code (csharp):
    1.  
    2. public class ObjectData
    3. {
    4.     private float _a;
    5.     private string _b;
    6.    
    7.     // constructor
    8.     public ObjectData(float a, string b)
    9.     {
    10.         _a = a,
    11.         _b = b;
    12.     }
    13. }
    14.  
    15. // unity component to be attached to the gameobject
    16. public class DataHolder : MonoBehaviour
    17. {
    18.     public ObjectData myData;
    19.    
    20.     void Start()
    21.     {
    22.         myData = new ObjectData( Random.Range(0f, 10f),  (Char)Random.Range(97, 122));
    23.     }
    24.     //...
    25.  
    just didn't feel that was as clear given the poor "example" variable names :p :)
     
    Joris Albertus likes this.
  10. Joris Albertus

    Joris Albertus

    Joined:
    Jun 21, 2016
    Posts:
    10
    Thanks, that fixed the problem, but i now get an error that "ObjectData" does not contain the definition of "myData" when doing

    Code (CSharp):
    1. Debug.LogFormat("{0}, {1}", dh.myData.a, dh.myData.b);
    Visual studio marked both "myData"

    I believe this is probably because

    Code (CSharp):
    1. DataHolder dh = hit[i].GetComponent<DataHolder>();
    doesnt get "myData", but instead only gets the class "DataHolder"
    Not sure how to fix it though

    Also, you have to use

    When getting the component off a raycast hit
    (Notice transform)
     
  11. Joris Albertus

    Joris Albertus

    Joined:
    Jun 21, 2016
    Posts:
    10
    Yeah, my main concern is holding it orginized, so i don't lose myself in multiple scripts with the same name
    Ive thought about using the tag solution, but i don't want to use it because it could limit other things down the line like AI scripts, etc

    Im not really sure how i could make this reusable though.
     
  12. Tetra

    Tetra

    Joined:
    May 22, 2013
    Posts:
    29
    hit .transform.getComponent <DataHolder>().myData
     
  13. Tetra

    Tetra

    Joined:
    May 22, 2013
    Posts:
    29
    I'm still really confused on what you're trying to do, and it might be because you are trying to do something that is either an incorrect practice or something?

    For instance, if you have a health script, you put that script on everything that you want to have health. You don't need 50 different health scripts. Then, let's say you have an Area of effect spell that damages enemies in an area. You do your raycast and now have a list of colliders

    Foreach Collider col in hit Colliers
    col.transform.getComponent <Health>().dealDamage (1)
     
  14. Joris Albertus

    Joris Albertus

    Joined:
    Jun 21, 2016
    Posts:
    10
    Thanks, that fixed it, although now i get an error "Object reference not set to an instance of an object" from that line when i try to use it?
    Will try to find the cause of this tommorow, if its too general or if there is something wrong on my end.
     
  15. Joris Albertus

    Joris Albertus

    Joined:
    Jun 21, 2016
    Posts:
    10
    Im probably not going to use this script for dealing damage, but rather for gathering information
    An example of the use of this would be if i shot a bullet through a wall and wanted a multiplier on the bullet slowdown while its in for example a wooden wall
    I would first measure the distance with two raycastall, then get the object material through this script, and then apply the value "a" from the example above as material density
     
  16. Tetra

    Tetra

    Joined:
    May 22, 2013
    Posts:
    29
    Ah okay. So something like

    hit.getComponent<Renderer>().material
     
  17. Joris Albertus

    Joris Albertus

    Joined:
    Jun 21, 2016
    Posts:
    10
    I get the error "renderer does not contain material" from using this
    And yes, ive replaced material with the name of the new class ive made
     
  18. Tetra

    Tetra

    Joined:
    May 22, 2013
    Posts:
    29
    It's probably on your MeshRenderer, so use that instead.
     
  19. JoshuaMcKenzie

    JoshuaMcKenzie

    Joined:
    Jun 20, 2015
    Posts:
    897
    All I'm hearing that that you just trying to re-invent the wheel here. making a class to hold ALL your data... thats what Gameobjects are for! with components "organizing" the data the gameobjects hold. I would simply test if a gameobject contains a component then just check the data that component holds. using the concept of object composition to filter out the gameobjects that don't matter. A Dataholder class that holds everything would mean that you'd have invest development into effectively filtering that data, because you'll be doing that a lot.

    So I must ask, do you really need to make this class, can you not simply use Gameobjects and monobehaviours together with object composition? or will this data holder class be able to do things that can't be done with monobehaviours (or ScriptableObjects if the data is scene-independent)

    MeshRenderer derives from Renderer, if Renderer didn't work then he likely raycasted to a gameobject that doesn't have a renderer component. you should always test if getComponent returns null before trying to use it. if it returned null, then it's likely a gameobject you don't want.
    Code (CSharp):
    1. for(int i=0;i<hits.length;i++)
    2. {
    3.     Renderer rend = hit[i].transform.GetComponent<Renderer>();
    4.     if(rend == null)
    5.     {
    6.         continue;
    7.     }
    8.  
    9.     rend.material;
    10. }
     
  20. Joris Albertus

    Joris Albertus

    Joined:
    Jun 21, 2016
    Posts:
    10
    Im not sure what you mean, but i wanted it to not be one single file with all the data on it because it would be hard to identify which object it hits, and then get the correct values by attaching different classes to every gameobject, although i might be way off because i just recently started using unity, before that i had only used the c# console.

    Could you link me a tutorial of some sort that can show me how to do something like this, because i still get the error that "Renderer does not contain a definition for..." even though all my objects have sprite renderers / mesh renderers