Tutorial: Measuring Motion¶
Track speed, distance, acceleration, angular velocity, bounds, and other spatial data on Attachables, AttachmentPoints, or any GameObject. Write the measurements into a DataStorage by keys, then read them anywhere: conditions, UI bindings, reactors, save state.
By the end of this tutorial you'll have a cube whose live speed and traveled distance are stored under Keys, and a Reactor that fires when speed crosses a threshold.
Prerequisites: A scene with a moving Cube (an AttachableObject driven by an AttachingAgent is a good baseline). Basic familiarity with DataStorage helps.
How Measurements Fit Together¶
Three pieces in play:
- A Process Component on a GameObject. It decides when measuring happens.
- A Measurement Command as its process. It resolves which GameObject to measure.
- Individual measurements inside the command: Speed, Position, Distance Traveled, and so on. Each one writes into its own Sink.
flowchart LR
PC["Process Component<br/>(when)"]
MC["Measurement Command<br/>(target: the cube)"]
M1["Speed"]
M2["Distance Traveled"]
DS["DataStorage<br/>(keyed values)"]
PC --> MC
MC --> M1
MC --> M2
M1 -->|sink: 'Speed' key| DS
M2 -->|sink: 'DistanceTraveled' key| DS
Once the values land in DataStorage, anything that reads from a Key picks them up. A sink does not have to be a key: a value asset or any other settable value works too.
1. Create the DataStorage¶
Right-click in the Project window → Create → Jungle → Data → Data Storage. Name the asset CubeMotionStorage.
Alternatively, put a DataStorageComponent on the GameObject for an instance-scoped storage.
2. Make a Few Keys¶
Each value in the storage lives under a Key asset. Create:
- Create → Jungle → Data → Key, name it Speed.
- Repeat for DistanceTraveled.
3. Add a Process Component¶
On the Cube (or any controller GameObject), add a Process Component.
Add Component → Jungle → Process → Process Component
In its Process field, pick Measurement Command. Point its Target at the cube.
- Process: Measurement Command.
- Target: the object to measure.
Three measurement commands exist. Pick by what you want to measure:
- Measurement Command: any GameObject. Motion and spatial measurements (speed, position, bounds, …). Use this one for this tutorial.
- Attachable Object Measurement Command: an Attachable. Attach counts, hold durations, Is Currently Held.
- Attachment Point Measurement Command: an AttachmentPoint. Attach counts, hold durations, Is Holding.
4. Add Measurements¶
Click + on the command's measurement list. The picker shows:
| Measurement | What it writes |
|---|---|
| Position | World position vector. |
| Velocity | Velocity vector (position delta / time). |
| Speed | Scalar speed. |
| Acceleration | How fast the speed is changing. |
| Angular Velocity | Rotation rate. |
| Accumulated Twist | Total degrees turned around an axis. |
| Distance Traveled | Cumulative distance moved since the command started. |
| Distance To Object | Distance between the target and another object. |
| Bounds | World-space renderer bounds. |
Add Speed and Distance Traveled. For each one, set Sink to Float From Data Storage. Switch its Data Storage to DataStorage Value From Asset and drop in CubeMotionStorage, then set Key to Speed (or DistanceTraveled).
Most measurements also have an optional modifier list (smoothing, clamping, remapping) and a schedule that sets how often it samples. The default is every frame.
- Sink: where the measured value goes.
- The storage asset from step 1.
- The key from step 2.
Press Play and drag the cube. Open the DataStorage inspector, or the Jungle Monitor window (Window > Jungle > Monitor), and you'll see Speed and DistanceTraveled updating in real time.
5. Read the Measurements Elsewhere¶
The measurements are now plain DataStorage entries. Anything that takes an observable value can read them.
Display in UI¶
Bind a UI label to the Speed Key with a Float From Keyed Source value and a UI binder.
React to a Threshold with a Reactor¶
Add a Reactor component. Click + on its targets and pick the Float target. Configure:
| Field | Value |
|---|---|
| Source | Float From Keyed Source reading the Speed key from CubeMotionStorage. |
| Trigger | Threshold: Above 5.0. |
| Process | Whatever you want to run when the cube is moving fast: spawn a trail particle, play a whoosh sound, raise a signal. |
Now the Reactor fires when the cube's speed climbs above 5, and stops when it drops back. Hysteresis on the trigger prevents flutter near the boundary.
6. Lifecycle: When Are Measurements Active?¶
Measurements run while the Process Component runs, and stop when it stops.
- Default frame: on enable / on disable. Measurements update while the GameObject is active.
- For "measure only while attached": set the Process Component's Execution Frame to a Targeted Cycle Frame on the Attachable's
Attachedcycle. Or put the Measurement Command in the While Running slot of a cycle reaction on a Reactor. - For "measure only during a specific phase": tie the frame to whichever phase or signal makes sense.
Distance Traveled starts again from 0 each time the command starts. The other measurements simply stop updating when it stops.
7. Reset-on-Play¶
DataStorage values are part of the asset by default. They persist between play sessions and between scene reloads. For measurements you usually don't want that.
To clear an asset at play start, add a second Process Component that starts with the scene, and give it a Data Storage Command with a Clear operation.
See the DataStorage docs for the full reset patterns.
8. Authoring Custom Measurements¶
The shipped measurement set covers most needs. To add a new one, derive from SampledMeasurement<GameObject, T> and implement IObjectMeasurement (or IAttachableObjectMeasurement / IAttachmentPointMeasurement with the matching target type). Declare a settable sink field, return it from Sink, and call Write in Sample. Mark the class with [JungleClassInfo] and [TypeHelp] so designers see it in the picker.
Next Steps¶
- Data system overview: DataStorage and Keys.
- Reactor reference: running responses on measurement changes.
- Writing Values tutorial: the same Process Component pattern for writing values.
- ProcessComponent reference.