Пример #1
0
        /// <summary>Computes the cells the specified rectangle falls into.</summary>
        /// <param name="rectangle">The rectangle.</param>
        /// <returns>The cells the rectangle intersects with.</returns>
        private static IEnumerable <Tuple <ulong, TPoint> > ComputeCells(TRectangle rectangle)
        {
#if FALSE && FARMATH // Only works when automatically normalizing.
            var left   = rectangle.X.Segment;
            var right  = rectangle.Right.Segment;
            var top    = rectangle.Y.Segment;
            var bottom = rectangle.Bottom.Segment;
#elif FARMATH // TODO make sure this works
            var left   = rectangle.X.Segment + (int)(rectangle.X.Offset / FarValue.SegmentSizeHalf);
            var right  = rectangle.Right.Segment + (int)(rectangle.Right.Offset / FarValue.SegmentSizeHalf);
            var top    = rectangle.Y.Segment + (int)(rectangle.Y.Offset / FarValue.SegmentSizeHalf);
            var bottom = rectangle.Bottom.Segment + (int)(rectangle.Bottom.Offset / FarValue.SegmentSizeHalf);
#else
            var left   = (int)(rectangle.X / CellSize);
            var right  = (int)(rectangle.Right / CellSize);
            var top    = (int)(rectangle.Y / CellSize);
            var bottom = (int)(rectangle.Bottom / CellSize);
#endif

            TPoint center;
            for (var x = left; x <= right; x++)
            {
                center.X = -x * CellSize;
                for (var y = top; y <= bottom; y++)
                {
                    center.Y = -y * CellSize;
                    yield return(Tuple.Create(BitwiseMagic.Pack(x, y), center));
                }
            }
        }
Пример #2
0
        public void OnEndContact(EndContact message)
        {
            // Stop damage that is being applied because of this collision.
            var contact = message.Contact;

            // Get the two related entities.
            var entityA = Math.Min(contact.FixtureA.Entity, contact.FixtureB.Entity);
            var entityB = Math.Max(contact.FixtureB.Entity, contact.FixtureB.Entity);

            // See if we're tracking such a collision.
            var key = BitwiseMagic.Pack(entityA, entityB);
            ActiveCollisionInfo active;

            if (_activeCollisions.TryGetValue(key, out active))
            {
                // One less fixture contact.
                --active.Count;
                if (active.Count == 0)
                {
                    // That was the last one, stop tracking this and remove any "during contact" effects.
                    _activeCollisions.Remove(key);

                    // TODO figure out a nice way to let contact based debuffs know they can stop (radiation, ...)
                    //int effectId;
                    //if (_collisions.TryGetValue(BitwiseMagic.Pack(damagee, damager), out effectId))
                    //{
                    //    Manager.RemoveComponent(effectId);
                    //}
                }
            }
        }
Пример #3
0
        public static ulong GetSubCellIdFromCoordinates(FarPosition position)
        {
            const float segmentFactor = (float)FarValue.SegmentSize / (float)SubCellSize;
            const float offsetFactor  = 1f / (float)FarValue.SegmentSize * segmentFactor; // = 1f / (float) SubCellSize

            return(BitwiseMagic.Pack(
                       (int)Math.Floor(position.X.Segment * segmentFactor + position.X.Offset * offsetFactor),
                       (int)Math.Floor(position.Y.Segment * segmentFactor + position.Y.Offset * offsetFactor)));
        }
Пример #4
0
 /// <summary>
 ///     Adds the combined coordinates for all neighboring cells and the specified cell itself to the specified set of
 ///     cells.
 /// </summary>
 /// <param name="x">The x coordinate of the main cell.</param>
 /// <param name="y">The y coordinate of the main cell.</param>
 /// <param name="cells">The set of cells to add to.</param>
 private static void AddCellAndNeighbors(int x, int y, ISet <ulong> cells)
 {
     for (var ny = y - 1; ny <= y + 1; ny++)
     {
         for (var nx = x - 1; nx <= x + 1; nx++)
         {
             cells.Add(BitwiseMagic.Pack(nx, ny));
         }
     }
 }
