I have an enemy and I want to have a few triggers on it:
Aggro radius (radius at which it comes to attack the player)
Retreat radius (radius at which it will forget about the player and return to base)
Attack radius (radius at which it will stop still and fire at the player)
From what I’ve read, objects can only have 1 trigger on, so I must create multiple game objects as children, then attach triggers to them, then make a short script which calls the parent script when it is triggered with both the type of trigger it’s calling from, and the type of object that has triggered it.
Something like
// child
var parentScriptName : String; // parent script name
function OnTriggerEnter(collision : Collider)
{
var parent = transform.parent.gameObject.GetComponent(parentScriptName);
parent.OnTriggerEnterExternal(name,collision);
}
// parent
function OnTriggerEnterExternal (triggerName : string, collision : Collider )
{
... etc
Is this really the best way of doing this? I would have thought something as common as communicating with multiple triggers on one object would have something like this built in?
If the colliders don’t themselves overlap (such as concentric spheres) you could check based on which trigger event occurs. For example, if you got an OnTriggerEnter, increase a counter. If you get OnTriggerEnter and the counter == 1, you know you have hit the first inner sphere.
Ran into this same problem, couldn’t find much, but my solution was to just create a new gameObject, have it follow the object I wanted another trigger on, add an in-file class that contains the new trigger code. Made a skeleton that should be simple enough to modify.
using UnityEngine;
using System.Collections;
public class ProjectileDetectionStrippedForForum : MonoBehaviour
{
public float radius; //radius for collider
private GameObject hit_circle; //reference to the object containing CircleCollider2d thing
private CircleCollider2D c2d; //reference to the added circle collider
private CustomSecondTrigger pdtf; //reference to the in file class that contains trigger code for new trigger
void Start ()
{
//create and add components
hit_circle = new GameObject ();
c2d = hit_circle.AddComponent<CircleCollider2D> ();
pdtf = hit_circle.AddComponent<CustomSecondTrigger> ();
//if we need to reference this created gameobject from the created trigger class below, we need to have a reference
pdtf.Sendee = gameObject;
//setup our collider
c2d.isTrigger = true;
c2d.radius = radius;
c2d.center = transform.position;
}
void FixedUpdate() {
//follow the object this script is attached to
c2d.center = transform.position;
}
void Evade() {
//can call a function here from the trigger, or can run code in the next defined class that we attach to our GO
}
}
public class CustomSecondTrigger : MonoBehaviour
{
private GameObject sendee;
public GameObject Sendee {
get { return sendee; }
set { sendee = value; }
}
void OnTriggerEnter2D(Collider2D other) {
//can send message to whomever or run our code here
Sendee.SendMessage( "Evade" );
}
}
I’m trying to figure out a way to overcome this, in my opinion, huge omission from Unity. The only thing I can think about is your solution, but here is my precise solution, which I’m still not totally satisfied with.
using UnityEngine;
using System.Collections;
public class ColliderContainer : MonoBehaviour {
public MonoBehaviour mediator;
private ICollidable _mediator;
void Awake () {
_mediator = (ICollidable)mediator;
}
void OnTriggerEnter(Collider other) {
_mediator.enterCollision(other, LayerMask.LayerToName(gameObject.layer));
}
}
This is the children script. mediator is the monobehaviour which has an enterCollision method that will handle the collisions, just put the script that will handle on top of the components list in your gameObject, then drag the gameObject in the monobehaviour slot (could make something more automatic, but it would be too heavy for what it is)
So I have been working on the same issue, and the best solution that I have found for this issue is just to create multiple cube objects to use as triggers and attach them to the character’s prefab. Then use these triggers to call methods from within that character accordingly.
This is what I am using and it works so far:
In my own component in the Awake
//Setup the detector
DetectorGameObject = new GameObject(“MotionCollider”);
GameObjectUtility.SetParentAndAlign(DetectorGameObject, gameObject);
DetectorCollider2D = DetectorGameObject.AddComponent();
DetectorCollider2D.isTrigger = true;
//Use a collider helper to work around the unity limit of one collider per GameObject
Collider2DHelper helper = DetectorGameObject.AddComponent();
helper.TriggerEntered2D += (sender, d) => TriggerEntered2D((GameObject)sender, d);
helper.TriggerExited2D += (sender, d) => TriggerExited2D((GameObject)sender, d);
/// <summary>
/// Add this helper to a GameObject with a single collider2D and register for its trigger events.
/// This works around the single collider trigger per GameObject limit in unity.
/// </summary>
public class Collider2DHelper : MonoBehaviour
{
/// <summary>
/// Sent when another object enters a trigger collider attached to this object (2D physics only).
///Further information about the other collider is reported in the Collider2D parameter passed during the call.
//Note: Trigger events will be sent to disabled MonoBehaviours, to allow enabling Behaviours in response to collisions.
/// </summary>
public event EventHandler<Collider2D> TriggerEntered2D;
/// <summary>
/// Sent when another object leaves a trigger collider attached to this object (2D physics only).
///Further information about the other collider is reported in the Collider2D parameter passed during the call.
///Notes: Trigger events will be sent to disabled MonoBehaviours, to allow enabling Behaviours in response to collisions.
/// </summary>
public event EventHandler<Collider2D> TriggerExited2D;
/// <summary>
/// Sent each frame where another object is within a trigger collider attached to this object (2D physics only).
///Further information about the other collider is reported in the Collider2D parameter passed during the call.
///Notes: Trigger events will be sent to disabled MonoBehaviours, to allow enabling Behaviours in response to collisions.
/// </summary>
public event EventHandler<Collider2D> TriggerStayed2D;
/// <summary>
///Sent when an incoming collider makes contact with this object's collider (2D physics only).
///Further information about the collision is reported in the Collision 2D parameter passed during the call.
///Notes: Collision events will be sent to disabled MonoBehaviours, to allow enabling Behaviours in response to collisions.
/// </summary>
public event EventHandler<Collision2D> CollisionEntered2D;
/// <summary>
/// Sent when a collider on another object stops touching this object's collider (2D physics only).
///Further information about the objects involved is reported in the Collision2D parameter passed during the call.
///Notes: Collision events will be sent to disabled MonoBehaviours, to allow enabling Behaviours in response to collisions.
/// </summary>
public event EventHandler<Collision2D> CollisionExited2D;
/// <summary>
///Sent each frame where a collider on another object is touching this object's collider (2D physics only).
///Further information about the objects involved is reported in the Collision2D parameter passed during the call.
///Notes: Collision events will be sent to disabled MonoBehaviours, to allow enabling Behaviours in response to collisions.
/// </summary>
public event EventHandler<Collision2D> CollisionStayed2D;
//Unity callback that are converted to events
#region Unity Callbacks
private void OnTriggerEnter2D(Collider2D triggerCollider2D)
{
TriggerEntered2D?.Invoke(gameObject, triggerCollider2D);
}
private void OnTriggerExit2D(Collider2D triggerCollider2D)
{
TriggerExited2D?.Invoke(gameObject, triggerCollider2D);
}
private void OnTriggerStay2D(Collider2D triggerCollider2D)
{
TriggerStayed2D?.Invoke(gameObject, triggerCollider2D);
}
private void OnCollisionEnter2D(Collision2D collision2D)
{
CollisionEntered2D?.Invoke(gameObject, collision2D);
}
private void OnCollisionExit2D(Collision2D collision2D)
{
CollisionExited2D?.Invoke(gameObject, collision2D);
}
private void OnCollisionStay2D(Collision2D collision2D)
{
CollisionStayed2D?.Invoke(gameObject, collision2D);
}
#endregion
}
Sorry to resurrect this this thread but when I googled this issue, this was still one of the top answers. I just wanted to post my solution in case anyone else runs into this problem.
Make a child for each trigger on your gameobject, and place one trigger per child. Then add this script to each trigger collider object you made.
2D
public class TriggerColliderEvent : MonoBehaviour
{
public UnityEvent unityEvent;
The script lets you call a separate event from from the context of each trigger. Once it’s added, you can assign a function to be invoke by each respective trigger in the inspector. Make sure to handle stuff like comparing tags inside the functions you write.
You can extend this script to also handle OnTriggerStay and OnTriggerExit situations.