public static async Task AnimateAsync(this IRectangularF rectangular, RectangularAnimationOptions options) { var startX = rectangular.Left; var startY = rectangular.Top; var startW = rectangular.Width; var startH = rectangular.Height; await Animator.AnimateAsync(new FloatAnimatorOptions() { Duration = options.Duration, AutoReverse = options.AutoReverse, AutoReverseDelay = options.AutoReverseDelay, DelayProvider = options.DelayProvider, Loop = options.Loop, EasingFunction = options.EasingFunction, From = 0, To = 1, IsCancelled = options.IsCancelled, Setter = v => { var dest = options.Destination(); var xDelta = dest.Left - startX; var yDelta = dest.Top - startY; var wDelta = dest.Width - startW; var hDelta = dest.Height - startH; var frameX = startX + (v *xDelta); var frameY = startY + (v *yDelta); var frameW = startW + (v *wDelta); var frameH = startH + (v *hDelta); var frameBounds = RectangularF.Create(frameX, frameY, frameW, frameH); options.Setter(rectangular, frameBounds); } }); }
public static ILocationF GetNudgeLocation(this SpacialElement el, IRectangularF desiredLocation = null, float optimalAngle = 0, int?z = null) { desiredLocation = desiredLocation ?? el.EffectiveBounds(); var obstacles = el.GetObstacles(z: z); if (obstacles.Where(o => o.Touches(desiredLocation)).Any() || SpaceTime.CurrentSpaceTime.Bounds.Contains(desiredLocation) == false) { foreach (var angle in Enumerate360Angles(optimalAngle)) { for (var d = .1f; d < 15f; d += .1f) { var effectiveAngle = angle % 360; var testLoc = desiredLocation.MoveTowards(effectiveAngle, d); var testArea = RectangularF.Create(testLoc.Left, testLoc.Top, desiredLocation.Width, desiredLocation.Height); if (obstacles.Where(o => o.Touches(testArea)).None() && SpaceTime.CurrentSpaceTime.Bounds.Contains(testArea)) { return(testLoc.TopLeft()); } } } return(null); } else { return(el.TopLeft()); } }
public static IRectangularF MoveTowards(this IRectangularF r, float angle, float distance) { var newLoc = MoveTowards(r.TopLeft(), angle, distance); var ret = RectangularF.Create(newLoc.Left, newLoc.Top, r.Width, r.Height); return(ret); }
public SpaceTime(float width, float height, TimeSpan?increment = null, TimeSpan?now = null) : base(increment, now) { this.Width = width; this.Height = height; this.Bounds = RectangularF.Create(0, 0, Width, Height); Invoke(() => { this.ChangeTracker = new SpacialChangeTracker(SpacialElementChanged); this.OnDisposed(ChangeTracker.Dispose); }); addedSub = this.TimeFunctionAdded.SubscribeUnmanaged((f) => { if (f is SpacialElement) { SpacialElementAdded.Fire(f as SpacialElement); SpacialElementChanged.Fire(f as SpacialElement); } }); removedSub = this.TimeFunctionRemoved.SubscribeUnmanaged((f) => { if (f is SpacialElement) { SpacialElementRemoved.Fire(f as SpacialElement); SpacialElementChanged.Fire(f as SpacialElement); } }); }
private static List <IRectangularF> GetLineOfSight(this IRectangularF from, IRectangularF to, List <IRectangularF> obstacles, float increment = .5f) { IRectangularF current = from; var currentDistance = current.CalculateDistanceTo(to); var a = current.Center().CalculateAngleTo(to.Center()); var path = new List <IRectangularF>(); while (currentDistance > increment) { current = RectangularF.Create(MoveTowards(current.Center(), a, increment), current); current = RectangularF.Create(current.Left - current.Width / 2, current.Top - current.Height / 2, current.Width, current.Height); foreach (var obstacle in obstacles) { if (obstacle == to || obstacle == from) { continue; } else if (obstacle.OverlapPercentage(current) > 0) { return(null); } } path.Add(current); currentDistance = current.CalculateDistanceTo(to); } return(path); }
public static IRectangularF ToRect(this ILocationF loc, float w, float h) { var left = loc.Left - w / 2; var top = loc.Top - h / 2; return(RectangularF.Create(left, top, w, h)); }
public static IRectangularF Shrink(this IRectangularF rect, float percentage) { var center = rect.Center(); var newW = rect.Width * (1 - percentage); var newH = rect.Height * (1 - percentage); return(RectangularF.Create(center.Left - newW / 2, center.Top - newH / 2, newW, newH)); }
public bool IsComingTowards(IRectangularF target) { var d = Element.CalculateDistanceTo(target); var projectedLocation = this.Element.TopLeft().MoveTowards(this.Angle, d); var projectedRect = RectangularF.Create(projectedLocation.Left, projectedLocation.Top, Element.Width, Element.Height); var ret = projectedRect.CalculateDistanceTo(target); return(ret < .5); }
public static IRectangularF Round(this IRectangularF rect) { return(RectangularF.Create( (int)Math.Round(rect.Left), (int)Math.Round(rect.Top), (int)Math.Round(rect.Width), (int)Math.Round(rect.Height) )); }
public static IRectangularF Round(this IRectangularF rect) { return(RectangularF.Create( Geometry.Round(rect.Left), Geometry.Round(rect.Top), Geometry.Round(rect.Width), Geometry.Round(rect.Height) )); }
public static IRectangularF Resize(this IRectangularF me, float ratio) { var newW = me.Width * ratio; var newH = me.Height * ratio; var leftAdjust = (me.Width - newW) / 2; var topAdjust = (me.Height - newH) / 2; var ret = RectangularF.Create(me.Left + leftAdjust, me.Top + topAdjust, newW, newH); return(ret); }
public static HitPrediction PredictHit(HitDetectionOptions options) { HitPrediction prediction = new HitPrediction(); var left = Math.Min(options.MovingObject.Left, options.MovingObject.Left + options.Dx); var top = Math.Min(options.MovingObject.Top, options.MovingObject.Top + options.Dy); var right = Math.Max(options.MovingObject.Left + options.MovingObject.Width, options.MovingObject.Left + options.MovingObject.Width + options.Dx); var bottom = Math.Max(options.MovingObject.Top + options.MovingObject.Height, options.MovingObject.Top + options.MovingObject.Height + options.Dy); var relevantArea = RectangularF.Create(left, top, right - left, bottom - top); var effectiveObstacles = options.Obstacles.Where(o => o.Touches(relevantArea)).ToList(); if (options.Dx == 0 && options.Dy == 0) { prediction.Direction = Direction.None; prediction.Type = HitType.None; return(prediction); } var endPoint = RectangularF.Create(options.MovingObject.Left + options.Dx, options.MovingObject.Top + options.Dy, options.MovingObject.Width, options.MovingObject.Height); var angle = options.MovingObject.CalculateAngleTo(endPoint); var d = endPoint.CalculateDistanceTo(options.MovingObject); for (var dPrime = options.Precision; dPrime < d; dPrime += options.Precision) { var testLocation = options.MovingObject.Center().MoveTowards(angle, dPrime); var testArea = RectangularF.Create(testLocation.Left - options.MovingObject.Width / 2, testLocation.Top - options.MovingObject.Height / 2, options.MovingObject.Width, options.MovingObject.Height); var obstacleHit = effectiveObstacles.Where(o => IsIncluded(options, o) && o.Touches(testArea) == true).FirstOrDefault(); if (obstacleHit != null) { return(new HitPrediction() { Type = HitType.Obstacle, ObstacleHit = obstacleHit }); } } var obstacleHitFinal = effectiveObstacles.Where(o => IsIncluded(options, o) && o.Touches(endPoint) == true).FirstOrDefault(); if (obstacleHitFinal != null) { return(new HitPrediction() { Type = HitType.Obstacle, ObstacleHit = obstacleHitFinal }); } prediction.Type = HitType.None; return(prediction); }
public static float LineOfSightVisibility(this IRectangularF from, float angle, IEnumerable <IRectangularF> obstacles, float range, float increment = .5f) { for (var d = increment; d < range; d += increment) { var testLocation = from.Center().MoveTowards(angle, d); var testRect = RectangularF.Create(testLocation.Left - from.Width / 2, testLocation.Top - from.Height / 2, from.Width, from.Height); if (obstacles.Where(o => o.Touches(testRect)).Any() || SpaceTime.CurrentSpaceTime.Bounds.Contains(testRect) == false) { return(d); } } return(range); }
public static IRectangularF CalculateMassBounds(this IEnumerable <IRectangularF> parts) { var left = float.MaxValue; var top = float.MaxValue; var right = float.MinValue; var bottom = float.MinValue; foreach (var part in parts) { left = Math.Min(left, part.Left); top = Math.Min(top, part.Top); right = Math.Max(right, part.Right()); bottom = Math.Max(bottom, part.Bottom()); } var bounds = RectangularF.Create(left, top, right - left, bottom - top); return(bounds); }
public static List <IRectangularF> GetObstacles(this SpacialElement element, IEnumerable <SpacialElement> exclusions = null, IEnumerable <Type> excludedTypes = null) { var ret = new List <IRectangularF>(); foreach (var e in SpaceTime.CurrentSpaceTime.Elements) { if (e == element) { continue; } else if (exclusions != null && exclusions.Contains(e)) { continue; } else if (e.ZIndex != element.ZIndex) { continue; } else if (e.HasSimpleTag(PassThruTag)) { continue; } else if (excludedTypes != null && excludedTypes.Contains(e.GetType())) { continue; } else { ret.Add(e); } } ret.Add(RectangularF.Create(0, -1, SpaceTime.CurrentSpaceTime.Width, 1)); // top boundary ret.Add(RectangularF.Create(0, SpaceTime.CurrentSpaceTime.Height, SpaceTime.CurrentSpaceTime.Width, 1)); // bottom boundary ret.Add(RectangularF.Create(-1, 0, 1, SpaceTime.CurrentSpaceTime.Height)); // left boundary ret.Add(RectangularF.Create(SpaceTime.CurrentSpaceTime.Width, 0, 1, SpaceTime.CurrentSpaceTime.Height)); // right boundary return(ret); }
public static ILocationF GetNudgeLocation(this SpacialElement el, IRectangularF desiredLocation = null, float initialAngle = 0) { desiredLocation = desiredLocation ?? el.EffectiveBounds(); var obstacles = el.GetObstacles(); if (obstacles.Where(o => o.Touches(desiredLocation)).Any()) { for (var d = 1f; d < 15; d++) { for (var angle = initialAngle; angle < initialAngle + 360; angle += 20) { var effectiveAngle = angle % 360; var testLoc = desiredLocation.MoveTowards(effectiveAngle, d); var testArea = RectangularF.Create(testLoc.Left, testLoc.Top, desiredLocation.Width, desiredLocation.Height); if (obstacles.Where(o => o.Touches(testArea)).None() && SpaceTime.CurrentSpaceTime.Bounds.Contains(testArea)) { return(testLoc.TopLeft()); } } } } return(null); }
public static IRectangularF CopyBounds(this IRectangularF rectangular) => RectangularF.Create(rectangular.Left, rectangular.Top, rectangular.Width, rectangular.Height);
public static IRectangularF Offset(this IRectangularF rectangle, float dx, float dy) => RectangularF.Create(rectangle.Left + dx, rectangle.Top + dy, rectangle.Width, rectangle.Height);
public static List <IRectangularF> GetObstacles(this SpacialElement element, IEnumerable <SpacialElement> exclusions = null, IEnumerable <Type> excludedTypes = null, Func <IEnumerable <SpacialElement> > dynamicExclusions = null) { var ret = new List <IRectangularF>(); var dynamicEx = dynamicExclusions != null?dynamicExclusions.Invoke() : null; foreach (var e in SpaceTime.CurrentSpaceTime.Elements) { if (e == element) { continue; } else if (exclusions != null && exclusions.Contains(e)) { continue; } else if (e.ZIndex != element.ZIndex) { continue; } else if (e.HasSimpleTag(PassThruTag)) { continue; } else if (excludedTypes != null && excludedTypes.Where(t => e.GetType() == t || e.GetType().IsSubclassOf(t) || e.GetType().GetInterfaces().Contains(t)).Any()) { continue; } else if (dynamicEx != null && dynamicEx.Contains(e)) { continue; } else if (element is IHaveMassBounds && (element as IHaveMassBounds).IsPartOfMass(e)) { // own mass can't obstruct itself continue; } else if (e is WeaponElement && (e as WeaponElement).Weapon?.Holder == element) { // Characters can't hit their own weapon elements continue; } else if (e is WeaponElement && (e as WeaponElement).Weapon?.Holder != null && element is IHaveMassBounds && (element as IHaveMassBounds).IsPartOfMass((e as WeaponElement).Weapon?.Holder)) { // Characters can't hit their own weapon elements continue; } else if (element is WeaponElement && e.HasSimpleTag(WeaponsPassThruTag)) { continue; } else if (element is Character && e.HasSimpleTag(WeaponsPassThruTag)) { continue; } else if (element is WeaponElement && (element as WeaponElement).Weapon?.Holder == e) { // Characters can't hit their own weapon elements continue; } else if (e is WeaponElement && element is WeaponElement && (e as WeaponElement).Weapon?.Holder == (element as WeaponElement).Weapon?.Holder) { if (e is Explosive || element is Explosive) { if (e is WeaponElement && (e as WeaponElement).Weapon?.Style == WeaponStyle.Shield) { continue; } else if (e is WeaponElement && (e as WeaponElement).Weapon?.Style == WeaponStyle.Shield) { continue; } else { ret.Add(e); } } else { // WeaponElements from the same holder don't collide with each other continue; } } else { ret.Add(e); } } ret.Add(RectangularF.Create(0, -1, SpaceTime.CurrentSpaceTime.Width, 1)); // top boundary ret.Add(RectangularF.Create(0, SpaceTime.CurrentSpaceTime.Height, SpaceTime.CurrentSpaceTime.Width, 1)); // bottom boundary ret.Add(RectangularF.Create(-1, 0, 1, SpaceTime.CurrentSpaceTime.Height)); // left boundary ret.Add(RectangularF.Create(SpaceTime.CurrentSpaceTime.Width, 0, 1, SpaceTime.CurrentSpaceTime.Height)); // right boundary return(ret); }
public static IRectangularF GetOffsetByPixels(this IRectangularF r, float dx, float dy) { return(RectangularF.Create(r.Left + dx, r.Top + dy, r.Width, r.Height)); }
public static IRectangularF CenterRect(this IRectangularF rectangular) => RectangularF.Create(rectangular.CenterX(), rectangular.CenterY(), 0, 0);
public override void Evaluate() { float dt = (float)Governor.Rate.TotalSeconds; if (dt == 0) { dt = (float)Time.CurrentTime.Increment.TotalSeconds; } float dx = SpeedX * dt; float dy = SpeedY * dt; var obstacles = GetObstacles().ToList(); if (dx == 0 && dy == 0) { return; } var effectiveExclusions = HitDetectionExclusionTypes.Count > 0 || HitDetectionExclusions.Count == 0 ? new List <IRectangularF>(this.HitDetectionExclusions.Union(SpaceTime.CurrentSpaceTime.Elements.Where(e => HitDetectionExclusionTypes.Contains(e.GetType())))) : null; var hitPrediction = HitDetection.PredictHit(new HitDetectionOptions() { Bounds = SpaceTime.CurrentSpaceTime.Bounds, MovingObject = Element, Exclusions = effectiveExclusions, Obstacles = obstacles.As <IRectangularF>().ToList(), Dx = dx, Dy = dy, }); if (hitPrediction.Type != HitType.None) { float angle = Element.Center().CalculateAngleTo(hitPrediction.ObstacleHit.Center()); if (haveMovedSinceLastHitDetection) { ImpactOccurred?.Fire(new Impact() { Angle = angle, MovingObject = Element, ObstacleHit = hitPrediction.ObstacleHit, HitType = hitPrediction.Type, }); haveMovedSinceLastHitDetection = false; var testArea = RectangularF.Create(Element.Left + dx, Element.Top + dy, Element.Width, Element.Height); if (hitPrediction.Direction == Direction.Down || hitPrediction.Direction == Direction.Up) { SpeedY = -SpeedY * Bounciness; SpeedX = SpeedX * ImpactFriction; } else if (hitPrediction.Direction == Direction.Left || hitPrediction.Direction == Direction.Right) { SpeedX = -SpeedX * Bounciness; SpeedY = SpeedY * ImpactFriction; } else { SpeedX = -SpeedX * Bounciness; SpeedY = -SpeedY * Bounciness; } Element.SizeOrPositionChanged.Fire(); } } else { var oldLocation = Element.CopyBounds(); Element.MoveBy(dx, dy); isSettingAnglePrivately = true; this.Angle = oldLocation.Center().CalculateAngleTo(Element.Center()); isSettingAnglePrivately = false; haveMovedSinceLastHitDetection = true; } }