//public VertexPositionTexture[] WallVertices; //public VertexPositionColor[] BodyVertices; public LevelRenderer(Level level) { if (shaftTexture == null) { shaftTexture = TextureLoader.FromFile("Content/Map/iceWall.png"); } if (background == null) { background = new Sprite("Content/Map/background2.png", Vector2.Zero); backgroundTop = new Sprite("Content/Map/background.png", Vector2.Zero); dustParticles = new Sprite("Content/Map/dustparticles.png", Vector2.Zero); } if (wallEdgeEffect == null) { wallEdgeEffect = new BasicEffect(GameMain.Instance.GraphicsDevice) { DiffuseColor = new Vector3(0.8f, 0.8f, 0.8f), VertexColorEnabled = false, TextureEnabled = true, Texture = shaftTexture }; wallEdgeEffect.CurrentTechnique = wallEdgeEffect.Techniques["BasicEffect_Texture"]; } if (wallCenterEffect == null) { wallCenterEffect = new BasicEffect(GameMain.Instance.GraphicsDevice) { VertexColorEnabled = false, TextureEnabled = true, Texture = backgroundTop.Texture }; wallCenterEffect.CurrentTechnique = wallCenterEffect.Techniques["BasicEffect_Texture"]; } if (backgroundSpriteManager == null) { var files = GameMain.SelectedPackage.GetFilesOfType(ContentType.BackgroundSpritePrefabs); if (files.Count > 0) { backgroundSpriteManager = new BackgroundSpriteManager(files); } else { backgroundSpriteManager = new BackgroundSpriteManager("Content/BackgroundSprites/BackgroundSpritePrefabs.xml"); } } this.level = level; }
public void DrawBackground(SpriteBatch spriteBatch, Camera cam, BackgroundSpriteManager backgroundSpriteManager = null, BackgroundCreatureManager backgroundCreatureManager = null) { spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearWrap); Vector2 backgroundPos = cam.WorldViewCenter; backgroundPos.Y = -backgroundPos.Y; backgroundPos *= 0.05f; if (backgroundPos.Y < 1024) { if (backgroundPos.Y < 0) { backgroundTop.SourceRect = new Rectangle((int)backgroundPos.X, (int)backgroundPos.Y, 1024, (int)Math.Min(-backgroundPos.Y, 1024)); backgroundTop.DrawTiled(spriteBatch, Vector2.Zero, new Vector2(GameMain.GraphicsWidth, Math.Min(-backgroundPos.Y, GameMain.GraphicsHeight)), Vector2.Zero, level.BackgroundColor); } if (backgroundPos.Y > -1024) { background.SourceRect = new Rectangle((int)backgroundPos.X, (int)Math.Max(backgroundPos.Y, 0), 1024, 1024); background.DrawTiled(spriteBatch, (backgroundPos.Y < 0) ? new Vector2(0.0f, (int)-backgroundPos.Y) : Vector2.Zero, new Vector2(GameMain.GraphicsWidth, (int)Math.Ceiling(1024 - backgroundPos.Y)), Vector2.Zero, level.BackgroundColor); } } spriteBatch.End(); spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearWrap, DepthStencilState.Default, null, null, cam.Transform); if (backgroundSpriteManager != null) { backgroundSpriteManager.DrawSprites(spriteBatch, cam); } if (backgroundCreatureManager != null) { backgroundCreatureManager.Draw(spriteBatch); } Rectangle srcRect = new Rectangle(0, 0, 2048, 2048); Vector2 origin = new Vector2(cam.WorldView.X, -cam.WorldView.Y); Vector2 offset = -origin + dustOffset; while (offset.X <= -srcRect.Width) { offset.X += srcRect.Width; } while (offset.X > 0.0f) { offset.X -= srcRect.Width; } while (offset.Y <= -srcRect.Height) { offset.Y += srcRect.Height; } while (offset.Y > 0.0f) { offset.Y -= srcRect.Height; } for (int i = 0; i < 4; i++) { float scale = 1.0f - i * 0.2f; float recipScale = 1.0f / scale; //alpha goes from 1.0 to 0.0 when scale is in the range of 0.5-0.25 float alpha = (cam.Zoom * scale) < 0.5f ? (cam.Zoom * scale - 0.25f) * 40.0f : 1.0f; if (alpha <= 0.0f) { continue; } Vector2 offsetS = offset * scale + new Vector2(cam.WorldView.Width, cam.WorldView.Height) * (1.0f - scale) * 0.5f - new Vector2(256.0f * i); while (offsetS.X <= -srcRect.Width * scale) { offsetS.X += srcRect.Width * scale; } while (offsetS.X > 0.0f) { offsetS.X -= srcRect.Width * scale; } while (offsetS.Y <= -srcRect.Height * scale) { offsetS.Y += srcRect.Height * scale; } while (offsetS.Y > 0.0f) { offsetS.Y -= srcRect.Height * scale; } dustParticles.DrawTiled(spriteBatch, origin + offsetS, new Vector2(cam.WorldView.Width - offsetS.X, cam.WorldView.Height - offsetS.Y), Vector2.Zero, srcRect, Color.White * alpha, new Vector2(scale)); } spriteBatch.End(); RenderWalls(GameMain.Instance.GraphicsDevice, cam); }
public void Generate(bool mirror = false) { if (backgroundSpriteManager == null) { var files = GameMain.SelectedPackage.GetFilesOfType(ContentType.BackgroundSpritePrefabs); if (files.Count > 0) { backgroundSpriteManager = new BackgroundSpriteManager(files); } else { backgroundSpriteManager = new BackgroundSpriteManager("Content/BackgroundSprites/BackgroundSpritePrefabs.xml"); } } #if CLIENT if (backgroundCreatureManager == null) { var files = GameMain.SelectedPackage.GetFilesOfType(ContentType.BackgroundCreaturePrefabs); if (files.Count > 0) { backgroundCreatureManager = new BackgroundCreatureManager(files); } else { backgroundCreatureManager = new BackgroundCreatureManager("Content/BackgroundSprites/BackgroundCreaturePrefabs.xml"); } } #endif Stopwatch sw = new Stopwatch(); sw.Start(); if (loaded != null) { loaded.Unload(); } loaded = this; positionsOfInterest = new List <InterestingPosition>(); Voronoi voronoi = new Voronoi(1.0); List <Vector2> sites = new List <Vector2>(); bodies = new List <Body>(); Rand.SetSyncedSeed(ToolBox.StringToInt(seed)); #if CLIENT renderer = new LevelRenderer(this); backgroundColor = generationParams.BackgroundColor; float avgValue = (backgroundColor.R + backgroundColor.G + backgroundColor.G) / 3; GameMain.LightManager.AmbientLight = new Color(backgroundColor * (10.0f / avgValue), 1.0f); #endif SeaFloorTopPos = generationParams.SeaFloorDepth + generationParams.MountainHeightMax + generationParams.SeaFloorVariance; float minWidth = 6500.0f; if (Submarine.MainSub != null) { Rectangle dockedSubBorders = Submarine.MainSub.GetDockedBorders(); minWidth = Math.Max(minWidth, Math.Max(dockedSubBorders.Width, dockedSubBorders.Height)); } Rectangle pathBorders = borders; pathBorders.Inflate(-minWidth * 2, -minWidth * 2); startPosition = new Vector2( Rand.Range(minWidth, minWidth * 2, Rand.RandSync.Server), Rand.Range(borders.Height * 0.5f, borders.Height - minWidth * 2, Rand.RandSync.Server)); endPosition = new Vector2( borders.Width - Rand.Range(minWidth, minWidth * 2, Rand.RandSync.Server), Rand.Range(borders.Height * 0.5f, borders.Height - minWidth * 2, Rand.RandSync.Server)); //---------------------------------------------------------------------------------- //generate the initial nodes for the main path and smaller tunnels //---------------------------------------------------------------------------------- List <Vector2> pathNodes = new List <Vector2>(); pathNodes.Add(new Vector2(startPosition.X, borders.Height)); Vector2 nodeInterval = generationParams.MainPathNodeIntervalRange; for (float x = startPosition.X + nodeInterval.X; x < endPosition.X - nodeInterval.X; x += Rand.Range(nodeInterval.X, nodeInterval.Y, Rand.RandSync.Server)) { pathNodes.Add(new Vector2(x, Rand.Range(pathBorders.Y, pathBorders.Bottom, Rand.RandSync.Server))); } pathNodes.Add(new Vector2(endPosition.X, borders.Height)); if (pathNodes.Count <= 2) { pathNodes.Insert(1, borders.Center.ToVector2()); } GenerateTunnels(pathNodes, minWidth); //---------------------------------------------------------------------------------- //generate voronoi sites //---------------------------------------------------------------------------------- Vector2 siteInterval = generationParams.VoronoiSiteInterval; Vector2 siteVariance = generationParams.VoronoiSiteVariance; for (float x = siteInterval.X / 2; x < borders.Width; x += siteInterval.X) { for (float y = siteInterval.Y / 2; y < borders.Height; y += siteInterval.Y) { Vector2 site = new Vector2( x + Rand.Range(-siteVariance.X, siteVariance.X, Rand.RandSync.Server), y + Rand.Range(-siteVariance.Y, siteVariance.Y, Rand.RandSync.Server)); if (smallTunnels.Any(t => t.Any(node => Vector2.Distance(node, site) < siteInterval.Length()))) { //add some more sites around the small tunnels to generate more small voronoi cells if (x < borders.Width - siteInterval.X) { sites.Add(new Vector2(x, y) + Vector2.UnitX * siteInterval * 0.5f); } if (y < borders.Height - siteInterval.Y) { sites.Add(new Vector2(x, y) + Vector2.UnitY * siteInterval * 0.5f); } if (x < borders.Width - siteInterval.X && y < borders.Height - siteInterval.Y) { sites.Add(new Vector2(x, y) + Vector2.One * siteInterval * 0.5f); } } if (mirror) { site.X = borders.Width - site.X; } sites.Add(site); } } //---------------------------------------------------------------------------------- // construct the voronoi graph and cells //---------------------------------------------------------------------------------- Stopwatch sw2 = new Stopwatch(); sw2.Start(); List <GraphEdge> graphEdges = voronoi.MakeVoronoiGraph(sites, borders.Width, borders.Height); Debug.WriteLine("MakeVoronoiGraph: " + sw2.ElapsedMilliseconds + " ms"); sw2.Restart(); //construct voronoi cells based on the graph edges cells = CaveGenerator.GraphEdgesToCells(graphEdges, borders, GridCellSize, out cellGrid); Debug.WriteLine("find cells: " + sw2.ElapsedMilliseconds + " ms"); sw2.Restart(); //---------------------------------------------------------------------------------- // generate a path through the initial path nodes //---------------------------------------------------------------------------------- List <VoronoiCell> mainPath = CaveGenerator.GeneratePath(pathNodes, cells, cellGrid, GridCellSize, new Rectangle(pathBorders.X, pathBorders.Y, pathBorders.Width, borders.Height), 0.5f, mirror); for (int i = 2; i < mainPath.Count; i += 3) { positionsOfInterest.Add(new InterestingPosition(mainPath[i].Center, PositionType.MainPath)); } List <VoronoiCell> pathCells = new List <VoronoiCell>(mainPath); //make sure the path is wide enough to pass through EnlargeMainPath(pathCells, minWidth); foreach (InterestingPosition positionOfInterest in positionsOfInterest) { WayPoint wayPoint = new WayPoint(positionOfInterest.Position, SpawnType.Enemy, null); wayPoint.MoveWithLevel = true; } startPosition.X = pathCells[0].Center.X; //---------------------------------------------------------------------------------- // tunnels through the tunnel nodes //---------------------------------------------------------------------------------- foreach (List <Vector2> tunnel in smallTunnels) { if (tunnel.Count < 2) { continue; } //find the cell which the path starts from int startCellIndex = CaveGenerator.FindCellIndex(tunnel[0], cells, cellGrid, GridCellSize, 1); if (startCellIndex < 0) { continue; } //if it wasn't one of the cells in the main path, don't create a tunnel if (cells[startCellIndex].CellType != CellType.Path) { continue; } var newPathCells = CaveGenerator.GeneratePath(tunnel, cells, cellGrid, GridCellSize, pathBorders); positionsOfInterest.Add(new InterestingPosition(tunnel.Last(), PositionType.Cave)); if (tunnel.Count > 4) { positionsOfInterest.Add(new InterestingPosition(tunnel[tunnel.Count / 2], PositionType.Cave)); } pathCells.AddRange(newPathCells); } Debug.WriteLine("path: " + sw2.ElapsedMilliseconds + " ms"); sw2.Restart(); //---------------------------------------------------------------------------------- // remove unnecessary cells and create some holes at the bottom of the level //---------------------------------------------------------------------------------- cells = CleanCells(pathCells); pathCells.AddRange(CreateBottomHoles(generationParams.BottomHoleProbability, new Rectangle( (int)(borders.Width * 0.2f), 0, (int)(borders.Width * 0.6f), (int)(borders.Height * 0.8f)))); foreach (VoronoiCell cell in cells) { if (cell.Center.Y < borders.Height / 2) { continue; } cell.edges.ForEach(e => e.OutsideLevel = true); } //---------------------------------------------------------------------------------- // initialize the cells that are still left and insert them into the cell grid //---------------------------------------------------------------------------------- foreach (VoronoiCell cell in pathCells) { cell.edges.ForEach(e => e.OutsideLevel = false); cell.CellType = CellType.Path; cells.Remove(cell); } for (int x = 0; x < cellGrid.GetLength(0); x++) { for (int y = 0; y < cellGrid.GetLength(1); y++) { cellGrid[x, y].Clear(); } } foreach (VoronoiCell cell in cells) { int x = (int)Math.Floor(cell.Center.X / GridCellSize); int y = (int)Math.Floor(cell.Center.Y / GridCellSize); if (x < 0 || y < 0 || x >= cellGrid.GetLength(0) || y >= cellGrid.GetLength(1)) { continue; } cellGrid[x, y].Add(cell); } //---------------------------------------------------------------------------------- // create some ruins //---------------------------------------------------------------------------------- ruins = new List <Ruin>(); for (int i = 0; i < generationParams.RuinCount; i++) { GenerateRuin(mainPath); } //---------------------------------------------------------------------------------- // generate the bodies and rendered triangles of the cells //---------------------------------------------------------------------------------- startPosition.Y = borders.Height; endPosition.Y = borders.Height; List <VoronoiCell> cellsWithBody = new List <VoronoiCell>(cells); List <Vector2[]> triangles; bodies = CaveGenerator.GeneratePolygons(cellsWithBody, out triangles); #if CLIENT renderer.SetBodyVertices(CaveGenerator.GenerateRenderVerticeList(triangles).ToArray(), generationParams.WallColor); renderer.SetWallVertices(CaveGenerator.GenerateWallShapes(cells), generationParams.WallColor); #endif TopBarrier = BodyFactory.CreateEdge(GameMain.World, ConvertUnits.ToSimUnits(new Vector2(borders.X, 0)), ConvertUnits.ToSimUnits(new Vector2(borders.Right, 0))); TopBarrier.SetTransform(ConvertUnits.ToSimUnits(new Vector2(0.0f, borders.Height)), 0.0f); TopBarrier.BodyType = BodyType.Static; TopBarrier.CollisionCategories = Physics.CollisionLevel; bodies.Add(TopBarrier); GenerateSeaFloor(); backgroundSpriteManager.PlaceSprites(this, generationParams.BackgroundSpriteAmount); #if CLIENT backgroundCreatureManager.SpawnSprites(80); #endif foreach (VoronoiCell cell in cells) { foreach (GraphEdge edge in cell.edges) { edge.cell1 = null; edge.cell2 = null; edge.site1 = null; edge.site2 = null; } } //initialize MapEntities that aren't in any sub (e.g. items inside ruins) MapEntity.MapLoaded(null); Debug.WriteLine("Generatelevel: " + sw2.ElapsedMilliseconds + " ms"); sw2.Restart(); if (mirror) { Vector2 temp = startPosition; startPosition = endPosition; endPosition = temp; } Debug.WriteLine("**********************************************************************************"); Debug.WriteLine("Generated a map with " + sites.Count + " sites in " + sw.ElapsedMilliseconds + " ms"); Debug.WriteLine("Seed: " + seed); Debug.WriteLine("**********************************************************************************"); if (GameSettings.VerboseLogging) { DebugConsole.NewMessage("Generated level with the seed " + seed + " (type: " + generationParams.Name + ")", Color.White); } }
public void DrawBackground(SpriteBatch spriteBatch, Camera cam, BackgroundSpriteManager backgroundSpriteManager = null, BackgroundCreatureManager backgroundCreatureManager = null) { spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearWrap); Vector2 backgroundPos = cam.WorldViewCenter; backgroundPos.Y = -backgroundPos.Y; backgroundPos /= 20.0f; if (backgroundPos.Y < 1024) { if (backgroundPos.Y < 0) { backgroundTop.SourceRect = new Rectangle((int)backgroundPos.X, (int)backgroundPos.Y, 1024, (int)Math.Min(-backgroundPos.Y, 1024)); backgroundTop.DrawTiled(spriteBatch, Vector2.Zero, new Vector2(GameMain.GraphicsWidth, Math.Min(-backgroundPos.Y, GameMain.GraphicsHeight)), Vector2.Zero, level.BackgroundColor); } if (backgroundPos.Y > -1024) { background.SourceRect = new Rectangle((int)backgroundPos.X, (int)Math.Max(backgroundPos.Y, 0), 1024, 1024); background.DrawTiled(spriteBatch, (backgroundPos.Y < 0) ? new Vector2(0.0f, (int)-backgroundPos.Y) : Vector2.Zero, new Vector2(GameMain.GraphicsWidth, (int)Math.Ceiling(1024 - backgroundPos.Y)), Vector2.Zero, level.BackgroundColor); } } spriteBatch.End(); spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, SamplerState.LinearWrap, DepthStencilState.Default, null, null, cam.Transform); if (backgroundSpriteManager != null) { backgroundSpriteManager.DrawSprites(spriteBatch, cam); } if (backgroundCreatureManager != null) { backgroundCreatureManager.Draw(spriteBatch); } for (int i = 0; i < 4; i++) { float scale = 1.0f - i * 0.2f; //alpha goes from 1.0 to 0.0 when scale is in the range of 0.2-0.1 float alpha = (cam.Zoom * scale) < 0.2f ? (cam.Zoom * scale - 0.1f) * 10.0f : 1.0f; if (alpha <= 0.0f) { continue; } Vector2 offset = (new Vector2(cam.WorldViewCenter.X, cam.WorldViewCenter.Y) + dustOffset) * scale; Vector3 origin = new Vector3(cam.WorldView.Width, cam.WorldView.Height, 0.0f) * 0.5f; dustParticles.SourceRect = new Rectangle( (int)((offset.X - origin.X + (i * 256)) / scale), (int)((-offset.Y - origin.Y + (i * 256)) / scale), (int)((cam.WorldView.Width) / scale), (int)((cam.WorldView.Height) / scale)); spriteBatch.Draw(dustParticles.Texture, new Vector2(cam.WorldViewCenter.X, -cam.WorldViewCenter.Y), dustParticles.SourceRect, Color.White * alpha, 0.0f, new Vector2(cam.WorldView.Width, cam.WorldView.Height) * 0.5f / scale, scale, SpriteEffects.None, 1.0f - scale); } spriteBatch.End(); RenderWalls(GameMain.Instance.GraphicsDevice, cam); }