rayIntersection method

RaycastResult<ShapeHitbox>? rayIntersection(
  1. Ray2 ray, {
  2. RaycastResult<ShapeHitbox>? out,
})

Returns whether the RaycastResult if the ray intersects the polygon.

If out is defined that is used to populate with the result and then returned, to minimize the creation of new objects.

Implementation

RaycastResult<ShapeHitbox>? rayIntersection(
  Ray2 ray, {
  RaycastResult<ShapeHitbox>? out,
}) {
  final vertices = globalVertices();
  var closestDistance = double.infinity;
  LineSegment? closestSegment;
  var crossings = 0;
  var isOverlappingPoint = false;
  for (var i = 0; i < vertices.length; i++) {
    final lineSegment = getEdge(i, vertices: vertices);
    final distance = ray.lineSegmentIntersection(lineSegment);
    // Using a small value above 0 just because of rounding errors later that
    // might cause a ray to go in the wrong direction.
    if (distance != null && distance > 0.0000000001) {
      crossings++;
      if (distance < closestDistance) {
        isOverlappingPoint = false;
        closestDistance = distance;
        closestSegment = lineSegment;
      } else if (distance == closestDistance) {
        isOverlappingPoint = true;
      }
    }
  }
  if (crossings > 0) {
    final intersectionPoint =
        ray.point(closestDistance, out: out?.intersectionPoint);
    // This is "from" to "to" since it is defined ccw in the canvas
    // coordinate system
    _temporaryNormal
      ..setFrom(closestSegment!.from)
      ..sub(closestSegment.to);
    _temporaryNormal
      ..setValues(_temporaryNormal.y, -_temporaryNormal.x)
      ..normalize();
    var isInsideHitbox = false;
    if (crossings == 1 || isOverlappingPoint) {
      _temporaryNormal.invert();
      isInsideHitbox = true;
    }
    final reflectionDirection =
        (out?.reflectionRay?.direction ?? Vector2.zero())
          ..setFrom(ray.direction)
          ..reflect(_temporaryNormal);

    final reflectionRay = (out?.reflectionRay
          ?..setWith(
            origin: intersectionPoint,
            direction: reflectionDirection,
          )) ??
        Ray2(origin: intersectionPoint, direction: reflectionDirection);
    return (out ?? RaycastResult<ShapeHitbox>())
      ..setWith(
        hitbox: this as T,
        reflectionRay: reflectionRay,
        normal: _temporaryNormal,
        distance: closestDistance,
        isInsideHitbox: isInsideHitbox,
      );
  }
  out?.reset();
  return null;
}