Пример #5
0
        public void OnBeginContact(BeginContact message)
        {
            // We only get one message for a collision pair, so we handle it for both parties.
            var contact = message.Contact;

            // Get the two involved entities. We only handle one collision between
            // two bodies per tick, to avoid damage being applied multiple times.
            var entityA = Math.Min(contact.FixtureA.Entity, contact.FixtureB.Entity);
            var entityB = Math.Max(contact.FixtureA.Entity, contact.FixtureB.Entity);

            // See if either one does some damage and/or should be removed.
            var damageA = (CollisionDamage)Manager.GetComponent(entityA, CollisionDamage.TypeId);
            var damageB = (CollisionDamage)Manager.GetComponent(entityB, CollisionDamage.TypeId);

            var healthA = (Health)Manager.GetComponent(entityA, Health.TypeId);
            var healthB = (Health)Manager.GetComponent(entityB, Health.TypeId);

            // See if the hit entity should be removed on collision.
            var persistent = true;

            if (damageA != null && damageA.RemoveOnCollision)
            {
                // Entity gets removed, so forget about handling the collision physically.
                ((DeathSystem)Manager.GetSystem(DeathSystem.TypeId)).MarkForRemoval(entityA);
                contact.Disable();
                persistent = false;
            }
            if (damageB != null && damageB.RemoveOnCollision)
            {
                // Entity gets removed, so forget about handling the collision physically.
                ((DeathSystem)Manager.GetSystem(DeathSystem.TypeId)).MarkForRemoval(entityB);
                contact.Disable();
                persistent = false;
            }

            // Ignore contacts where no damage is involved at all.
            if ((damageA == null || healthB == null) &&
                (damageB == null || healthA == null))
            {
                return;
            }

            // See if we already know something about this collision.
            var key = BitwiseMagic.Pack(entityA, entityB);
            NewCollisionInfo info;

            if (!_newCollisions.TryGetValue(key, out info))
            {
                info = new NewCollisionInfo();
                _newCollisions.Add(key, info);
            }

            // Track the number of persistent contacts. This is necessary for damage "fields",
            // such as radiation in a certain area.
            if (persistent)
            {
                ++info.Count;
            }

            // See if the shield was hit.
            var shielded = false;
            var shieldA  = Manager.GetComponent(entityA, ShieldEnergyStatusEffect.TypeId) as ShieldEnergyStatusEffect;

            if (shieldA != null && (contact.FixtureA.Id == shieldA.Fixture || contact.FixtureB.Id == shieldA.Fixture))
            {
                info.IsShieldA = true;
                shielded       = true;
            }
            var shieldB = Manager.GetComponent(entityB, ShieldEnergyStatusEffect.TypeId) as ShieldEnergyStatusEffect;

            if (shieldB != null && (contact.FixtureA.Id == shieldB.Fixture || contact.FixtureA.Id == shieldB.Fixture))
            {
                info.IsShieldB = true;
                shielded       = true;
            }

            // For at least one of the involved entities a shield was hit, so get the normal.
            // Note that this can potentially lead to 'wrong' results, if an entity is hit by
            // multiple fixtures in the same frame. This is a problematic case, logically speaking:
            // what to do if this happens?
            if (shielded)
            {
                IList <FarPosition> points;
                contact.ComputeWorldManifold(out info.Normal, out points);
            }
        }
Пример #6
0
        private void PopulateCell(CellStateChanged message, IUniformRandom random)
        {
            // Check if we have a changed cell info.
            if (!_cellInfo.ContainsKey(message.Id))
            {
                // No, generate the default one. Get an independent
                // randomizer to avoid different results in other
                // sampling operations from when we have an existing
                // cell info.
                var hasher = new Hasher();
                hasher.Write(message.Id).Write(WorldSeed);
                var independentRandom = new MersenneTwister(hasher.Value);

                // Figure out which faction should own this cell.
                Factions faction;
                switch (independentRandom.NextInt32(3))
                {
                case 0:
                    faction = Factions.NPCFactionA;
                    break;

                case 1:
                    faction = Factions.NPCFactionB;
                    break;

                default:
                    faction = Factions.NPCFactionC;
                    break;
                }

                // Figure out our tech level.
                // TODO make dependent on distance to center / start system.
                var techLevel = independentRandom.NextInt32(3);

                // Create the cell and push it.
                _cellInfo.Add(message.Id, new CellInfo(faction, techLevel));
            }

            // Get center of our cell.
            const int cellSize = CellSystem.CellSize;
            var       center   = new FarPosition(
                cellSize * message.X + (cellSize >> 1),
                cellSize * message.Y + (cellSize >> 1));

            // Check if it's the start system or not.
            if (message.X == 0 && message.Y == 0)
            {
                // It is, use a predefined number of planets and moons,
                // and make sure it's a solar system.
                FactoryLibrary.SampleSunSystem(Manager, "solar_system", center, random);
            }
            else
            {
                // It isn't, randomize.
                FactoryLibrary.SampleSunSystem(Manager, "sunsystem_1", center, random);
            }

            // Find nearby active cells and the stations in them, mark
            // them as possible targets for all station sin this cell,
            // and let them know about our existence, as well.
            var cellSystem = (CellSystem)Manager.GetSystem(CellSystem.TypeId);
            var stations   = _cellInfo[message.Id].Stations;

            for (var ny = message.Y - 1; ny <= message.Y + 1; ny++)
            {
                for (var nx = message.X - 1; nx <= message.X + 1; nx++)
                {
                    // Don't fly to cells that are diagonal to
                    // ourselves, which we do by checking if the
                    // sum of the coordinates is uneven.
                    // This becomes more obvious when considering this:
                    // +-+-+-+-+
                    // |0|1|0|1|
                    // +-+-+-+-+
                    // |1|0|1|0|
                    // +-+-+-+-+
                    // |0|1|0|1|
                    // +-+-+-+-+
                    // |1|0|1|0|
                    // +-+-+-+-+
                    // Where 0 means the sum of the own coordinate is
                    // even, 1 means it is odd. Then we can see that
                    // the sum of diagonal pairs of cells is always
                    // even, and the one of straight neighbors is
                    // always odd.
                    if (((message.X + message.Y + ny + nx) & 1) == 0)
                    {
                        // Get the id, only mark the station if we have
                        // info on it and it's an enemy cell.
                        var id = BitwiseMagic.Pack(nx, ny);
                        if (cellSystem.IsCellActive(id) &&
                            _cellInfo.ContainsKey(id) &&
                            (_cellInfo[id].Faction.IsAlliedTo(_cellInfo[message.Id].Faction)))
                        {
                            // Tell the other stations.
                            foreach (var stationId in _cellInfo[id].Stations)
                            {
                                var spawn = ((ShipSpawner)Manager.GetComponent(stationId, ShipSpawner.TypeId));
                                foreach (var otherStationId in stations)
                                {
                                    spawn.Targets.Add(otherStationId);
                                }
                            }
                            // Tell our own stations.
                            foreach (var stationId in stations)
                            {
                                var spawner = ((ShipSpawner)Manager.GetComponent(stationId, ShipSpawner.TypeId));
                                foreach (var otherStationId in _cellInfo[id].Stations)
                                {
                                    spawner.Targets.Add(otherStationId);
                                }
                            }
                        }
                    }
                }
            }
        }