public void Add(IPortalable portalable, CurveTransform2 curve) { animated.Add(portalable, curve.ShallowClone()); portalable.EnterPortal += (data, transformPrev, velocityPrev) => { animated[portalable].EnterPortal(data.EntrancePortal, data.EntrancePortal.Linked); }; }
/// <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); }
public void Move(IPortalable moveable) { Transform2 v = moveable.GetVelocity(); Transform2 t = moveable.GetTransform(); if (Input.KeyDown(Key.Left)) { v.Position += t.GetRight() * -Acceleration * Math.Abs(Transform2.GetSize(moveable)); } if (Input.KeyDown(Key.Right)) { v.Position += t.GetRight() * Acceleration * Math.Abs(Transform2.GetSize(moveable)); } if (Input.KeyDown(Key.Up)) { v.Position += t.GetUp() * Acceleration * Math.Abs(Transform2.GetSize(moveable)); } if (Input.KeyDown(Key.Down)) { v.Position += t.GetUp() * -Acceleration * Math.Abs(Transform2.GetSize(moveable)); } v.Position *= 1 - Friction; moveable.SetVelocity(v); }
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); } }
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); }