/// <summary>The <c>_intersect</c> method tests whether the room passed as the second parameter /// intersects with any of the rooms in the <c>rooms</c> list.</summary> public bool _intersects(List <Rect2> rooms, Rect2 room) { var isIntersecting = false; foreach (Rect2 roomOther in rooms) { if (room.Intersects(roomOther)) { isIntersecting = true; break; } } return(isIntersecting); }
/// <summary> /// Moves the entity to the specified location with collision. /// </summary> /// <remarks> /// This always assumes that after moving entities by their MTVs they won't escape the NEARBY_BOUNDS, but /// if isLargeMovement is true it recalculates EntityNearbyIds from loc rather than reusing the existing /// one. /// </remarks> /// <param name="world">The world</param> /// <param name="entity">The entity to move</param> /// <param name="loc">The desired location of the entity</param> /// <param name="isLargeMovement">If the entity might intersect entities that aren't in its EntityNearbyIds</param> /// <returns>The entity after attempting to move it to loc</returns> public static Entity DoMoveEntity(MutatingWorld world, Entity entity, Vector2 loc, Stopwatch watch, bool isLargeMovement = false) { loc.X = Math.Min(Math.Max(loc.X, 0), world.Width - entity.Attributes.Bounds.AABB.Width); loc.Y = Math.Min(Math.Max(loc.Y, 0), world.Height - entity.Attributes.Bounds.AABB.Height); int entId = entity.ID; HashSet <int> ignoreIds = null; IEnumerable <int> potentialCollisionIds; if (isLargeMovement) { var potColIds = new ConcurrentQueue <int>(); Parallel.ForEach(world.Entities, (value, pls, index) => { if (value.Key != entId && Rect2.Intersects(value.Value.Attributes.Bounds.AABB, NEARBY_BOUNDS, value.Value.Location, loc, true)) { potColIds.Enqueue(value.Key); } }); potentialCollisionIds = potColIds; } else { potentialCollisionIds = entity.NearbyEntityIds; } watch.Start(); while (true) { int collidingId = -1; Tuple <Vector2, float> collidingMTV = null; foreach (var potentialCollidingEntityID in potentialCollisionIds) { var potentialCollidingEntity = world.Entities[potentialCollidingEntityID]; if (potentialCollidingEntity.ID != entId && (ignoreIds == null || !ignoreIds.Contains(potentialCollidingEntity.ID))) { if (!Rect2.Intersects(entity.Attributes.Bounds.AABB, potentialCollidingEntity.Attributes.Bounds.AABB, entity.Location, potentialCollidingEntity.Location, true)) { continue; } var mtv = Polygon2.IntersectMTV(entity.Attributes.Bounds, potentialCollidingEntity.Attributes.Bounds, loc, potentialCollidingEntity.Location); if (mtv != null) { collidingId = potentialCollidingEntity.ID; collidingMTV = mtv; break; } } } ; if (collidingMTV != null) { if (ignoreIds == null) { ignoreIds = new HashSet <int>(new[] { collidingId }); } else { ignoreIds.Add(collidingId); } loc += collidingMTV.Item1 * collidingMTV.Item2; } else { break; } } watch.Stop(); var elapsed = watch.ElapsedMilliseconds; if (elapsed > 2) { Console.WriteLine($"Took a long time to resolve collisions: {elapsed} ms"); } watch.Start(); var nearbyIds = new HashSet <int>(); var keys = new List <int>(world.Entities.Keys); foreach (var id in keys) { var e = world.Entities[id]; if (e.ID != entId && Rect2.Intersects(e.Attributes.Bounds.AABB, NEARBY_BOUNDS, e.Location, loc, true)) { nearbyIds.Add(e.ID); } } foreach (var oldNearby in entity.NearbyEntityIds) { if (!nearbyIds.Contains(oldNearby)) { Entity oldEnt; if (world.Entities.TryGetValue(oldNearby, out oldEnt)) { world.Entities[oldNearby] = new Entity(oldEnt, nearby: (Maybe <ImmutableHashSet <int> >)oldEnt.NearbyEntityIds.Remove(entId)); } } } foreach (var nearby in nearbyIds) { var ent = world.Entities[nearby]; if (!ent.NearbyEntityIds.Contains(entId)) { world.Entities[nearby] = new Entity(ent, nearby: (Maybe <ImmutableHashSet <int> >)ent.NearbyEntityIds.Add(entId)); } } watch.Stop(); elapsed = watch.ElapsedMilliseconds; if (elapsed > 3) { Console.WriteLine($"Took a long time to update nearby: {elapsed} ms"); } return(new Entity(entity, location: loc, nearby: (Maybe <ImmutableHashSet <int> >)nearbyIds.ToImmutableHashSet())); }
public void Apply(MutatingWorld world) { var watch = new Stopwatch(); watch.Start(); var spawnBounds = SpawnBounds; var team = Team; if (team == -1) { MutatingTeam teamObj = null; foreach (var teamkvp in world.Teams) { if (teamObj == null || teamkvp.Value.Members.Count < teamObj.Members.Count) { team = teamkvp.Key; teamObj = teamkvp.Value; } } world.Teams[team].LastSpawnTimeMS = world.Timestamp; spawnBounds = world.Teams[team].SpawnRect; } Vector2 spawnLoc; while (true) { spawnLoc = new Vector2( (float)(spawnBounds.Min.X + world.RandomGen.NextDouble() * spawnBounds.Width), (float)(spawnBounds.Min.Y + world.RandomGen.NextDouble() * spawnBounds.Height)); var alreadyCollidedIds = new HashSet <int>(); var done = true; while (true) { var inter = world.Entities.Select((e) => Tuple.Create(e, Polygon2.IntersectMTV(e.Value.Attributes.Bounds, Attributes.Bounds, e.Value.Location, spawnLoc))).FirstOrDefault((tup) => tup.Item2 != null); if (inter != null) { if (alreadyCollidedIds.Contains(inter.Item1.Key)) { break; } alreadyCollidedIds.Add(inter.Item1.Key); spawnLoc += inter.Item2.Item1 * (inter.Item2.Item2 * 1.1f); done = false; } else { break; } } if (done) { break; } } var entId = world.IDCounter++; var nearbyBounds = Logic.NEARBY_BOUNDS; var nearby = new HashSet <int>(); foreach (var kvp in world.Entities) { if (Rect2.Intersects(kvp.Value.Attributes.Bounds.AABB, nearbyBounds, kvp.Value.Location, spawnLoc, true)) { nearby.Add(kvp.Key); } } foreach (var id in nearby) { var e = world.Entities[id]; world.Entities[id] = new Entity(e, nearby: (Maybe <ImmutableHashSet <int> >)e.NearbyEntityIds.Add(entId)); } var ent = new Entity(entId, team, Name, Attributes, spawnLoc, Vector2.Zero, Attributes.MaxHealth, Attributes.MaxMana, null, ImmutableDictionary.Create <int, int>(), nearby.ToImmutableHashSet(), ImmutableList <IModifier> .Empty); world.Add(ent); world.FinishedCallbacks.Add(() => Callback?.Invoke(ent)); watch.Stop(); var elapsedMS = watch.ElapsedMilliseconds; if (elapsedMS > 2) { Console.WriteLine($"Took a long time to spawn new entity! ({elapsedMS} ms)"); } }