1
\$\begingroup\$

I'm trying to switch the tag on my Player to something else when a collision between two unrelated objects happens, and then switch the tag of another object to Player, so my camera script will follow it.

How do I detect a collision between two objects that do not have my script attached to them?

void OnCollisionEnter(Collision col) only detects collision on the object that the script is assigned to, so I can't use that. Either I need to know how to detect a unrelated collision in a script, or I need to know how to change the tag of an object that does not contain the script.

This script is on my player, whom does not collide with anything:

void OnCollisionEnter (Collision col) 
{
    if (col.gameObject.name == "triggerCube") 
    {
        Debug.Log ("HIT");
    }
    else 
    {
        Debug.Log ("HIT2");
    }
}

The `Debug.Log("HIT") does not show when the objects collide. This script is on the object "triggerCube":

using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using UnityEngine.SceneManagement;

public class EndPoint : MonoBehaviour 
{
    public Text textWin;

    private Vector3 offset;

    void OnCollisionEnter (Collision col) 
    {
        if (col.gameObject.name == "triggerCube") 
        {
            Debug.Log ("HIT SOMETHING");
            setWinText ();
        }
    }

    void setWinText () 
    {
        textWin.text = "LMAO";
    }
}
\$\endgroup\$
  • 1
    \$\begingroup\$ I think in that very method, col.gameObject will give you the other collided object even if that object has no script on it. \$\endgroup\$ – Hamza Hasan Aug 23 '16 at 9:05
  • \$\begingroup\$ Edited with more info. There is nothing happening. \$\endgroup\$ – user3078100 Aug 23 '16 at 9:10
  • 1
    \$\begingroup\$ Is HIT2 logging? And one more thing, you are checking in triggerCube's script if (col.gameObject.name == "triggerCube"), this will give you the name of other body, not its own name \$\endgroup\$ – Hamza Hasan Aug 23 '16 at 9:13
  • \$\begingroup\$ If you are just changing the tag to affect camera behaviour then it sounds like you are going about it the wrong way. Just tell the camera which game object to follow rather than letting it decide for itself. \$\endgroup\$ – Droppy Aug 23 '16 at 9:22
1
\$\begingroup\$

As things are right now, only your player can detect collisions. For this to happen your player must have a collider attached, and be sure the IsTrigger checkbox is unchecked. If you want to make it react to IsTrigger than you should change your OnCollisionEnter() to OnTriggerEnter().

Collisions can only be detected if at least one of the colliding objects has a call to OnCollisionEnter() or OnTriggerEnter(), depending on if you want the collider to react to collisions or triggers, and obviously both colliding objects must have a collider attached.

For further detail on understanding how to properly handle collision detection among your objects, please see this question.

\$\endgroup\$
0
\$\begingroup\$

You can't detect a collision between two objects if you do not add a script to one of them. You have to add another script to the colliding objects, and then let your EndPoint script know about that collision through a function call.

\$\endgroup\$
0
\$\begingroup\$

As stated in the other answers, collision is only initially being handled between the two game objects that are colliding. You need to have a script on one of the two objects involved in the collision, and have it relay information back to the player, somehow.

Potential problems with same-named objects colliding

In your example, you have a script that is on an object named "triggerCube". You also check to see if the othercol.name == "triggerCube", suggesting that both objects are named "triggerCube".

It is important that you are aware that both cubes will trigger a collision. This means that if both cubes have the EndPoint script, they will each run their own version of OnCollisionEnter, where they will each see the opposite triggerCube and determine that (col.name == "triggerCube") == true.

'Why is this important', you might ask? Well, it means that your logic will be run twice. Under some logic, this won't appear to mess things up; but you might have some fatal errors, as a result. You could also have situations where the "Player" tag jumps an extra game object, depending how you have things set up, as both triggerCube objects detect a collision and individually instruct the player to 'hop objects'.

I will assume only one of the triggerCube objects contains the EndPoint script, which allows quick assurance that the logic will only process once. You may also want to look at an alternate question, "Check which object triggered another".

Alerting the Player object to collision

Ultimately, you need to be able to identify the Player script, to push action to the player when your two triggerCube objects collide. You can do this several ways, each of which has their advantages and disadvantages. We will assume that the script attached to your player is called Player.

Here are three easy ways to set up your reference:

  • Use Unity Editor: If your only making the jump once, this is the quickest and most reliable way to go.
  • Use a static script: If your only keeping one instance of the player, this might be the quickest way to go. Beware: If you do not properly ensure that you only have one Player, your going to have a bad time.
  • Find the reference on the fly with tags: If you only have one Player tag at a time, this might be the more reliable way to go. Than again, if you have a lot of objects in your scene, you might find that this method is slow to work itself out.

Passing the reference via Unity Editor

Having a public reference allows you to manually set the reference using drag and drop, in the Unity Editor.

This is a good way to test out certain functionality, while ensuring correct reference. This is also a good way to go when the reference is some what static - that is, if the script should not move from that game object, your reference should always work properly. This is also, arguably, the easiest way.

If you have to perform this sort of action again, i.e. it is not a 'one-time only' event, this is probably not the best solution. If you still go this way, you will still have to ensure that the reference is properly set up again, when you move to the next 'player object'. Since your now in-game, you will have to reset the reference without the Unity Editor, so your better off just using one of the more adaptable solutions from the start.

public class EndPoint : MonoBehaviour
{
    public Player player;

    void OnCollisionEnter(Collision other)
    {
        if(other.gameObject.name == "triggerCube")
        {
            player.NextPlayer();
        }
    }
}

public class Player : MonoBehaviour
{
    public void NextPlayer()
    {
        // Move tag to next object;
    }
}

Keeping a static reference to Player

Having a static reference allows you to guarantee access to your script, but you should remember that to be static, a script can not have instanced variations in play. While you are not hard-bound by this constraint in using static, if you do not follow the logic, bad things will happen.

You could consider attaching the script to your new 'player object' with each NextPlayer(), if you need to move players more than once. If your logic insists that multiple Player scripts be at play at the same time, this will not work for you. If you have multiple Player scripts, with only one at play at a single time, you still need to make absolute sure that Player.me references the active version of your Player script. Even with precision, that could be tricky.

public class Player : MoboBehaviour()
{
    public static Player me; // cheeky self-reference

    void Start()
    {
        me = this;           // set up the self-reference
    }

    public void NextPlayer()
    {
        // Move tag to next object;
        // Attach this script to the next object;
        // That way, this static script can be kept,
        // but it still references the next object with this.gameObject
    }
}

public class EndPoint : MonoBehaviour
{
    void OnCollisionEnter(Collision other)
    {
        if(other.gameObject.name == "triggerCube")
        {
            Player.me.NextPlayer();
        }
    }
}

Finding Player on the fly with tags

Another option you have is to locate the player using the same tag you wish to change.

This solution is more likely to work on the fly, in a variety of circumstances. That said, we are relying on checking all objects for the Player tag; while the scenario you describe seems to imply only one Player tag will be in use (so we are not worried about finding the wrong object), you have to keep aware of how many game objects are currently in your scene. As your logic has to sort through more objects to find the player, it will take longer to complete its operation.

public class EndPoint : MonoBehaviour
{
    Player player;

    void OnCollisionEnter(Collision other)
    {
        if(other.gameObject.name == "triggerCube")
        {
            FindPlayer();
            Player.NextPlayer();
        }
    }

    void FindPlayer()
    {
        GameObject.FindWithTag("Player");
    }
}

public class Player : MonoBehaviour
{
    public void NextPlayer()
    {
        // Move tag to next object;
    }
}

Moving the "Player" tag

Now that's all sorted out, changing the tags should be quite easy. Simply calling gameObject.tag = in a script should give you the ability to change its tag. That said, you must ensure you set a tag that has previously been set in the Tags & Layers Manager.

If it was not already obvious, you will have to retrieve a reference to your 'new player object', just as you had for your player. You should be able to do this in effectively the same way as you would to identify the initial 'player object'.

You may consider using a different method to that which you used for Player. Keep in mind that since you may not be calling any real script logic on the other side, yet, you may not have an actual script on the other side. You can store a reference to the direct game object with GameObject nextPlayerObject, and work your way from there.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.