public void OnClicked(int X, int Y) { Viewport viewPort = new Viewport(RenderTarget.Bounds); Vector3 forward = (World.Renderer.Camera.Target - World.Renderer.Camera.Position); forward.Normalize(); Vector3 pos = viewPort.Unproject(new Vector3(X, Y, 0), Camera.ProjectionMatrix, Camera.ViewMatrix, Matrix.Identity); Vector3 target = new Vector3(pos.X, World.Renderer.Camera.Position.Y, pos.Z); var height = VoxelHelpers.FindFirstVoxelBelow(new VoxelHandle( World.ChunkManager, GlobalVoxelCoordinate.FromVector3(target))) .Coordinate.Y + 1; target.Y = Math.Max(height + 15, target.Y); target = MathFunctions.Clamp(target, World.ChunkManager.Bounds); World.Renderer.Camera.SetZoomTarget(target); }
public static BalloonPortVoxelSets GenerateBalloonPort(ChunkManager chunkManager, float x, float z, int size, ChunkGeneratorSettings Settings) { var centerCoordinate = GlobalVoxelCoordinate.FromVector3(new Vector3(x, (Settings.WorldSizeInChunks.Y * VoxelConstants.ChunkSizeY) - 1, z)); var averageHeight = (int)GetAverageHeight(centerCoordinate.X - size, centerCoordinate.Y - size, size * 2 + 1, size * 2 + 1, Settings); // Next, create the balloon port by deciding which voxels to fill. var balloonPortDesignations = new List <VoxelHandle>(); for (int dx = -size; dx <= size; dx++) { for (int dz = -size; dz <= size; dz++) { var worldPos = new Vector3(centerCoordinate.X + dx, centerCoordinate.Y, centerCoordinate.Z + dz); var baseVoxel = VoxelHelpers.FindFirstVoxelBelow(chunkManager.CreateVoxelHandle(GlobalVoxelCoordinate.FromVector3(worldPos))); if (!baseVoxel.IsValid) { continue; } var h = baseVoxel.Coordinate.Y + 1; for (int y = averageHeight; y < h && y < chunkManager.World.WorldSizeInVoxels.Y; y++) { var v = chunkManager.CreateVoxelHandle(new GlobalVoxelCoordinate(baseVoxel.Coordinate.X, y, baseVoxel.Coordinate.Z)); v.RawSetType(Library.EmptyVoxelType); v.RawSetIsExplored(); v.QuickSetLiquid(LiquidType.None, 0); } if (averageHeight < h) { h = averageHeight; } bool isPosX = (dx == size && dz == 0); bool isPosZ = (dz == size & dx == 0); bool isNegX = (dx == -size && dz == 0); bool isNegZ = (dz == -size && dz == 0); bool isSide = (isPosX || isNegX || isPosZ || isNegZ); Vector3 offset = Vector3.Zero; if (isSide) { if (isPosX) { offset = Vector3.UnitX; } else if (isPosZ) { offset = Vector3.UnitZ; } else if (isNegX) { offset = -Vector3.UnitX; } else if (isNegZ) { offset = -Vector3.UnitZ; } } // Fill from the top height down to the bottom. for (int y = Math.Max(0, h - 1); y < averageHeight && y < chunkManager.World.WorldSizeInVoxels.Y; y++) { var v = chunkManager.CreateVoxelHandle(new GlobalVoxelCoordinate(baseVoxel.Coordinate.X, y, baseVoxel.Coordinate.Z)); if (!v.IsValid) { throw new InvalidProgramException("Voxel was invalid while creating a new game's initial zones. This should not happen."); } v.RawSetType(Library.GetVoxelType("Scaffold")); v.IsPlayerBuilt = true; v.QuickSetLiquid(LiquidType.None, 0); v.Sunlight = false; if (y == averageHeight - 1) { v.RawSetIsExplored(); balloonPortDesignations.Add(v); } if (isSide) { var ladderPos = new Vector3(worldPos.X, y, worldPos.Z) + offset + Vector3.One * 0.5f; var ladderVox = chunkManager.CreateVoxelHandle(GlobalVoxelCoordinate.FromVector3(ladderPos)); if (ladderVox.IsValid && ladderVox.IsEmpty) { var ladder = EntityFactory.CreateEntity <Ladder>("Ladder", ladderPos); Settings.World.PlayerFaction.OwnedObjects.Add(ladder); ladder.Tags.Add("Moveable"); ladder.Tags.Add("Deconstructable"); } } } CastSunlightColumn(baseVoxel.Coordinate.X, baseVoxel.Coordinate.Z, Settings); } } return(new BalloonPortVoxelSets { StockpileVoxels = balloonPortDesignations, }); }
override public void Render(DwarfTime gameTime, ChunkManager chunks, Camera camera, SpriteBatch spriteBatch, GraphicsDevice graphicsDevice, Shader effect, bool renderingForWater) { base.Render(gameTime, chunks, camera, spriteBatch, graphicsDevice, effect, renderingForWater); if (Debugger.Switches.DrawRailNetwork) { //Drawer3D.DrawBox(GetContainingVoxel().GetBoundingBox(), Color.White, 0.01f, true); //Drawer3D.DrawLine(GetContainingVoxel().GetBoundingBox().Center(), GlobalTransform.Translation, Color.White, 0.01f); var transform = Matrix.CreateRotationY((float)Math.PI * 0.5f * (float)Piece.Orientation) * GlobalTransform; if (Library.GetRailPiece(Piece.RailPiece).HasValue(out var piece)) { foreach (var spline in piece.SplinePoints) { for (var i = 1; i < spline.Count; ++i) { Drawer3D.DrawLine(Vector3.Transform(spline[i - 1], transform), Vector3.Transform(spline[i], transform), Color.Purple, 0.1f); } } foreach (var connection in piece.EnumerateConnections()) { Drawer3D.DrawLine(Vector3.Transform(connection.Item1, transform) + new Vector3(0.0f, 0.2f, 0.0f), Vector3.Transform(connection.Item2, transform) + new Vector3(0.0f, 0.2f, 0.0f), Color.Brown, 0.1f); } //foreach (var neighborConnection in NeighborRails) //{ // var neighbor = Manager.FindComponent(neighborConnection.NeighborID); // if (neighbor == null) // Drawer3D.DrawLine(Position, Position + Vector3.UnitY, Color.CornflowerBlue, 0.1f); // else // Drawer3D.DrawLine(Position + new Vector3(0.0f, 0.5f, 0.0f), (neighbor as Body).Position + new Vector3(0.0f, 0.5f, 0.0f), Color.Teal, 0.1f); //} } } if (!IsVisible) { return; } if (Primitive == null) { var bounds = Vector4.Zero; var uvs = Sheet.GenerateTileUVs(Frame, out bounds); if (Library.GetRailPiece(Piece.RailPiece).HasValue(out var rawPiece)) { var transform = Matrix.CreateRotationY((float)Math.PI * 0.5f * (float)Piece.Orientation); var realShape = 0; if (rawPiece.AutoSlope) { var transformedConnections = GetTransformedConnections(); var matchingNeighbor1 = NeighborRails.FirstOrDefault(n => (n.Position - transformedConnections[0].Item1 - new Vector3(0.0f, 1.0f, 0.0f)).LengthSquared() < 0.001f); var matchingNeighbor2 = NeighborRails.FirstOrDefault(n => (n.Position - transformedConnections[1].Item1 - new Vector3(0.0f, 1.0f, 0.0f)).LengthSquared() < 0.001f); if (matchingNeighbor1 != null && matchingNeighbor2 != null) { realShape = 3; } else if (matchingNeighbor1 != null) { realShape = 1; } else if (matchingNeighbor2 != null) { realShape = 2; } } Primitive = new RawPrimitive(); Primitive.AddVertex(new ExtendedVertex(Vector3.Transform(new Vector3(-0.5f, VertexHeightOffsets[realShape, 0], 0.5f), transform), Color.White, Color.White, uvs[0], bounds)); Primitive.AddVertex(new ExtendedVertex(Vector3.Transform(new Vector3(0.5f, VertexHeightOffsets[realShape, 1], 0.5f), transform), Color.White, Color.White, uvs[1], bounds)); Primitive.AddVertex(new ExtendedVertex(Vector3.Transform(new Vector3(0.5f, VertexHeightOffsets[realShape, 2], -0.5f), transform), Color.White, Color.White, uvs[2], bounds)); Primitive.AddVertex(new ExtendedVertex(Vector3.Transform(new Vector3(-0.5f, VertexHeightOffsets[realShape, 3], -0.5f), transform), Color.White, Color.White, uvs[3], bounds)); Primitive.AddIndicies(new short[] { 0, 1, 3, 1, 2, 3 }); var sideBounds = Vector4.Zero; Vector2[] sideUvs = null; sideUvs = Sheet.GenerateTileUVs(new Point(3, 4), out sideBounds); AddScaffoldGeometry(transform, sideBounds, sideUvs, -1.0f, false); if (realShape == 3) { AddScaffoldGeometry(transform, sideBounds, sideUvs, 0.0f, false); } else if (realShape == 1) { sideUvs = Sheet.GenerateTileUVs(new Point(0, 4), out sideBounds); AddScaffoldGeometry(transform, sideBounds, sideUvs, 0.0f, true); } else if (realShape == 2) { sideUvs = Sheet.GenerateTileUVs(new Point(0, 4), out sideBounds); AddScaffoldGeometry(transform, sideBounds, sideUvs, 0.0f, false); } // Todo: Make these static and avoid recalculating them constantly. var bumperBackBounds = Vector4.Zero; var bumperBackUvs = Sheet.GenerateTileUVs(new Point(0, 5), out bumperBackBounds); var bumperFrontBounds = Vector4.Zero; var bumperFrontUvs = Sheet.GenerateTileUVs(new Point(1, 5), out bumperFrontBounds); var bumperSideBounds = Vector4.Zero; var bumperSideUvs = Sheet.GenerateTileUVs(new Point(2, 5), out bumperSideBounds); foreach (var connection in GetTransformedConnections()) { var matchingNeighbor = NeighborRails.FirstOrDefault(n => (n.Position - connection.Item1).LengthSquared() < 0.001f); if (matchingNeighbor == null && rawPiece.AutoSlope) { matchingNeighbor = NeighborRails.FirstOrDefault(n => (n.Position - connection.Item1 - new Vector3(0.0f, 1.0f, 0.0f)).LengthSquared() < 0.001f); } if (matchingNeighbor == null) { var bumperOffset = connection.Item1 - GlobalTransform.Translation; var bumperGap = Vector3.Normalize(bumperOffset) * 0.1f; var bumperAngle = AngleBetweenVectors(new Vector2(bumperOffset.X, bumperOffset.Z), new Vector2(0, 0.5f)); var xDiag = bumperOffset.X <-0.001f || bumperOffset.X> 0.001f; var zDiag = bumperOffset.Z <-0.001f || bumperOffset.Z> 0.001f; if (xDiag && zDiag) { var y = bumperOffset.Y; bumperOffset *= sqrt2; bumperOffset.Y = y; var endBounds = Vector4.Zero; var endUvs = Sheet.GenerateTileUVs(new Point(6, 2), out endBounds); Primitive.AddQuad( Matrix.CreateRotationY((float)Math.PI * 1.25f) * Matrix.CreateRotationY(bumperAngle) // This offset would not be correct if diagonals could slope. * Matrix.CreateTranslation(new Vector3(Sign(bumperOffset.X), 0.0f, Sign(bumperOffset.Z))), Color.White, Color.White, endUvs, endBounds); } Primitive.AddQuad( Matrix.CreateRotationX(-(float)Math.PI * 0.5f) * Matrix.CreateTranslation(0.0f, 0.3f, -0.2f) * Matrix.CreateRotationY(bumperAngle) * Matrix.CreateTranslation(bumperOffset + bumperGap), Color.White, Color.White, bumperBackUvs, bumperBackBounds); Primitive.AddQuad( Matrix.CreateRotationX(-(float)Math.PI * 0.5f) * Matrix.CreateTranslation(0.0f, 0.3f, -0.2f) * Matrix.CreateRotationY(bumperAngle) * Matrix.CreateTranslation(bumperOffset), Color.White, Color.White, bumperFrontUvs, bumperFrontBounds); if (VoxelHelpers.FindFirstVoxelBelow(GetContainingVoxel()).RampType == RampType.None) { Primitive.AddQuad( Matrix.CreateRotationX(-(float)Math.PI * 0.5f) * Matrix.CreateRotationY(-(float)Math.PI * 0.5f) * Matrix.CreateTranslation(0.3f, 0.3f, 0.18f) * Matrix.CreateRotationY(bumperAngle) * Matrix.CreateTranslation(bumperOffset), Color.White, Color.White, bumperSideUvs, bumperSideBounds); Primitive.AddQuad( Matrix.CreateRotationX(-(float)Math.PI * 0.5f) * Matrix.CreateRotationY(-(float)Math.PI * 0.5f) * Matrix.CreateTranslation(-0.3f, 0.3f, 0.18f) * Matrix.CreateRotationY(bumperAngle) * Matrix.CreateTranslation(bumperOffset), Color.White, Color.White, bumperSideUvs, bumperSideBounds); } } } } } // Everything that draws should set it's tint, making this pointless. var under = new VoxelHandle(chunks, GlobalVoxelCoordinate.FromVector3(Position)); if (under.IsValid) { Color color = new Color(under.Sunlight ? 255 : 0, 255, 0); LightRamp = color; } else { LightRamp = new Color(200, 255, 0); } Color origTint = effect.VertexColorTint; if (!Active) { DoStipple(effect); } effect.VertexColorTint = VertexColor; effect.LightRamp = LightRamp; effect.World = GlobalTransform; effect.MainTexture = Sheet.GetTexture(); effect.EnableWind = false; foreach (EffectPass pass in effect.CurrentTechnique.Passes) { pass.Apply(); Primitive.Render(graphicsDevice); } effect.VertexColorTint = origTint; if (!Active) { EndDraw(effect); } }
public static void GenerateRuin(VoxelChunk Chunk, ChunkGeneratorSettings Settings) { // Todo: Support ruins deep underground - empty out their interiors. LoadRuinTemplates(); var noiseVector = Chunk.Origin.ToVector3() * Settings.CaveNoiseScale; var ruinsNoise = Settings.CaveNoise.GetValue(noiseVector.X, noiseVector.Y, noiseVector.Z); if (Math.Abs(ruinsNoise) > GameSettings.Current.GenerationRuinsRate) { return; } var avgHeight = GetAverageHeight(Chunk.Origin.X, Chunk.Origin.Z, 16, 16, Settings); var ruinWallType = Library.GetVoxelType("Cobble"); // Todo: Should make this data so this doesn't break if tile names change? var ruinFloorType = Library.GetVoxelType("Blue Tile"); if (Settings.Overworld.Map.GetBiomeAt(Chunk.Origin.ToVector3(), Settings.Overworld.InstanceSettings.Origin).HasValue(out var biome)) { ruinWallType = Library.GetVoxelType(biome.RuinWallType); ruinFloorType = Library.GetVoxelType(biome.RuinFloorType); } if (!ruinWallType.HasValue() || !ruinFloorType.HasValue()) { return; } int wallHeight = MathFunctions.RandInt(2, 6); var template = RuinTemplates[MathFunctions.RandInt(0, RuinTemplates.Count)]; var rotations = MathFunctions.RandInt(0, 3); for (var i = 0; i < rotations; ++i) { template = TextureTool.RotatedCopy(template); } for (int dx = 0; dx < 16; dx++) { for (int dz = 0; dz < 16; dz++) { var worldPos = new Vector3(Chunk.Origin.X + dx, avgHeight, Chunk.Origin.Z + dz); var baseVoxel = Settings.World.ChunkManager.CreateVoxelHandle(GlobalVoxelCoordinate.FromVector3(worldPos)); var underVoxel = VoxelHelpers.FindFirstVoxelBelow(Settings.World.ChunkManager.CreateVoxelHandle(GlobalVoxelCoordinate.FromVector3(worldPos))); var decay = Settings.NoiseGenerator.Generate(worldPos.X * 0.05f, worldPos.Y * 0.05f, worldPos.Z * 0.05f); if (decay > 0.7f) { continue; } if (!baseVoxel.IsValid) { continue; } if (baseVoxel.Coordinate.Y == (Settings.WorldSizeInChunks.Y * VoxelConstants.ChunkSizeY) - 1) { continue; } if (!underVoxel.IsValid) { continue; } var templateColor = template.Data[template.Index(dx, dz)]; if (templateColor == new Color(0, 0, 255, 255)) // Border { continue; } else if (templateColor == new Color(0, 0, 0, 255)) // Space { continue; } else if (templateColor == new Color(255, 0, 0, 255)) // Wall { baseVoxel.RawSetType(ruinWallType); FillBelowRuins(Settings, ruinWallType, baseVoxel, underVoxel); FillRuinColumn(Settings, ruinWallType, 1, wallHeight, baseVoxel, decay); } else if (templateColor == new Color(128, 128, 0, 255)) // Door { baseVoxel.RawSetType(ruinWallType); FillBelowRuins(Settings, ruinWallType, baseVoxel, underVoxel); FillRuinColumn(Settings, ruinWallType, 3, wallHeight, baseVoxel, decay); } else if (templateColor == new Color(128, 0, 0, 255)) // Floor { FillBelowRuins(Settings, ruinWallType, baseVoxel, underVoxel); baseVoxel.RawSetType(ruinFloorType); } } } }
public static void GenerateRuin(VoxelChunk Chunk, ChunkGeneratorSettings Settings) { var noiseVector = Chunk.Origin.ToVector3() * Settings.CaveNoiseScale; var ruinsNoise = Settings.CaveNoise.GetValue(noiseVector.X, noiseVector.Y, noiseVector.Z); if (Math.Abs(ruinsNoise) > GameSettings.Default.GenerationRuinsRate) { return; } int structureWidth = MathFunctions.RandInt(4, 16); int structureDepth = MathFunctions.RandInt(4, 16); int xOffset = MathFunctions.RandInt(0, VoxelConstants.ChunkSizeX - structureWidth); int zOffset = MathFunctions.RandInt(0, VoxelConstants.ChunkSizeZ - structureDepth); int wallHeight = MathFunctions.RandInt(2, 6); int heightOffset = MathFunctions.RandInt(-4, 2); if (Settings.Overworld.Map.GetBiomeAt(Chunk.Origin.ToVector3(), Settings.Overworld.InstanceSettings.Origin).HasValue(out var biome)) { var avgHeight = GetAverageHeight(Chunk.Origin.X, Chunk.Origin.Z, structureWidth, structureDepth, Settings); bool[] doors = new bool[4]; for (int k = 0; k < 4; k++) { doors[k] = MathFunctions.RandEvent(0.5f); } for (int dx = 0; dx < structureWidth; dx++) { for (int dz = 0; dz < structureDepth; dz++) { var worldPos = new Vector3(Chunk.Origin.X + dx + xOffset, avgHeight + heightOffset, Chunk.Origin.Z + dz + zOffset); var baseVoxel = Settings.World.ChunkManager.CreateVoxelHandle(GlobalVoxelCoordinate.FromVector3(worldPos)); var underVoxel = VoxelHelpers.FindFirstVoxelBelow(Settings.World.ChunkManager.CreateVoxelHandle(GlobalVoxelCoordinate.FromVector3(worldPos))); var decay = Settings.NoiseGenerator.Generate(worldPos.X * 0.05f, worldPos.Y * 0.05f, worldPos.Z * 0.05f); if (decay > 0.7f) { continue; } if (!baseVoxel.IsValid) { continue; } if (baseVoxel.Coordinate.Y == (Settings.WorldSizeInChunks.Y * VoxelConstants.ChunkSizeY) - 1) { continue; } if (!underVoxel.IsValid) { continue; } var edge = (dx == 0 || dx == structureWidth - 1) || (dz == 0 || dz == structureDepth - 1); if (!edge && !baseVoxel.IsEmpty) { continue; } if (edge) { baseVoxel.RawSetType(Library.GetVoxelType(biome.RuinWallType)); } else { baseVoxel.RawSetType(Library.GetVoxelType(biome.RuinFloorType)); } bool[] wallState = new bool[4]; wallState[0] = dx == 0; wallState[1] = dx == structureWidth - 1; wallState[2] = dz == 0; wallState[3] = dz == structureDepth - 1; bool[] doorState = new bool[4]; doorState[0] = Math.Abs(dz - structureDepth / 2) < 1; doorState[1] = doorState[0]; doorState[2] = Math.Abs(dx - structureWidth / 2) < 1; doorState[3] = doorState[2]; for (int dy = 1; dy < (baseVoxel.Coordinate.Y - underVoxel.Coordinate.Y); dy++) { var currVoxel = Settings.World.ChunkManager.CreateVoxelHandle(underVoxel.Coordinate + new GlobalVoxelOffset(0, dy, 0)); if (!currVoxel.IsValid) { continue; } currVoxel.RawSetType(underVoxel.Type); } underVoxel.RawSetGrass(0); if (edge) { for (int dy = 1; dy < wallHeight * (1.0f - decay) && dy < (Settings.WorldSizeInChunks.Y * VoxelConstants.ChunkSizeY) - 2; dy++) { var currVoxel = Settings.World.ChunkManager.CreateVoxelHandle(baseVoxel.Coordinate + new GlobalVoxelOffset(0, dy, 0)); if (!currVoxel.IsValid) { continue; } if (currVoxel.Coordinate.Y == VoxelConstants.ChunkSizeY - 1) { continue; } bool door = false; for (int k = 0; k < 4; k++) { if (wallState[k] && doors[k] && doorState[k]) { door = true; break; } } if (door && dy < 3) { continue; } currVoxel.RawSetType(Library.GetVoxelType(biome.RuinWallType)); } } } } } }