Пример #1
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());
            }
        }
Пример #2
0
        public static NudgeEvent NudgeFree(this SpacialElement el, IRectangularF desiredLocation = null, float optimalAngle = 0, int?z = null)
        {
            var loc = GetNudgeLocation(el, desiredLocation, optimalAngle, z);

            if (loc != null)
            {
                if (el is IHaveMassBounds == false)
                {
                    el.MoveTo(loc.Left, loc.Top, z);
                }
                else
                {
                    var elBounds = el.EffectiveBounds();
                    var dx       = el.Left - elBounds.Left;
                    var dy       = el.Top - elBounds.Top;
                    el.MoveTo(loc.Left + dx, loc.Top + dy, z);
                }
                var ev = new NudgeEvent()
                {
                    Element = el, Success = true
                };
                OnNudge.Fire(ev);
                return(ev);
            }
            else
            {
                var ev = new NudgeEvent()
                {
                    Element = el, Success = false
                };
                OnNudge.Fire(ev);
                return(ev);
            }
        }
Пример #3
0
 public Seeker(SpacialElement seeker, SpacialElement seekee, SpeedTracker seekerSpeed, float accelleration) : base(seeker)
 {
     this.Seekee        = seekee;
     this.SeekerSpeed   = seekerSpeed;
     this.accelleration = accelleration;
     IsSeeking          = true;
     Governor.Rate      = TimeSpan.FromSeconds(.1);
     Seekee.Lifetime.OnDisposed(() => { this.Lifetime.Dispose(); });
 }
Пример #4
0
        public static void NudgeFree(this SpacialElement el)
        {
            var loc = GetNudgeLocation(el);

            if (loc != null)
            {
                el.MoveTo(loc.Left, loc.Top);
            }
        }
Пример #5
0
        public Roamer(SpacialElement roamer, Velocity roamerSpeed, float accelleration) : base(roamer)
        {
            this.RoamerSpeed   = roamerSpeed;
            this.accelleration = accelleration;
            Governor.Rate      = TimeSpan.FromSeconds(.1);

            if (IsRoaming)
            {
                currentForce = new Force(RoamerSpeed, accelleration, NextAngle());
            }
        }
Пример #6
0
 public static Velocity For(SpacialElement el)
 {
     if (el is IHaveVelocity)
     {
         return((el as IHaveVelocity).Velocity);
     }
     else
     {
         return(Time.CurrentTime.Functions.WhereAs <Velocity>().Where(v => v.Element == el).FirstOrDefault());
     }
 }
Пример #7
0
        private static void AssertNoOverlaps(Func <SpacialElement, bool> filter, SpacialElement el, Action <OverlapInfo> handler)
        {
            if (filter(el) == false)
            {
                return;
            }

            var overlappingObstacle = GetObstacleIfMovedTo(el);

            if (overlappingObstacle != null)
            {
                handler(new OverlapInfo()
                {
                    DetectingElement = el, OverlappingElement = overlappingObstacle
                });
            }
        }
Пример #8
0
        public static async Task <bool> TryControlVelocity(this SpacialElement el, Func <Velocity, Task> takeoverAction, ILifetimeManager lt)
        {
            Velocity tempV = new Velocity(el);

            lt.OnDisposed(tempV.Lifetime.Dispose);
            if (el is IHaveVelocity)
            {
                if ((el as IHaveVelocity).Velocity.MovementTakeover != null)
                {
                    return(false);
                }
                await(el as IHaveVelocity).Velocity.Takeover(() => takeoverAction(tempV));
            }
            else
            {
                await takeoverAction(tempV);
            }
            return(true);
        }
Пример #9
0
        public Roamer(SpacialElement roamer, Velocity roamerSpeed, float accelleration) : base(roamer)
        {
            this.RoamerSpeed   = roamerSpeed;
            this.accelleration = accelleration;


            if (IsRoaming)
            {
                currentForce = new Force(RoamerSpeed, accelleration, NextAngle());
            }

            this.Added.SubscribeOnce(async() =>
            {
                while (this.Lifetime.IsExpired == false)
                {
                    Evaluate();
                    await Time.CurrentTime.DelayAsync(100);
                }
            });
        }
