Example #1
0
 /// <summary>
 /// Moves a portable object along a ray, taking into account portal teleportation.  Portal velocity is ignored for this method.
 /// </summary>
 /// <param name="portalable">Instance travelling along ray.</param>
 /// <param name="portals">Collection of portals used for portal teleportation.</param>
 /// <param name="portalEnter">Callback that is executed after entering a portal.</param>
 public static void RayCast(IPortalable portalable, IEnumerable<IPortal> portals, Settings settings, Action<EnterCallbackData, double> portalEnter = null)
 {
     Debug.Assert(settings.MaxIterations >= 0);
     Debug.Assert(portalable != null);
     Debug.Assert(portals != null);
     Debug.Assert(settings.TimeScale >= 0);
     Debug.Assert(!(portalable is IPortal));
     if (portalable.GetVelocity().Position.Length == 0 || settings.TimeScale == 0)
     {
         return;
     }
     _rayCast(
         portalable,
         portals,
         portalable.GetVelocity().Position.Length * settings.TimeScale,
         null,
         portalEnter,
         settings,
         0);
 }
Example #2
0
        private static void _rayCast(IPortalable placeable, IEnumerable<IPortal> portals, double movementLeft, IPortal portalPrevious, Action<EnterCallbackData, double> portalEnter, Settings settings, int count)
        {
            Transform2 begin = placeable.GetTransform();
            Transform2 velocity = placeable.GetVelocity().Multiply(settings.TimeScale);
            if (settings.MaxIterations <= count)
            {
                //If we run out of iterations before running out of movement, call _rayEnd with 0 movementLeft just to make sure the AdjustEnpoint setting is handled.
                _rayEnd(placeable, portals, 0, portalPrevious, settings, begin, velocity);
                return;
            }
            if (!placeable.IsPortalable)
            {
                _rayEnd(placeable, portals, movementLeft, portalPrevious, settings, begin, velocity);
                return;
            }
            double distanceMin = movementLeft;
            IPortal portalNearest = null;
            IntersectCoord intersectNearest = new IntersectCoord();
            LineF ray = new LineF(begin.Position, begin.Position + velocity.Position);
            foreach (IPortal p in portals)
            {
                if (!Portal.IsValid(p) || portalPrevious == p)
                {
                    continue;
                }

                LineF portalLine = new LineF(Portal.GetWorldVerts(p));
                IntersectCoord intersect = MathExt.LineLineIntersect(portalLine, ray, true);
                double distance = ((Vector2d)begin.Position - intersect.Position).Length;
                if (intersect.Exists && distance < distanceMin)
                {
                    distanceMin = distance;
                    portalNearest = p;
                    intersectNearest = intersect;
                }
            }
            if (portalNearest != null)
            {
                movementLeft -= distanceMin;

                double t = (velocity.Position.Length - movementLeft) / velocity.Position.Length;

                begin.Position = (Vector2)intersectNearest.Position;
                placeable.SetTransform(begin);
                Portal.Enter(portalNearest, placeable, (float)intersectNearest.TFirst, true);

                portalEnter?.Invoke(new EnterCallbackData(portalNearest, placeable, intersectNearest.TFirst), t);

                movementLeft *= Math.Abs(placeable.GetTransform().Size / begin.Size);
                _rayCast(placeable, portals, movementLeft, portalNearest.Linked, portalEnter, settings, count + 1);
            }
            else
            {
                _rayEnd(placeable, portals, movementLeft, portalPrevious, settings, begin, velocity);
            }
        }
Example #3
0
 private static void _rayEnd(IPortalable placeable, IEnumerable<IPortal> portals, double movementLeft, IPortal portalPrevious, Settings settings, Transform2 begin, Transform2 velocity)
 {
     begin.Position += velocity.Position.Normalized() * (float)movementLeft;
     if (settings.AdjustEndpoint)
     {
         /*After the end position of the ray has been determined, adjust it's position so that it isn't too close to
          * any portal.  Otherwise there is a risk of ambiguity as to which side of a portal the end point is on.*/
         begin = AddMargin(portals, portalPrevious, begin, velocity);
     }
     placeable.SetTransform(begin);
 }