/// <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);
    }
Example #2
0
        /// <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()));
        }
Example #3
0
        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)");
            }
        }