Last active
September 15, 2017 22:40
-
-
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)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.