@Override
  public boolean update(final int deltaTime) {

    if (mNumPoints > 0) {

      if (!mFollowingHead && mTarget != null) {
        final PointF p1 = mTarget.getPosition();
        final float dx = p1.x - (mPoints[0].x - mTargetOffset.x);
        final float dy = p1.y - (mPoints[0].y - mTargetOffset.y);
        if (Math.abs(dx) >= 1 || Math.abs(dy) >= 1) {
          // flag
          mFollowingHead = true;
        }
      }

      if (mFollowingHead) {
        // calculate time loop for consistency with different framerate
        final int loop = deltaTime / Scene.DEFAULT_MSPF;
        PointF p1, p2;
        float dx, dy;
        for (int n = 0; n < loop; n++) {
          for (int i = mNumPoints - 1; i > 0; i--) {
            p1 = mPoints[i];
            p2 = mPoints[i - 1];
            dx = p2.x - p1.x;
            dy = p2.y - p1.y;
            if (mMinLength <= 1 || (dx * dx + dy * dy) > (mSegmentLength * mSegmentLength)) {
              // move toward the leading point
              p1.x += dx * mMotionEasingX;
              p1.y += dy * mMotionEasingY;
            }
          }
        }

        // follow the target
        if (mTarget != null) {
          // set the head
          final PointF pos = mTarget.getPosition();
          mPoints[0].set(pos.x + mTargetOffset.x, pos.y + mTargetOffset.y);
        }

        // apply
        setPoints(mPoints);
      }
    }

    return super.update(deltaTime);
  }
  public void setNumPoints(final int numPoints) {
    mNumPointsUsed = mNumPoints = numPoints;

    if (numPoints < 2) {
      mPoints = null;
      return;
    }

    if (mPoints == null || mPoints.length != numPoints) {
      mPoints = new PointF[numPoints];

      final PointF pos = (mTarget != null) ? mTarget.getPosition() : null;
      for (int i = 0; i < numPoints; i++) {
        mPoints[i] = new PointF();

        if (pos != null) {
          mPoints[i].set(pos.x + mTargetOffset.x, pos.y + mTargetOffset.y);
        }
      }

      // find the length
      mSegmentLength = mMinLength / (mNumPoints < 2 ? 1 : mNumPoints - 1);

      // optimize
      mTotalLength = 0;
      mFollowingHead = false;
    }

    // re-count, each point has 2 vertices
    allocateVertices(numPoints * 2, VERTEX_POINTER_SIZE);
  }
  public void setTarget(final Manipulatable target) {
    mTarget = target;

    if (mTarget != null) {
      final PointF pos = mTarget.getPosition();
      for (int i = 0; i < mNumPoints; i++) {
        mPoints[i].set(pos.x + mTargetOffset.x, pos.y + mTargetOffset.y);
      }

      // apply
      setPoints(mPoints);
    }
  }