# Custom Triggers

A **Trigger** derives from `Trigger`, subscribes in `OnEnable`, and calls `Run(args)` when the observed event occurs. Its lifecycle must pair every subscription with an unsubscription.

## The lifecycle

Pair setup and cleanup with the Event component's enabled state:

| Override | Called when | Do here |
| :--- | :--- | :--- |
| `OnEnable()` | The Event component is enabled. | Subscribe. |
| `OnDisable()` | The Event component is disabled. | Unsubscribe. |
| `OnDestroy()` | The component is destroyed. | Final cleanup. |

The base class handles `OnAwake` and assigns `Component`, which identifies the Event component that owns the Trigger. Access it from `OnEnable` onward.

!!! warning "Every subscription needs its unsubscription"
    A Trigger that subscribes in `OnEnable` and doesn't unsubscribe in `OnDisable` retains its callback after the Event is disabled. If the object is then destroyed, that callback can run against a destroyed component.

    Write both halves at the same time.

## A minimal Trigger

This Trigger subscribes to `MySystem.EventHappened` while enabled and forwards its `GameObject` argument as **Target**. The example assumes your system already defines that static event:

```cs
using System;
using UnityEngine;
using VisualScript.Icons;
using VisualScript.Runtime;

[Title("On My Event")]
[Description("Executed when the custom system raises its event")]
[Category("My System/On My Event")]

[Image(typeof(IconBell), ColorTheme.Type.Lime)]

[Serializable]
public class TriggerMyEvent : Trigger
{
    public override void OnEnable()
    {
        base.OnEnable();
        MySystem.EventHappened += this.OnHappened;
    }

    public override void OnDisable()
    {
        base.OnDisable();
        MySystem.EventHappened -= this.OnHappened;
    }

    private void OnHappened(GameObject who)
    {
        using Args args = Args.Get(this.Component, who);
        this.Run(args);
    }
}
```

`OnHappened` acquires a pooled `Args`, sets the Trigger owner as **Source**, and calls the inherited `Run` method. The `using` declaration releases the context afterward.

## Supplying context

The `Args` passed to `Run` supplies the Source and Target that every Instruction in the Event sees. Accurate context keeps the Event reusable.

Use the Trigger owner as **Source** and the other involved object as **Target**:

```cs
using Args args = Args.Get(this.Component, otherObject);
this.Run(args);
```

The `using` declaration disposes the pooled `Args` after `Run` returns. See [Args](../args.md).

!!! tip "Target identifies the other object involved"
    Instructions that resolve **Target** act on the object your Trigger supplies. Set it to the relevant object from the event so designers can reuse the same Instructions for different targets.

## Filtering

Most built-in Triggers use `TValueOrAny<T>` to filter events. **Any** accepts every value, while a specific Signal accepts only its resolved value:

```cs
[SerializeField]
private TValueOrAny<GetGameObject> m_Target = new TValueOrAny<GetGameObject>();

private void OnHappened(GameObject who)
{
    using Args args = Args.Get(this.Component, who);
    if (this.m_Target.IsSpecific && this.m_Target.Value.Get(args) != who) return;

    this.Run(args);
}
```

The filter runs after constructing `Args` because its Signal may depend on the current context.

## Reacting to Unity messages

Unity sends callbacks such as `OnTriggerEnter` and `OnMouseDown` to a `MonoBehaviour`, rather than a serialized Trigger class. Visual Script uses **handles**: small components added to the game object that receive and forward those messages.

Derive from the base class that manages the handle's lifetime:

```cs
[Serializable]
public class TriggerMyCollision : TriggerHandleSourceBase<HandleOnCollisionEnter3D>
{
    protected override void OnTrigger(GameObject target)
    {
        using Args args = Args.Get(this.Component, target);
        this.Run(args);
    }
}
```

The base class creates the handle on enable and shares it between Triggers that need the same message. It removes the handle when no Trigger needs it.

## Watching a value instead

For *fire when this value changes*, expose a [Signal](signals.md) that reports changes. The existing **On Number Change** family can then observe it.

Write a Trigger when the thing you're listening to is an **event**, and a Signal when it's a **value**.

When a dedicated value-watching Trigger is required, derive from the binding base that owns the subscription lifecycle:

```cs
[Serializable]
public class TriggerMyValueChange : TriggerCoreBindBase
{
    [SerializeField] private GetNumber m_Value = new GetNumber();

    protected override ISubscription Subscription => this.m_Value;
}
```

The base class subscribes to `m_Value` while the Trigger is enabled and runs the Event when that subscription fires.

## Checklist

- `[Serializable]`, derived from `Trigger`.
- Every `OnEnable` subscription has an `OnDisable` unsubscription.
- `base.OnEnable()` and `base.OnDisable()` are called.
- `Args` is pooled with `Args.Get` and disposed.
- **Target** is the most relevant object available.
- `GetTitle` reads as an event: the framework prefixes it with *On*.

## Where to go next

- **[Custom Signals](signals.md)** — expose values instead of events.
- **[Args](../args.md)** — build the context supplied to `Run`.
- **[Bindings](../../manual/signals/bindings.md)** — inspect change Triggers from the designer's perspective.
