public Box2 GetHardAABB(PhysicsComponent body, TransformComponent?xform = null, FixturesComponent?fixtures = null) { if (!Resolve(body.Owner, ref xform, ref fixtures)) { throw new InvalidOperationException(); } var(worldPos, worldRot) = xform.GetWorldPositionRotation(); var transform = new Transform(worldPos, (float)worldRot.Theta); var bounds = new Box2(transform.Position, transform.Position); foreach (var fixture in fixtures.Fixtures.Values) { if (!fixture.Hard) { continue; } for (var i = 0; i < fixture.Shape.ChildCount; i++) { var boundy = fixture.Shape.ComputeAABB(transform, i); bounds = bounds.Union(boundy); } } return(bounds); }
/// <summary> /// Retrieves a shuttle for delivery. /// </summary> public void CallShuttle(StationCargoOrderDatabaseComponent orderDatabase) { if (!TryComp <CargoShuttleComponent>(orderDatabase.Shuttle, out var shuttle) || !TryComp <TransformComponent>(orderDatabase.Owner, out var xform)) { return; } // Already called / not available if (shuttle.NextCall == null || _timing.CurTime < shuttle.NextCall) { return; } shuttle.NextCall = null; // Find a valid free area nearby to spawn in on // TODO: Make this use hyperspace now. var center = new Vector2(); var minRadius = 0f; Box2?aabb = null; foreach (var grid in _mapManager.GetAllMapGrids(xform.MapID)) { aabb = aabb?.Union(grid.WorldAABB) ?? grid.WorldAABB; } if (aabb != null) { center = aabb.Value.Center; minRadius = MathF.Max(aabb.Value.Width, aabb.Value.Height); } var offset = 0f; if (TryComp <IMapGridComponent>(orderDatabase.Shuttle, out var shuttleGrid)) { var bounds = shuttleGrid.Grid.LocalAABB; offset = MathF.Max(bounds.Width, bounds.Height) / 2f; } Transform(shuttle.Owner).Coordinates = new EntityCoordinates(xform.ParentUid, center + _random.NextVector2(minRadius + offset, minRadius + CallOffset + offset)); DebugTools.Assert(!MetaData(shuttle.Owner).EntityPaused); AddCargoContents(shuttle, orderDatabase); UpdateOrders(orderDatabase); UpdateShuttleCargoConsoles(shuttle); _console.RefreshShuttleConsoles(); _sawmill.Info($"Retrieved cargo shuttle {ToPrettyString(shuttle.Owner)} from {ToPrettyString(orderDatabase.Owner)}"); }
public Box2 GetWorldAABB(PhysicsComponent body, TransformComponent xform, EntityQuery <TransformComponent> xforms, EntityQuery <FixturesComponent> fixtures) { var(worldPos, worldRot) = xform.GetWorldPositionRotation(xforms); var transform = new Transform(worldPos, (float)worldRot.Theta); var bounds = new Box2(transform.Position, transform.Position); foreach (var fixture in fixtures.GetComponent(body.Owner).Fixtures.Values) { for (var i = 0; i < fixture.Shape.ChildCount; i++) { var boundy = fixture.Shape.ComputeAABB(transform, i); bounds = bounds.Union(boundy); } } return(bounds); }
/// <summary> /// Expands the AABB for this grid when a new tile is added. If the tile is already inside the existing AABB, /// nothing happens. If it is outside, the AABB is expanded to fit the new tile. /// </summary> private void UpdateAABB() { LocalBounds = new Box2(); foreach (var chunk in _chunks.Values) { var chunkBounds = chunk.CalcLocalBounds(); if (chunkBounds.Size.Equals(Vector2i.Zero)) { continue; } if (LocalBounds.Size == Vector2.Zero) { var gridBounds = chunkBounds.Translated(chunk.Indices * chunk.ChunkSize); LocalBounds = gridBounds; } else { var gridBounds = chunkBounds.Translated(chunk.Indices * chunk.ChunkSize); LocalBounds = LocalBounds.Union(gridBounds); } } }
public override void Update(float frameTime) { base.Update(frameTime); if (!Started) { return; } if (_waveCounter <= 0) { Running = false; return; } _cooldown -= frameTime; if (_cooldown > 0f) { return; } _waveCounter--; _cooldown += (MaximumCooldown - MinimumCooldown) * _robustRandom.NextFloat() + MinimumCooldown; Box2?playableArea = null; var mapId = EntitySystem.Get <GameTicker>().DefaultMap; foreach (var grid in _mapManager.GetAllGrids()) { if (grid.ParentMapId != mapId || !_entityManager.TryGetComponent(grid.GridEntityId, out PhysicsComponent? gridBody)) { continue; } var aabb = gridBody.GetWorldAABB(); playableArea = playableArea?.Union(aabb) ?? aabb; } if (playableArea == null) { EndAfter = float.MinValue; return; } var minimumDistance = (playableArea.Value.TopRight - playableArea.Value.Center).Length + 50f; var maximumDistance = minimumDistance + 100f; var center = playableArea.Value.Center; for (var i = 0; i < MeteorsPerWave; i++) { var angle = new Angle(_robustRandom.NextFloat() * MathF.Tau); var offset = angle.RotateVec(new Vector2((maximumDistance - minimumDistance) * _robustRandom.NextFloat() + minimumDistance, 0)); var spawnPosition = new MapCoordinates(center + offset, mapId); var meteor = _entityManager.SpawnEntity("MeteorLarge", spawnPosition); var physics = _entityManager.GetComponent <PhysicsComponent>(meteor.Uid); physics.BodyStatus = BodyStatus.InAir; physics.LinearDamping = 0f; physics.AngularDamping = 0f; physics.ApplyLinearImpulse(-offset.Normalized * MeteorVelocity * physics.Mass); physics.ApplyAngularImpulse( // Get a random angular velocity. physics.Mass * ((MaxAngularVelocity - MinAngularVelocity) * _robustRandom.NextFloat() + MinAngularVelocity)); // TODO: God this disgusts me but projectile needs a refactor. meteor.GetComponent <ProjectileComponent>().TimeLeft = 120f; } }
private DockingComponent?GetDockable(PhysicsComponent body, TransformComponent dockingXform) { // Did you know Saltern is the most dockable station? // Assume the docking port itself (and its body) is valid if (!_mapManager.TryGetGrid(dockingXform.GridID, out var grid) || !HasComp <ShuttleComponent>(grid.GridEntityId)) { return(null); } var transform = body.GetTransform(); var dockingFixture = _fixtureSystem.GetFixtureOrNull(body, DockingFixture); if (dockingFixture == null) { DebugTools.Assert(false); Logger.ErrorS("docking", $"Found null fixture on {(body).Owner}"); return(null); } Box2?aabb = null; for (var i = 0; i < dockingFixture.Shape.ChildCount; i++) { aabb = aabb?.Union(dockingFixture.Shape.ComputeAABB(transform, i)) ?? dockingFixture.Shape.ComputeAABB(transform, i); } if (aabb == null) { return(null); } var enlargedAABB = aabb.Value.Enlarged(DockingRadius * 1.5f); // Get any docking ports in range on other grids. _mapManager.FindGridsIntersectingEnumerator(dockingXform.MapID, enlargedAABB, out var enumerator); while (enumerator.MoveNext(out var otherGrid)) { if (otherGrid.Index == dockingXform.GridID) { continue; } foreach (var ent in otherGrid.GetAnchoredEntities(enlargedAABB)) { if (!TryComp(ent, out DockingComponent? otherDocking) || !otherDocking.Enabled || !TryComp(ent, out PhysicsComponent? otherBody)) { continue; } var otherTransform = otherBody.GetTransform(); var otherDockingFixture = _fixtureSystem.GetFixtureOrNull(otherBody, DockingFixture); if (otherDockingFixture == null) { DebugTools.Assert(false); Logger.ErrorS("docking", $"Found null docking fixture on {ent}"); continue; } for (var i = 0; i < otherDockingFixture.Shape.ChildCount; i++) { var otherAABB = otherDockingFixture.Shape.ComputeAABB(otherTransform, i); if (!aabb.Value.Intersects(otherAABB)) { continue; } // TODO: Need CollisionManager's GJK for accurate bounds // Realistically I want 2 fixtures anyway but I'll deal with that later. return(otherDocking); } } } return(null); }