Skip to content

Instantly share code, notes, and snippets.

@Stektpotet
Last active September 15, 2017 22:40
Show Gist options
  • Save Stektpotet/8c970cc7cfb6075a211c2322ed760db8 to your computer and use it in GitHub Desktop.
Save Stektpotet/8c970cc7cfb6075a211c2322ed760db8 to your computer and use it in GitHub Desktop.
Unity: Simple Trigger system. (Extremely useful for making different parts of your game/app connect quickly by unity's own implementation of delegate types)
using UnityEngine;
using UnityEngine.Events;
public abstract class Trigger : MonoBehaviour {
public LayerMask activatorLayers;
[SerializeField]
private bool explicitActivator;
public UnityEvent onEnter;
public UnityEvent onStay;
public UnityEvent onExit;
protected bool FilterActivator(GameObject other)
{
return explicitActivator ? IsActivator(other) : (activatorLayers & (1 << other.layer)) > 0;
}
protected abstract bool IsActivator(GameObject other);
}
using System;
using UnityEngine;
[RequireComponent(typeof(Collider2D))]
public class Trigger2D : Trigger
{
public Collider2D[] activators;
public void OnTriggerEnter2D(Collider2D other)
{
if (FilterActivator(other.gameObject))
{
onEnter.Invoke();
}
}
public void OnTriggerStay2D(Collider2D other)
{
if (FilterActivator(other.gameObject))
{
onStay.Invoke();
}
}
public void OnTriggerExit2D(Collider2D other)
{
if (FilterActivator(other.gameObject))
{
onExit.Invoke();
}
}
protected override bool IsActivator(GameObject other)
{
foreach (var activator in activators)
{ if (activator.gameObject == other) return true; }
return false;
}
}
using UnityEngine;
using System;
[RequireComponent(typeof(Collider))]
public class Trigger3D : Trigger
{
public Collider[] activators;
public void OnTriggerEnter(Collider other)
{
if (FilterActivator(other.gameObject))
{
onEnter.Invoke();
}
}
public void OnTriggerStay(Collider other)
{
if (FilterActivator(other.gameObject))
{
onStay.Invoke();
}
}
public void OnTriggerExit(Collider other)
{
if (FilterActivator(other.gameObject)0)
{
onExit.Invoke();
}
}
protected override bool IsActivator(GameObject other)
{
foreach (var activator in activators)
{ if (activator.gameObject == other) return true; }
return false;
}
}
using UnityEditor;
using UnityEngine;
//...I know, this attribute-syntax is really f***ing weird
[CustomEditor(typeof(Trigger), editorForChildClasses:true, isFallback = true)]
public class TriggerEditor : Editor
{
SerializedProperty
isExplicitProp,
activatorsProp,
activatorLayersProp,
onEnterProp,
onStayProp,
onExitProp,
foundTriggerProp;
static GUIContent explicitLabel = new GUIContent("Explicit", "Explicitly set target objects for this trigger, otherwise use layers");
private void OnEnable()
{
isExplicitProp = serializedObject.FindProperty("explicitActivators");
activatorsProp = serializedObject.FindProperty("activators");
activatorLayersProp = serializedObject.FindProperty("activatorLayers");
onEnterProp = serializedObject.FindProperty("onEnter");
onStayProp = serializedObject.FindProperty("onStay");
onExitProp = serializedObject.FindProperty("onExit");
foundTriggerProp = serializedObject.FindProperty("hasRelativeTriggerComponent");
}
public override void OnInspectorGUI()
{
if(target.GetType() == typeof(Trigger2D))
{
if( !((Trigger2D)target).GetComponents<Collider2D>().Any(c => c.enabled && c.isTrigger) )
{
EditorGUILayout.HelpBox("No Collider2D found marked as trigger", MessageType.Warning);
}
}
else
{
if (!((Trigger3D)target).GetComponents<Collider>().Any(c => c.enabled && c.isTrigger))
{
EditorGUILayout.HelpBox("No Collider found marked as trigger", MessageType.Warning);
}
}
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(isExplicitProp, explicitLabel);
if(isExplicitProp.boolValue)
{ EditorGUILayout.PropertyField(activatorsProp, true); }
else
{ EditorGUILayout.PropertyField(activatorLayersProp); }
EditorGUILayout.PropertyField(onEnterProp);
EditorGUILayout.PropertyField(onStayProp);
EditorGUILayout.PropertyField(onExitProp);
if (EditorGUI.EndChangeCheck())
{ serializedObject.ApplyModifiedProperties(); }
}
}
@Stektpotet
Copy link
Author

Stektpotet commented Sep 15, 2017

An extremely powerful trigger-system for small prototype-projects

How to implement the system into your project:

  • Add these classes to your file structure within you project's asset-folder. (Make sure to place TriggerEditor.cs within a folder called "Editor")

  • I'd recommend placing the three first files in the same folder: e.g. Assets/Scripts/SimpleTrigger
    and then placing the TriggerEditor within Assets/Scripts/SimpleTrigger/Editor

  • Then it's simply a case of adding "UnityActions" within the OnEnter/Stay/Exit boxes, wich corresponds to the standard messages within unity's monobehaviours (OnTriggerEnter/Stay/Exit/-2D).

  • You can now select a target for your action (I.e. the one to respond to something entering/staying/exiting) and select a PUBLIC FUNCTION on said objects' components

  • Notice that you can also tick "explicit" to change the trigger to only react to specific colliders in your scene, the default behaviour otherwise is to react to a layermask, i.e. all objects marked as on either of the specified layers.

DISCLAIMER:
As this system take use of binary-serialized callbacks (afaik) it does not work well with large projects where many people would change the different trigger-callbacks, Therefore I'd never really reccomend building larger games with this system, as it has a tendency to break, which will cause your game logic to be lost.
I used a similar system during a larger project in the course Experience Design - IMT1362 which after a few weeks of work caused quite a bit of trouble. (minor changes in the code would cause all the callbacks to be lost, changes to the target objects might also cause problems, though not so severe, etc.)
HOWEVER:
Using this for a weekend-gamejam or something similar (fast prototyping) will be very useful as it's so extremely easy to connect so many different parts of your game/app together.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment