update method

  1. @override
void update(
  1. double deltaSeconds
)
override

Called once per frame while the component is mounted, enabled, and loaded. deltaSeconds is the elapsed time since the previous tick.

Implementation

@override
void update(double deltaSeconds) {
  _time += deltaSeconds;
  final world = node.globalTransform.getTranslation();

  if (emitting) {
    if (_worldPoints.isEmpty) {
      _worldPoints.insert(0, world.clone());
      _bornTimes.insert(0, _time);
    } else {
      // The head follows the node continuously; a new anchor is dropped
      // once it has traveled far enough from the previous one.
      _worldPoints.first.setFrom(world);
      _bornTimes[0] = _time;
      final anchored = _worldPoints.length > 1
          ? _worldPoints[1]
          : _worldPoints.first;
      if (_worldPoints.length == 1 ||
          anchored.distanceTo(world) >= minVertexDistance) {
        _worldPoints.insert(0, world.clone());
        _bornTimes.insert(0, _time);
      }
    }
  }

  // Expire by age and by capacity (head stays, tail goes).
  while (_worldPoints.length > _geometry.maxPoints ||
      (_bornTimes.isNotEmpty && _time - _bornTimes.last > lifetime)) {
    _worldPoints.removeLast();
    _bornTimes.removeLast();
    if (_worldPoints.isEmpty) break;
  }

  // Repack into node-local space (the mesh renders under the moving
  // node's transform, but the ribbon must stay pinned in the world).
  _scratchInverse.setFrom(node.globalTransform);
  _scratchInverse.invert();
  _geometry.setTrail(
    _worldPoints,
    _scratchInverse,
    (t) => width * (widthOverTrail?.sample(t) ?? (1.0 - t)),
    (t, out) {
      final gradient = colorOverTrail;
      if (gradient != null) {
        gradient.sample(t, out);
      } else {
        out.setValues(1, 1, 1, 1.0 - t);
      }
      return out;
    },
    _scratchColor,
  );
}