Пример #10
0
        public static HitPrediction PredictHit(SpaceTime r, SpacialElement Target, List <Type> hitDetectionTypes, List <SpacialElement> hitDetectionExclusions, float dx, float dy)
        {
            if (Math.Abs(dx) <= 1 && Math.Abs(dy) <= 1)
            {
                return(PredictHitInternal(r, Target, hitDetectionTypes, hitDetectionExclusions, dx, dy));
            }

            HitPrediction latestResult = null;

            for (var i = 1; i <= 10; i++)
            {
                var dxP = Approach(0, dx, dx / 10 * i);
                var dyP = Approach(0, dy, dy / 10 * i);
                latestResult = PredictHitInternal(r, Target, hitDetectionTypes, hitDetectionExclusions, dxP, dyP);
                if (latestResult.Type != HitType.None)
                {
                    return(latestResult);
                }
            }

            return(latestResult);
        }
Пример #11
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);
        }
Пример #12
0
        public static async Task <bool> TryControlVelocity(this SpacialElement el, Func <Velocity, Task> takeoverAction, ILifetimeManager lt)
        {
            Velocity tempV = new Velocity(el);

            lt.OnDisposed(tempV.Lifetime.Dispose);
            if (el is IHaveVelocity)
            {
                if ((el as IHaveVelocity).Velocity.MovementTakeover != null)
                {
                    return(false);
                }
                tempV.HitDetectionDynamicExclusions = (el as IHaveVelocity).Velocity.HitDetectionDynamicExclusions;
                tempV.HitDetectionExclusions.AddRange((el as IHaveVelocity).Velocity.HitDetectionExclusions);
                tempV.HitDetectionExclusionTypes.AddRange((el as IHaveVelocity).Velocity.HitDetectionExclusionTypes);
                await(el as IHaveVelocity).Velocity.Takeover(() => takeoverAction(tempV));
            }
            else
            {
                await takeoverAction(tempV);
            }
            return(true);
        }
Пример #13
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);
        }
Пример #14
0
        private void ConnectToElement(SpacialElement element)
        {
            added.Add(element);

            element.Lifetime.OnDisposed(() =>
            {
                removed.Add(element);
            });

            element.SizeOrPositionChanged.SubscribeForLifetime(() =>
            {
                if (Time.CurrentTime == null)
                {
                    throw new InvalidOperationException("Change did not occur on the time thread");
                }
                changedEvent.Fire(element);
                if (element.InternalSpacialState.Changed == false)
                {
                    changed.Add(element);
                    element.InternalSpacialState.Changed = true;
                }
            }, Lifetime.EarliestOf(this, element.Lifetime));
        }
Пример #15
0
        public SpacialElementRenderer Bind(SpacialElement t, SpaceTime spaceTime)
        {
            if (t.Renderer != null)
            {
                t.Renderer.Element = t;
                t.Renderer.OnBind();
                return(t.Renderer);
            }

            Type binding;

            if (Bindings.TryGetValue(t.GetType(), out binding) == false)
            {
                binding = typeof(SpacialElementRenderer);
            }

            SpacialElementRenderer ret = Activator.CreateInstance(binding) as SpacialElementRenderer;

            ret.Element   = t;
            ret.Spacetime = spaceTime;
            ret.OnBind();
            return(ret);
        }
Пример #16
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);
        }
Пример #17
0
        private static IRectangularF GetObstacleIfMovedTo(SpacialElement el, int?z = null)
        {
            var overlaps = el.GetObstacles(z).Where(e => e.EffectiveBounds().Touches(el)).ToArray();

            return(overlaps.FirstOrDefault());
        }
