/// <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)); } } }
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); //} } } }
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))); }
/// <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)); } } }
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); } }
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); } } } } } } }