How can I determine which Trigger is hit?
I have a GameObject. It has 3 BoxCollider2Ds:
Body Collider - Not a trigger - Determines if body is hit
Weapon Collider - Trigger - Determines if weapon is hit
Vision Collider - Trigger - Determines what the GameObject sees
I can tell the Body Collider apart from the other colliders, because it has a different method (OnCollisionEnter2D). However, I cannot tell the Weapon Collider and Vision Collider apart. They both access the same method (OnTriggerEnter2D), and pass in the collider they are hitting. I cannot determine which one is hit.
I could put each trigger on a separate child GameObject, and send a message to the parent, but this feels messy to me. What is the best way I can determine which trigger I am hitting?
From the Unity Docs for reference:
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour {
public bool characterInQuicksand;
void OnTriggerEnter2D(Collider2D other) {
characterInQuicksand = true;
}
}
@Ejpj123 Yes, I know. I thought that was clear in the first line of my question.
Answer by macorig · Jun 21, 2016 at 08:42 PM
There is no way to determine which one was hit, as far as I know. That's why using several colliders on a single GameObject like this is not advisable. The better solution would be to use several, separate child objects, just like you have described. Since you were concerned with elegance, you may consider an approach similar to this:
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(Collider2D))]
public class HitBox : MonoBehaviour {
private PlayerBehaviour player;
void Start () {
// Find the component this hitbox "belongs" to
player = GetComponentInParent<PlayerBehaviour> ();
}
void OnTriggerEnter2D(Collider2D other) {
// Do something to the "owning" component
player.AddDamage (10f);
}
}
You can put all kinds of extra functionality in there and still make calls to the parent object/component without the need to use "SendMessage." This also has the advantage that you can assign different layers to the separate collider-game-objects to filter physics interaction, something that would not be possible in your first approach.
This is what I was trying to avoid, but +1 for actually answering the question. Thanks :-)
What do you mean by filtering physics interactions with different layers? For some reason, I can't picture what you mean off the top of my head and I'm having a similar issue as the OP with a game I'm working on. Can you give an example? Thanks.
He means, that you can pre-cull a lot during physics checks, if you control which layers can trigger each other, so if you make a layer called "PlayerProximityTrigger" and put that on your trigger, then you can disable collision-checks with every layer it isn't supposed to be interacting with. If you're really keen, you can make a separate "PlayerProximityTriggerTarget" layer for all the colliders/triggers you want it to interact with (so everything it has to interact with needs to have a collider with this layer), and then make this layer THE ONLY layer to collide with "PlayerProximityTrigger". It's all about helping the physics engine to cull as much in its broad-phase as possible, and this way the layers are only ever checked against each other, and not even against themselves (neither "PlayerProximityTrigger" nor "PlayerProximityTriggerTarget" should be set to collide with themselves). That makes it as simple as possible to do the entire check for these layers for the engine, compared to sucking up all collisions, having OnTriggerEnter() for all objects and doing .GetComponent() or .CompareTag() on all of them, etc.. The more you can do with layers, without overusing them, the happier the physics engine will be. The biggest problem with this, is that OnTriggerEnter() only provides the "Incoming Collider", not the collider that was hit on the receiver of the call, so the thing itself cannot keep tabs on which of its triggers are currently being overlapped by a certain other collider and so keep an aggregate "IsBeingOverlapped"-bool inside of them; they cannot know which OnTriggerEXIT() is the last one so they can toggle the bool to false. It HAS to be the thing that has the overlapping collider, in our example case "PlayerProximityTrigger", which collects the information about which colliders it is overlapping correspond to "the same object", whatever that means in your context. For some, it'll just be a RigidBody that is the uniting factor, and you have the col.attachedRigidBody to use for that, but if you have a custom object-script (I have an AreaObject-script, which controls the visibility of an object), then you have to do GetComponent(), perhaps even the InParents-version, to get the script to compare with the already registered overlapping objects. And that sucks.
Answer by habsi70 · Jun 21, 2016 at 08:00 PM
Every collider - in your case 'other' - knows its gameObject. other.gameObject should give you the child it is attached to. Now you can compare tags, name etc.
The question is, how can I tell which trigger I am hitting?
Ah, I misunderstood. I thought you had the colliders on child-objects. I do not think that you can tell them apart otherwise.
Answer by Prawnir · Jun 21, 2016 at 09:29 PM
In the editor apply one tag to the object with the weapon collider and one tag to the object with the vision collider. In your OnTriggerEnter2D method you can then determine which object has collided by checking the value of the tag, this is performed by using the following code: if(other.tag.Equals("Weapon"))
. or vice versa with the "Vision" tag. I hope that answers your question.
The question is, how can I tell which trigger I am hitting? Not what is getting hit by the trigger.
$$anonymous$$y bad, as habsi70 pointed out you need to put other.GameObject.tag.Equals("Weapon");
Answer by Beef331 · Jun 22, 2016 at 05:14 AM
You can put a tag on the object that you want to check
if(gameobject.tag == "Weapon") characterInQuicksand = true;
Answer by MrN_Says_Hi · Jun 12, 2019 at 03:39 PM
As @macorig suggested, there is no way of knowing which collider was hit, however, I found that it's more convenient to use a couple of Physics2D.OverlapBox inside if statements and specifying the behavior for each, over dividing my GameObject to child objects and giving each its own script with an OnTriggerEnter2D, that latter seemed much harder in my case.
Doing overlap constantly eats infinitely more CPU-cycles than having separate triggers just sitting there doing nothing until they're triggered. If this is for a few entities, fine. If it's supposed to be triggers that are placed all over the map, you'll likely want something dormant, like a trigger, instead of checking a volume with overlap each FixedUpdate, or at least deactivate it when the player isn't near.
Your answer
Follow this Question
Related Questions
Camera being affected by sphere collider triggers 0 Answers
Trigger a box collider based on force of an object 1 Answer
How to trigger functions like OnTriggerEnter2d and OnTriggerExit2d with raycasthit2d ? 1 Answer
triggered sound playing on start 0 Answers
How Do I increase speed based off of a trigger collider? 0 Answers