Пример #18
0
 public SpeedTracker(SpacialElement t) : base(t)
 {
     Bounciness     = .4f;
     ImpactFriction = .95f;
 }
Пример #19
0
 public Velocity(SpacialElement t) : base(t)
 {
     Time.CurrentTime.DoASAP("V", async() => await ExecuteAsync());
 }
Пример #20
0
 public Floater(SpacialElement t, SpeedTracker tracker, float maxFloat = 1) : base(t)
 {
     this.MaxFloat      = maxFloat;
     this.Governor.Rate = TimeSpan.FromSeconds(.03);
     this.tracker       = tracker;
 }
Пример #21
0
 public Velocity(SpacialElement t) : base(t)
 {
     Time.CurrentTime.Invoke(async() => await ExecuteAsync());
 }
Пример #22
0
 public SpeedTracker(SpacialElement t) : base(t)
 {
     HitDetectionTypes = new List <Type>();
     Bounciness        = .4f;
     ImpactFriction    = .95f;
 }
Пример #23
0
 public static bool HasLineOfSight(this SpacialElement from, IRectangularF to) => HasLineOfSight(from, to, from.GetObstacles());
Пример #24
0
 public Roamer(SpacialElement roamer, SpeedTracker roamerSpeed, float accelleration) : base(roamer)
 {
     this.RoamerSpeed   = roamerSpeed;
     this.accelleration = accelleration;
     Governor.Rate      = TimeSpan.FromSeconds(.1);
 }
Пример #25
0
        public static HitPrediction PredictHit(SpaceTime r, SpacialElement Target, List <Type> hitDetectionTypes, float dx, float dy)
        {
            HitPrediction prediction = new HitPrediction();

            if (dx == 0 && dy == 0)
            {
                prediction.Direction = Direction.None;
                prediction.Type      = HitType.None;
                return(prediction);
            }

            if (dy > 0 && Target.Bottom() + dy >= r.Height)
            {
                prediction.Direction            = Direction.Down;
                prediction.Type                 = HitType.Boundary;
                prediction.BoundsOfItemBeingHit = Rectangular.Create(Target.Left + dx, r.Bounds.Height + dy, 1, 1);
                return(prediction);
            }
            else if (dx < 0 && Target.Left + dx <= 0)
            {
                prediction.Direction            = Direction.Left;
                prediction.Type                 = HitType.Boundary;
                prediction.BoundsOfItemBeingHit = Rectangular.Create(-dx, Target.Top + dy, 1, 1);
                return(prediction);
            }
            else if (dy < 0 && Target.Top + dy <= 0)
            {
                prediction.Direction            = Direction.Up;
                prediction.Type                 = HitType.Boundary;
                prediction.BoundsOfItemBeingHit = Rectangular.Create(Target.Left + dx, -dy, 1, 1);
                return(prediction);
            }
            else if (dx > 0 && Target.Right() + dx >= r.Width)
            {
                prediction.Direction            = Direction.Right;
                prediction.Type                 = HitType.Boundary;
                prediction.BoundsOfItemBeingHit = Rectangular.Create(r.Width + dx, Target.Top + dy, 1, 1);
                return(prediction);
            }

            var testArea = Rectangular.Create(Target.Left + dx, Target.Top + dy, Target.Width, Target.Height);

            var match = (from t in r.Elements
                         where
                         t.IsOneOfThese(hitDetectionTypes) &&
                         Target != t &&
                         testArea.NumberOfPixelsThatOverlap(t) > 0
                         select t).OrderBy(t => t.Center().CalculateDistanceTo(Target.Center()));


            if (match.Count() == 0)
            {
                prediction.Direction = Direction.None;
                prediction.Type      = HitType.None;
            }
            else
            {
                prediction.ElementHit           = match.First();
                prediction.Type                 = HitType.Element;
                prediction.Direction            = testArea.GetHitDirection(match.First().Bounds);
                prediction.BoundsOfItemBeingHit = prediction.ElementHit.Bounds;
            }

            return(prediction);
        }