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 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); } }
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(); }); }
public static void NudgeFree(this SpacialElement el) { var loc = GetNudgeLocation(el); if (loc != null) { el.MoveTo(loc.Left, loc.Top); } }
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()); } }
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()); } }
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 }); } }
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); }
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); } }); }
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); }
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 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); }
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); }
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)); }
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); }
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); }
private static IRectangularF GetObstacleIfMovedTo(SpacialElement el, int?z = null) { var overlaps = el.GetObstacles(z).Where(e => e.EffectiveBounds().Touches(el)).ToArray(); return(overlaps.FirstOrDefault()); }
public SpeedTracker(SpacialElement t) : base(t) { Bounciness = .4f; ImpactFriction = .95f; }
public Velocity(SpacialElement t) : base(t) { Time.CurrentTime.DoASAP("V", async() => await ExecuteAsync()); }
public Floater(SpacialElement t, SpeedTracker tracker, float maxFloat = 1) : base(t) { this.MaxFloat = maxFloat; this.Governor.Rate = TimeSpan.FromSeconds(.03); this.tracker = tracker; }
public Velocity(SpacialElement t) : base(t) { Time.CurrentTime.Invoke(async() => await ExecuteAsync()); }
public SpeedTracker(SpacialElement t) : base(t) { HitDetectionTypes = new List <Type>(); Bounciness = .4f; ImpactFriction = .95f; }
public static bool HasLineOfSight(this SpacialElement from, IRectangularF to) => HasLineOfSight(from, to, from.GetObstacles());
public Roamer(SpacialElement roamer, SpeedTracker roamerSpeed, float accelleration) : base(roamer) { this.RoamerSpeed = roamerSpeed; this.accelleration = accelleration; Governor.Rate = TimeSpan.FromSeconds(.1); }
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); }