Attributes
Enjoying Obstacle Course Kit?Leave a reviewLearn how the obstacle attributes work and how to create your own behaviours.
An attribute is the behaviour of an obstacle, such as moving, rotating, changing color, changing state and so on. The included obstacles that have some behaviour are all ready out-of-the-box. This means that you can ignore attributes unless you want to customize them or create your own.
How does attributes work?
Every interactive obstacle is built from three types of components that you attach to a GameObject:
| Component | What it does |
|---|---|
| Attribute | The core behaviour (e.g. animate a shader, bump or launch object) |
| Trigger | Watches for something to happen and fires the attribute |
| Callback | Reacts to what the attribute is doing (e.g. add force, fire another trigger) |
Attributes
An Attribute is the main component. Add one to a GameObject and it will manage a forward → back sequence that loops or plays on demand.
Inspector fields
| Property | Tooltip |
|---|---|
Start On |
Whether the attribute begins active |
Initial Delay |
Seconds to wait before the attributes does anything at all |
Off Action |
What happens when the attributes is turned off mid-sequence (Stop freezes immediately, Continue finished the current sequence first, then stops) |
Startup |
Controls when a sequence begins (Auto starts immediately, Delay waits a set number of seconds, Trigger waits for a Trigger components with the matching target (Begin or Return)) |
Extra Callbacks |
References Callback components that live on other GameObjects |
Extra Triggers |
References Trigger components that live on other GameObjects |
By default the Attribute automatically finds all
ICallbackandATriggercomponents on the same GameObject. The extra fields are only needed for cross-object communication.
Triggers
A Trigger watches for something and fires the Attribute when it happens. Add one alongside an Attribute.
Inspector fields
| Property | Tooltip |
|---|---|
Targets |
Which action(s) on the Attributes this trigger controls (On/Off turn the attribute on or off, Begin start a forward sequence, Return start a back sequence) |
Callbacks
A Callback listens to the Attribute's events and does something in response. Add one alongside an Attribute.
Typical setup
- Add an Attribute component to your GameObject (e.g.
Dummablewhich is useful for behaviours where you need to have full control of its state, such as a launch pad). SetStart Onto false & keep everything else the same. - Add a Trigger if you want something external to start the sequence (e.g.
CollisionTrigger& add a collider and make it a trigger). Set itsTargetstoOnandOff. - Add a Callback if you want a side-effect (e.g.
AddForceCallback). Set it to toggleOnand setStart Onto false. - Now it will launch an object whenever it touches the hitbox.
Create your own behaviour
Class hierarchy
AAttribute ← base for all attributes
└── AIntervalAttribute ← base for attributes driven by a timer
Creating a Basic Attribute
Extend AAttribute and implement two methods:
public class MyAttribute : AAttribute
{
// Return a normalized value (0–1) representing current progress.
// This is passed to callbacks every frame.
protected override float GetT() => 1f;
// Called every frame when the attribute is On and Running.
// Put your per-frame logic here.
protected override void Step() { }
}
Override Init() to set up state. Always call base.Init() first:
protected override void Init()
{
base.Init();
// your setup here
}
Override Awake() if needed. Always call base.Awake():
protected override void Awake()
{
base.Awake();
// your setup here
}
Override CanMoveWhenOff to control whether the Off Action (Stop / Continue) setting is available. Return false to always hard-stop when turned off, true to let the user choose. Defaults to true.
Creating a Timer-Based Attribute
Extend AIntervalAttribute instead. This gives you a built-in timer.
public class MyTimedAttribute : AIntervalAttribute
{
protected override float GetT() => GetTimeNormalized(); // 0 → 1 over the timer duration
protected override void Init()
{
base.Init();
SetTime(2f); // 2-second sequence
}
// Called when the timer finishes. Always call base.OnTimerFinished().
protected override void OnTimerFinished()
{
// do something at the end of each cycle
base.OnTimerFinished(); // triggers the state flip (Running → Waiting → Running)
}
}
Timer helpers
| Method | Description |
|---|---|
SetTime(float) |
Set the duration and reset the timer |
ResetTime() |
Reset timer to 0 without changing duration |
GetTime() |
Current elapsed seconds |
GetTimeNormalized() |
Current progress as 0-1 |
State Management
You never set states directly, instead use the request methods:
RequestStateChange(EState.Running); // start the sequence
RequestStateChange(EState.Waiting); // pause/end the sequence
RequestOnOffStateChange(EOnOffState.On);
RequestOnOffStateChange(EOnOffState.Off);
The direction field (EDirection.Forward / EDirection.Back) flips automatically each time a sequence finishes meaning you don't set it manually.
Creating a Custom Trigger
Extend ATrigger and call Trigger() when your condition is met:
public class MyTrigger : ATrigger
{
public override void Reset()
{
// reset whatever state your trigger tracks
}
private void Update()
{
if (SomeCondition())
Trigger(true); // true = also reset if nothing subscribed
}
}
Set Targets in the Inspector to control which Attribute action this trigger controls.
Creating a Custom Callback
Implement ICallback on any MonoBehaviour:
public class MyCallback : MonoBehaviour, ICallback
{
public void On() { }
public void Off() { }
public void Begin() { }
public void End() { }
public void BeginAtStart() { }
public void BeginAtReturn() { }
public void EndAtStart() { }
public void EndAtReturn() { }
public void Step(float t, AAttribute.EDirection direction, bool running)
{
// called every frame while On. t = 0–1 progress.
}
}
Place it on the same GameObject as the Attribute and it will be picked up automatically.

