예제 #1
0
        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);
                }
            });
        }
예제 #2
0
        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());
            }
        }
예제 #3
0
        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);
        }
예제 #4
0
        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);
                }
            });
        }
예제 #5
0
        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);
        }
예제 #6
0
        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));
        }
예제 #7
0
        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));
        }
예제 #8
0
        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);
        }
예제 #9
0
 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)
                ));
 }
예제 #10
0
 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)
                ));
 }
예제 #11
0
        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);
        }
예제 #12
0
        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);
        }
예제 #13
0
        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);
        }
예제 #14
0
        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);
        }
예제 #15
0
        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);
        }
예제 #16
0
        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);
        }
예제 #17
0
 public static IRectangularF CopyBounds(this IRectangularF rectangular) => RectangularF.Create(rectangular.Left, rectangular.Top, rectangular.Width, rectangular.Height);
예제 #18
0
 public static IRectangularF Offset(this IRectangularF rectangle, float dx, float dy) => RectangularF.Create(rectangle.Left + dx, rectangle.Top + dy, rectangle.Width, rectangle.Height);
예제 #19
0
        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);
        }
예제 #20
0
 public static IRectangularF GetOffsetByPixels(this IRectangularF r, float dx, float dy)
 {
     return(RectangularF.Create(r.Left + dx, r.Top + dy, r.Width, r.Height));
 }
예제 #21
0
 public static IRectangularF CenterRect(this IRectangularF rectangular) => RectangularF.Create(rectangular.CenterX(), rectangular.CenterY(), 0, 0);
예제 #22
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;
            }
        }