Search Unity

Detecting OnTriggerEnter collisions from an object not involved in the collision?

Discussion in 'Scripting' started by rhianu, Feb 8, 2011.

  1. rhianu

    rhianu

    Joined:
    Feb 25, 2010
    Posts:
    93
    I already know how to use OnTriggerEnter to detect if an object is colliding with the object to which the script is attached, but I was wondering if it was somehow possible to detect if two OTHER objects, separate from the current object, are colliding with each other.

    In other words, I need to detect if object X is colliding with object Y, but the script which does the detection must be attached to object Z.

    How would I do this? I'm guessing something with tags, but I'm not sure how to put it together.
     
  2. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
    I don't think there's any built-in support for that. But, it should be easy enough to dispatch a message to object Z any time a collision involving object X or Y occurs.
     
  3. rhianu

    rhianu

    Joined:
    Feb 25, 2010
    Posts:
    93
    Okay, I guess that could work. How would I dispatch and receive such a message using C#?

    I'm working off a pre-made script written by someone else, and they did it all in C#, but I'm more familiar with JavaScript, and I'm having trouble figuring out the syntax.
     
    Last edited: Feb 9, 2011
  4. muplor

    muplor

    Joined:
    Nov 2, 2009
    Posts:
    75
    would adding a rigid body to the object do the trick?
     
  5. rhianu

    rhianu

    Joined:
    Feb 25, 2010
    Posts:
    93
    Doesn't seem to make a difference. =/
     
  6. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
    For linking up the objects, you can use any of the usual methods, such as those described here.

    For sending a message from one object to another, you could use a simple function call, or you could use one of the GameObject 'send message' functions.

    Beyond that, if you're having problems, perhaps you could post some code and show us where you're getting hung up.
     
  7. rhianu

    rhianu

    Joined:
    Feb 25, 2010
    Posts:
    93
    Well, I'm trying to take the random dungeon generator from -> this topic <- and implement it into my game. Thing is, though, the original dungeon generator comes with a lot of other extra features I don't need, such as a custom character controller, title screen, story-page, random battles, mock-inventory, character stats, etc. And I'm trying extricate the dungeon generator from all those extra features, but I'm having a heck of a time doing it while still keeping the dungeon generator itself intact and functional.

    Anyway, in the dungeon generator, there are two colored cubes which represent stairs. The red cube goes down to the next level, while the green cube goes back up to the previous level. With the way the original code is written, there is a dungeon generator object that detects when the player and a colored cube are at the same position, and then preforms the appropriate action (either going down to the next level or up to the previous one). However, in my project I need to use an OnTriggerEnter event to preform the action, since I'm using my own character controller, and not the one that the author provided (the issue is explained in more detail in the topic I linked to at the beginning of this post).

    Basically, I just need the DungeonGenerator object to detect when the player collides or comes into contact with the stairs, and then generate the next level.

    The DungeonGenerator already has fully functional methods for generating a random level, I just need those functions to be called in a different way than what the author originally programed.

    In my own project, I had to create a small little custom script to attach to the red cube to detect a player collision:

    clearedLevel.cs:
    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class clearedLevel : MonoBehaviour
    5. {
    6.    public static bool touchedStairsDown;
    7.  
    8.    void OnTriggerEnter(Collider other)
    9.    {
    10.      if (other.gameObject.tag == "Player")
    11.        {
    12.          Debug.Log("Down Stairs!");
    13.          touchedStairsDown=true;
    14.        }
    15.    }
    16. }
    Anyway, that much of the code seems to work fine, but I can't figure out how to make the variable touchedStairsDown trigger the two functions that generate the next level. The first function, called GoToNextLevel, is in the DungeonGenerator object:

    DungeonGenerator.cs:
    Code (csharp):
    1.     public void GoToNextLevel()
    2.     {
    3.         DeleteDungeonFloor();
    4.         CreateDungeonFloor();
    5.         DungeonFloorNumber++;
    6.     }
    And the other function, called SetNewMetaState, is inside another script attached to a game object called the MetaStateManager:

    MetaStateManager.cs:
    Code (csharp):
    1.     public void SetNewMetaState(MetaState newMetaState)
    2.     {
    3.         pendingNewMetaState = newMetaState;
    4.     }
    Basically, I just need those two functions from those two scripts to execute when the variable touchedStairsDown becomes true. Remember, this all needs to be done in C#.
     
    Last edited: Feb 10, 2011
  8. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
    I think my previous advice still applies: basically, you just need to link up the objects in whatever way is necessary so that whoever needs to receive the 'these two objects collided' message can receive it.

    Just as an example, you could give the trigger object a reference to the DungeonGenerator object, and then in OnTriggerEnter(), if a collision with the player is registered, send a message to the DungeonGenerator object (e.g. by function call or message broadcast) letting it know that the trigger has been entered. Then, the DungeonGenerator object can do whatever it needs to do in response to that.
     
  9. rhianu

    rhianu

    Joined:
    Feb 25, 2010
    Posts:
    93
    Well I'm trying to get the other scripts to detect when a collision occurs, but I can't seem to get them to read the variable from the collision script.

    Inside the void Update() function of the MetaStateManager.cs script, I put the following bit of code:
    Code (csharp):
    1. if (clearedLevel.touchedStairsDown == true);
    2. {
    3.   Debug.Log("^_^");
    4. }
    However, instead of only displaying ^_^ in the debug log after the player has collided with the stairsDown object, the MetaStateManager starts displaying it right away as soon as the level loads.
     
  10. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
    That would suggest that 'touchedStairsDown' is either initially 'true', or is set to 'true' more or less immediately once the level is loaded, so that's probably where you'll want to investigate next.
     
  11. rhianu

    rhianu

    Joined:
    Feb 25, 2010
    Posts:
    93
    Well that's what I thought at first, too, but I looked over my clearedLevel.cs script, and that doesn't seem to be the case.

    clearedLevel.cs
    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class clearedLevel : MonoBehaviour
    5. {
    6.     public static bool touchedStairsDown = false;
    7.     int i = 0;
    8.    
    9.     void OnTriggerEnter(Collider other)
    10.     {
    11.         if (other.gameObject.tag == "Player")
    12.         {
    13.             i++;
    14.             Debug.Log("Down Stairs! " + i);
    15.             touchedStairsDown = true;
    16.         }
    17.     }
    18. }
     
    Last edited: Feb 10, 2011
  12. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
    Well, *something* must be causing it not to work :)

    What I'd probably do at this point is start stepping through the code in the debugger and try to find the problem that way.
     
  13. rhianu

    rhianu

    Joined:
    Feb 25, 2010
    Posts:
    93
    Debugger? You mean the Error Console, right?

    And am I at least telling the MetaStateManager.cs script to access the clearedLevel.cs script correctly?
     
    Last edited: Feb 11, 2011
  14. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
    I'm referring to the MonDevelop debugger. (Using MonoDevelop, you can debug as you would in any similar IDE, i.e. by stepping through the code a statement as a time.)

    I'm not sure; can you post the relevant code? (Maybe you already did, but I'm not sure where to look for it.)
     
  15. rhianu

    rhianu

    Joined:
    Feb 25, 2010
    Posts:
    93
    This code:
    Code (csharp):
    1. if (clearedLevel.touchedStairsDown == true);
    2. {
    3.   Debug.Log("^_^");
    4. }
    It's contained inside the void Update() function in the MetaStateManager.cs script. There is nothing else beyond that telling the MetaStateManager to access the clearedLevel script.
     
    Last edited: Feb 11, 2011
  16. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
    Yes, that looks correct.
     
  17. rhianu

    rhianu

    Joined:
    Feb 25, 2010
    Posts:
    93
    Okay, well I made a new C# script containing nothing except that line, and it still does the exact same thing.

    test.cs
    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class test : MonoBehaviour
    5. {
    6.  
    7.     // Use this for initialization
    8.     void Start ()
    9.     {
    10.    
    11.     }
    12.    
    13.     // Update is called once per frame
    14.     void Update ()
    15.         {
    16.           if (clearedLevel.touchedStairsDown == true);
    17.           {
    18.             Debug.Log("^_^");
    19.           }
    20.     }
    21. }
    clearedLevel.cs
    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class clearedLevel : MonoBehaviour
    5. {
    6.     public static bool touchedStairsDown = false;
    7.     int i = 0;
    8.    
    9.     void OnTriggerEnter(Collider other)
    10.     {
    11.         if (other.gameObject.tag == "Player")
    12.         {
    13.             i++;
    14.             Debug.Log("Down Stairs! " + i);
    15.             touchedStairsDown = true;
    16.         }
    17.     }
    18. }
     
    Last edited: Feb 11, 2011
  18. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
    Is this message:

    Code (csharp):
    1. Debug.Log("Down Stairs! " + i);
    Ever printed to the console?
     
  19. rhianu

    rhianu

    Joined:
    Feb 25, 2010
    Posts:
    93
    Yeah, that part works just fine. It doesn't print immediately when the level starts (which is good, because it's not supposed to), and then prints only once each time the player collides with the red cube.

    The debug output from the test script (^_^) however, continually prints every single frame, regardless of whether or not the player has collided with the red cube.
     
  20. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
    Well, it sounds like you probably need to do some debugging. Add more console output if needed, and/or try debugging it in MonoDevelop.

    Maybe someone else will have a better suggestion, but so far at least, I haven't been able to spot the problem in the code that you've posted. (Also, if you wanted to upload a Unity package demonstrating the problem, I or someone else might be able to take a look.)
     
  21. rhianu

    rhianu

    Joined:
    Feb 25, 2010
    Posts:
    93
    Well I just created a totally new project, and it still does the same thing. So clearly the problem isn't coming from something else in the project, but from some flaw with the script.

    Perhaps I'm simply not declaring something properly. Maybe the test.cs script needs something more to identify the clearedLevel.cs script? But what?
     
  22. Jesse Anders

    Jesse Anders

    Joined:
    Apr 5, 2008
    Posts:
    2,857
    What you posted earlier looked fine (that's really all there is to accessing a public static variable.)

    Unless someone else has a better idea, I'd recommend posting a Unity package containing a minimal working example that demonstrates the error. (That is, create a new duplicate project and then strip as much stuff as you can out, so that what's left is only the relevant parts, more or less.) Then, post the Unity package here, and I or someone else can probably take a look at it.
     
  23. rhianu

    rhianu

    Joined:
    Feb 25, 2010
    Posts:
    93
    I'll upload the project, just a sec.

    EDIT: the upload keeps failing for some odd reason. =/

    I don't know why, but the Unity forums don't seem to like the file, even though I compressed it as a rar file, and it's only 3 MB.
     
    Last edited: Feb 11, 2011