public void CalculateBounds() { if (connectedBody == null) { _bodyBounds = new Bounds(); return; } AABB aabb_full = new AABB(); bool combine = false; for (int i = 0; i < connectedBody.FixtureList.Count; i++) { for (int j = 0; j < connectedBody.FixtureList[i].Shape.ChildCount; j++) { AABB aabb; connectedBody.FixtureList[i].Shape.ComputeAABB(out aabb, ref connectedBody.Xf, j); if (!combine) { combine = true; aabb_full = aabb; } else { aabb_full.Combine(ref aabb); } } } _bodyBounds = Bounds.FromAABB(ref aabb_full, to2dMode, GetSize()); }
public static Rectangle GetAABB(EasyGameComponent component) { AABB overallAABB = new AABB(); component.Body.FixtureList.ForEach(delegate(Fixture fixture) { for (int i = 0; i < fixture.Shape.ChildCount; i++) { AABB currentAABB; Transform transform; fixture.Body.GetTransform(out transform); fixture.Shape.ComputeAABB(out currentAABB, ref transform, i); overallAABB.Combine(ref currentAABB); } }); int left = (int)overallAABB.UpperBound.X; int right = (int)overallAABB.LowerBound.X; int top = (int)overallAABB.UpperBound.Y; int bottom = (int)overallAABB.LowerBound.Y; Rectangle rectangle = new Rectangle(left, top, right - left, bottom - top); return rectangle; }
/// <summary> /// Creates terrain fixtures that are nearby physics entities and destroys those that are no longer in range of /// any entities. /// </summary> private void CreateAndDestroyTerrainFixtures() { Entity terrainEntity = this.EntityManager.GetFirstEntityWithComponent(typeof(TerrainComponent)); // Get the terrain components var cTerrain = (TerrainComponent)this.EntityManager.GetComponent(terrainEntity, typeof(TerrainComponent)); var cTerrainPhysics = (PhysicsComponent)this.EntityManager.GetComponent(terrainEntity, typeof(PhysicsComponent)); var cTerrainPosition = (PositionComponent)this.EntityManager.GetComponent(terrainEntity, typeof(PositionComponent)); var cTerrainScale = (ScaleComponent)this.EntityManager.GetComponent(terrainEntity, typeof(ScaleComponent)); // Build the list of terrain blocks that are in range of a physics entity var blocksInRange = new HashSet<Square>(); foreach (Entity physicsEntity in this.EntityManager.GetEntitiesWithComponent(typeof(PhysicsComponent))) { var cPhysics = (PhysicsComponent)this.EntityManager.GetComponent(physicsEntity, typeof(PhysicsComponent)); // Skip the body if it is static or has no fixtures if (cPhysics.Body.IsStatic || cPhysics.Body.FixtureList.Count == 0) { continue; } // Get the bounds of body in physics-world coordinates AABB bodyAABB = new AABB(); bool firstStep = true; foreach (Fixture fixture in cPhysics.Body.FixtureList) { AABB fixtureBounds; fixture.GetAABB(out fixtureBounds, 0); if (firstStep) { bodyAABB = fixtureBounds; firstStep = false; } else { bodyAABB.Combine(ref fixtureBounds); } } // Translate the body AABB with the body position bodyAABB.LowerBound += cPhysics.Body.Position; bodyAABB.UpperBound += cPhysics.Body.Position; // Add the body padding bodyAABB.LowerBound -= new Vector2(Const.BodyCollisionPadding); bodyAABB.UpperBound += new Vector2(Const.BodyCollisionPadding); // Get the distance of the top-left point of the body relative to the terrain's top-left position // Remember that the terrain quad tree goes top-left to bottom-right, so Y increases as the body is // further down var terrainRelativeDistance = new Vector2( bodyAABB.LowerBound.X - cTerrainPosition.Position.X, cTerrainPosition.Position.Y - bodyAABB.UpperBound.Y); // Scale the distance by the terrain scale factor (ie. if the terrain is x2 sized, the body's // relative distance should be halved) terrainRelativeDistance /= cTerrainScale.Scale; // Scale the length/width of the body by the terrain scale factor to get the size Vector2 bodySize = (bodyAABB.UpperBound - bodyAABB.LowerBound) / cTerrainScale.Scale; var bodyBounds = new Rectangle( (int)terrainRelativeDistance.X, (int)terrainRelativeDistance.Y, (int)(Math.Abs(bodySize.X) + 0.5), (int)(Math.Abs(bodySize.Y) + 0.5)); // Get the terrain blocks which intersect the body foreach (ClipQuadTree<TerrainData> block in cTerrain.Terrain.GetNodesIntersecting(bodyBounds)) { if (block.Data.State == TerrainState.Terrain) { blocksInRange.Add(block.Bounds); } } } // Determine which terrain fixtures which are no longer in range of any bodies var blocksToRemove = new List<KeyValuePair<Square, Fixture>>(); foreach (KeyValuePair<Square, Fixture> kvp in cTerrain.Fixtures) { if (!blocksInRange.Contains(kvp.Key)) { blocksToRemove.Add(kvp); } } // Remove terrain fixtures which are no longer in range of any bodies foreach (KeyValuePair<Square, Fixture> kvp in blocksToRemove) { cTerrainPhysics.Body.DestroyFixture(kvp.Value); cTerrain.Fixtures.Remove(kvp.Key); } // Add new terrain fixtures foreach (Square block in blocksInRange) { if (!cTerrain.Fixtures.ContainsKey(block)) { Vector2 blockPosition = new Vector2(block.X, -block.Y) * cTerrainScale.Scale; float blockSize = block.Length * cTerrainScale.Scale; float halfSize = blockSize / 2; // Create the fixture for this block var fixture = FixtureFactory.AttachRectangle( blockSize, blockSize, 1, new Vector2(blockPosition.X + halfSize, blockPosition.Y - halfSize), cTerrainPhysics.Body); // Add the fixture to the terrain's collection cTerrain.Fixtures.Add(block, fixture); } } }