Search Unity

Need help detecting GameObject

Discussion in '2D' started by TheWebExpert, Jul 21, 2016.

  1. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    I have three objects I've Instantiated on screen in one script. In the other script, I need to detect the GameObjects. I know the physical coordinates onscreen, so I'm trying to use OverlapSphere. Here's what I have:

    Code (CSharp):
    1. Vector3 Temp1 = new Vector3(0.00f, StartPos.y, 0);
    2. GameObject T1 = FindAt(Temp1);
    3. ...
    4.     GameObject FindAt(Vector3 Pos)
    5.       {
    6.         Collider[] colliders;
    7.         GameObject go = null;
    8.         if ((colliders = Physics.OverlapSphere(Pos, 1f)).Length > 1)
    9.           {
    10.             foreach(Collider collider in colliders)
    11.               {
    12.                 go = collider.gameObject; //gameObject we collided with
    13.               }
    14.            }
    15.         return go;
    16.       }
    I'm getting a NullReferenceException here. I know that there's an object at the coordinates specified for Temp1 (because I put it there); I want to move the object on the screen using code, so I need to grab onto the object & then adjust its transform.position.x. Can anyone help? The examples I've found so far for OverlapSphere were in java, not C#.
     
  2. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    Why do you need to detect the objects with physics? If you spawn them in another script, can you keep references to those new GameObjects, instead of just positions, and get them in the second script to alter their positions?
     
  3. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    I don't "need" to detect them with physics; I just thought that was the best way. I'm not sure how you would "keep the references."
     
  4. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    Okay, instead of doing anything fancy, one very straightforward way to make things really easy for you (but this is not the most efficient way) is to make the objects you are spawning into prefabs (if you haven't already), and also give those prefabs a specific script. Then you can use the function "FindObjectsOfType" to have Unity go through the hierarchy and find any objects that have the given script. That script could even be empty, it just needs to be in the component list for the object to be found.

    For example in the class you need the objects you can do this:
    Code (CSharp):
    1. // find all the objects in the scene that have the script "MyScriptName"
    2. // not efficient, but okay to use sparingly (you wouldn't want to use this function every frame)
    3. MyScriptName[] myObjects = FindObjectsOfType<MyScriptName>();
    4.  
    5. // set the first object's position to (0, 0, 0)
    6. myObjects[0].transform.position = Vector3.zero;
    7.  
    8. // Vector3.zero is shorthand for "new Vector3(0,0,0)" but doesn't need to create a "new" one
    Instead of finding the spawned objects, you could alternatively find your script that does the spawning. So say you named that class "Spawner". You could do "Spawner mySpawner = FindObjectOfType<Spawner>()" (notice the singular "object" not "objects". This function will return the first one it finds in the scene.

    Then if your "Spawner" had a public list of objects it spawned called "spawnedObjects", you can then use your "mySpawner" variable and do "mySpawner.spawnedObjects[0].transform.position = Vector3.zero", to follow with my previous example.

    In the same way, you could give your prefabs a Tag, and use GameObject.FindGameObjectsWithTag or GameObject.FindGameObjectWithTag.

    let me know if you follow, i can elaborate if you're not sure about something.
     
    Last edited: Jul 21, 2016
  5. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    This may or may not work; I'm not sure. Here's an "example" of the game:
    <A> <B> <C>

    [1] [2] [3]

    I drag object #1 into spot A. Now #1 is empty. I want to move object #2 into spot #1, and then #3 into spot #2 - and then generate a new #3. All the objects (including the one on spot A) would have the tag, or would have the code. I'm only interested in the ones in #'s 1, 2 & 3.
     
    Last edited: Jul 21, 2016
  6. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    Ok, I got it. I did this:

    Code (CSharp):
    1.             GameObject[] T1 = GameObject.FindGameObjectsWithTag("Animal");
    2.             int j = 0;
    3.             foreach(GameObject animals in T1)
    4.               {
    5.                 if (T1[j].transform.position.x == 0.00f)
    6. ...
    If the object in question is at position 0f (there's only one such possible object), then it does what I want it to do. Thanks!
     
  7. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    No problem. One thing i see in your snippet is that you dont need to keep the counter j as an index, you can use "animals". Personally i would rename that "animal" as it represents only one item in the list, for each loop iteration.
     
  8. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    I have a new problem I need help with. My movement is way too fast for my taste. Here's the code:

    Code (CSharp):
    1.                     for (i = 0f; i >= -1.95f; i-= .05f)
    2.                       {
    3.                         Vector3 Temp2 = new Vector3(i, StartPos.y, 0);
    4.                         StartCoroutine(Delay());
    5.                         T1[j].transform.position = Temp2;
    6.                       }
    and

    Code (CSharp):
    1.     IEnumerator Delay ()
    2.       {
    3.         yield return new WaitForSeconds(160);
    4.       }
    Yet, no matter what I set WaitForSeconds to, it doesn't seem to affect anything. I'd like to slow it down, say half as fast or a quarter as fast. Anybody got any ideas?
     
  9. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    yield return new WaitForSeconds() only affects things that come after it within the coroutine.

    You'll need to do it like this:
    Code (CSharp):
    1. private IEnumerator moveObjects() {
    2.     for(i = 0f; i >= -1.95f; i -= .05f) {
    3.         Vector3 Temp2 = new Vector3(i, StartPos.y, 0);
    4.         yield return new WaitForSeconds(3);
    5.         T1[j].transform.position = Temp2;
    6.     }
    7. }
    So something will need to start that coroutine.
     
  10. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    That worked great! Thank you so much.
     
    LiterallyJeff likes this.
  11. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    Ok... I have a new problem, and I'm very much hoping that someone can help me with it. So, here's the deal: My first script Instantiates three random characters onto the screen, in pre-defined, specified locations which I know. The second script, the one jeffreyschoch was helping me with above, is attached to each character game object, and detects when the mouse is down, dragged, and up.

    On the first iteration (of the second script), everything works fine. On the second drag, however, things go really, really wonky. I'm not sure if I'm still running the same first script (from the first character) or if I'm running the new script from the second character. I put in some debugging code into the script so I could try & see what's going on. Here's the code:

    Code (CSharp):
    1.     void OnMouseUp ()
    2.       {
    3.         int j = 0;
    4.         print("mouseUp");
    5.         for (int i = 0; i < LandingSpot.Length; i++)
    6.           {
    7.             if (MyCollider.IsTouching(LandingSpot[i]) )
    8.               {
    9.                 //LandingSpot[i].enabled = false;
    10.                 transform.position = LandingSpot[i].transform.position;
    11.                 transform.localScale = OriginalScale;
    12.                 //Now that we've dragged it, which one did we drag?
    13.                 ClickLoc = -1;
    14.                 print("ClickLoc a: " + ClickLoc);
    15.                 if (StartPos.x >= -2.05f && StartPos.x <= -1.95f) ClickLoc = 1;
    16.                 if (StartPos.x >= -0.10f && StartPos.x <=  0.10f) ClickLoc = 2;
    17.                 if (StartPos.x >=  1.76f && StartPos.x <=  1.96f) ClickLoc = 3;
    18.                 print("ClickLoc b: " + ClickLoc);
    19.                 FillSeat();
    20.                 j = 1;
    21.               }
    22.           }
    23. ...
    24.     void FillSeat()
    25.       {
    26.         print("ClickLoc: " + ClickLoc);
    27.         print("StartPos: " + StartPos.x);
    28.         print("Animal: " + an);
    29.         if (ClickLoc == 1)
    30.           {
    31.                      ...
    The first time I release the mouse, I get the "mouseUp" message, the "ClickLoc a" and "ClickLoc b" messages, and the three lines with "ClickLoc", "StartPos" and "Animal" from the FillSeat function.

    On the second release, however.... if I picked up the animal from the first position, I get only the StartPos and Animal lines from FillSeat. Other selections can be even stranger.

    Part of the problem MAY come from FillSeat itself:

    Code (CSharp):
    1.             GameObject[] T1 = GameObject.FindGameObjectsWithTag("Animal");
    Since every possible character exists on the screen at the beginning of the game, and since I'm Instantiating even more copies of these guys, the computer may be getting confused as to which object I'm talking about.

    I can't make the characters prefabs, because they'd lose their code. I would prefer a better way of searching for the objects; I know EXACTLY the screen coordinates of the three characters, which are NEVER going to change....
    and once they've been dropped, I want to ignore the actual gameobject, and just record WHAT was placed where...

    I have no idea why the print statements aren't printing on the second drag; the program IS running the FillSeat function (otherwise you wouldn't see the StartPos line); but it looks as is the variables aren't getting set or something. Is there a way to ensure that once I'm done with the FillSeat function that the script exits? I am really, REALLY lost on why this is acting this way...
     
    Last edited: Jul 28, 2016
  12. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    Now, this is interesting... for those who MAY be following this, if you've got similar problems, check your console for warning messages. Apparently, variables which are "set but never used" or have their values as null can screw up other things. When I removed (or used) these variables, the entire piece of code began to work properly. Go figure. In VisualBasic, such variables would just have been ignored. Not so here!