public AreaCollisionHelper(Area area)
        {
            collisionTiles = new List<CollisionTile>();
            boxCollisionPoints = new List<Vector3>();

            SetArea(area);
        }
        public List<Area> GetAreaNeighbors(Area area)
        {
            lock (AreaCollection.CollectionLock)
            {
                var neighbors = new List<Area>();

                // Get all neighbours of the current area
                foreach (var neighbor in AreaCollection.Areas.Concat(AreaCache.Areas))
                {
                    if (neighbor.Info.Location.X >= area.Info.Location.X - 1 &&
                        neighbor.Info.Location.X <= area.Info.Location.X + 1 &&
                        neighbor.Info.Location.Y >= area.Info.Location.Y - 1 &&
                        neighbor.Info.Location.Y <= area.Info.Location.Y + 1 &&
                        neighbor.Info.Location.Z >= area.Info.Location.Z - 1 &&
                        neighbor.Info.Location.Z <= area.Info.Location.Z + 1)
                    {
                        if (neighbor.Info.LocationId != area.Info.LocationId)
                        {
                            neighbors.Add(neighbor);
                        }
                    }
                }

                return neighbors;
            }
        }
Exemple #3
0
        private void HandleArea(Area area, Area areaMask, byte[] mask)
        {
            var location2i = new Vector2i(area.Info.Location.X, area.Info.Location.Z);

            random = new Random(location2i.GetHashCode());
            NoiseAreaType noiseAreaType;

            // Loop through all columns of the area
            for (int z = 0; z < Area.Size.Z; z++)
            {
                int currentZ = z * Area.Size.X;

                for (int x = 0; x < Area.Size.X; x++)
                {
                    // Skip unaffected columns
                    if (mask[currentZ + x] == 0)
                    {
                        continue;
                    }

                    // Get the heights of the two areas at the current column location
                    int areaHeight = areaTilesGenerators[area.Info.Type].GetHeight(location2i, x, z);
                    int maskAreaHeight = areaTilesGenerators[areaMask.Info.Type].GetHeight(location2i, x, z);
                    int newAreaHeight;

                    // For the outer edges of the mask affected by this threshold, clamp the area height to the areaMask height for a rounded/smoother visual effect
                    if (mask[currentZ + x] > AreaEdgeThreshold)
                    {
                        newAreaHeight = areaTilesGenerators[areaMask.Info.Type].GetHeight(location2i, x, z);
                        noiseAreaType = areaMask.Info.Type;
                    }
                    else
                    {
                        float maskPercentage = mask[currentZ + x] / (float)AreaEdgeThreshold;

                        newAreaHeight = Math.Max(0, areaHeight + (int)((maskAreaHeight - areaHeight) * maskPercentage));

                        // Find out if we should use the theme from the area or the areaMask for this tile column (weighted for a gradient effect by using the mask[])
                        noiseAreaType = random.Next(256) < mask[currentZ + x] ? areaMask.Info.Type : area.Info.Type;
                    }

                    // Lower the column
                    if (maskAreaHeight < areaHeight)
                    {
                        newAreaHeight = Math.Max(0, newAreaHeight - area.Info.TileHeight.Start);
                        areaTilesGenerators[noiseAreaType].TrimHeight(ref area, x, z, newAreaHeight);
                    }
                    // Raise the column
                    else if (maskAreaHeight > areaHeight)
                    {
                        newAreaHeight = Math.Min(Area.Size.Y - 1, newAreaHeight - areaMask.Info.TileHeight.Start);
                        areaTilesGenerators[noiseAreaType].ExpandHeight(ref area, x, z, newAreaHeight);
                    }
                }
            }
        }
Exemple #4
0
 public void Merge(ref Area area, Area areaMask, byte[] mask)
 {
     if (area.Info.IsEmpty)
     {
         HandleEmptyArea(area, areaMask, mask);
     }
     else
     {
         HandleArea(area, areaMask, mask);
     }
 }
        public void GenerateSurface(ref Area area)
        {
            GenerateNoiseMountains(area.Info.Location.X, area.Info.Location.Z);

            int index = 0;

            // Down/up (vertically)
            for (int tileY = 0; tileY < Area.Size.Y; tileY++)
            {
                int currentTileY = (Area.Size.Y - (tileY + 1)) + (area.Info.Location.Y * Area.Size.Y);

                // In/out
                for (int tileZ = 0; tileZ < Area.Size.Z; tileZ++)
                {
                    int currentZ = tileZ * Area.Size.Z;

                    // Left/right (horizontally)
                    for (int tileX = 0; tileX < Area.Size.X; tileX++)
                    {
                        int currentSurfaceIndex = currentZ + tileX;
                        int currentSurfaceY = surface[currentSurfaceIndex] - 1;

                        // Above the ground?
                        if (currentTileY > currentSurfaceY)
                        {
                            // Empty tile
                            area.Info.Tiles[index].Type = TileType.Empty;
                        }
                        // At the exact ground level?
                        else if (currentTileY == currentSurfaceY)
                        {
                            area.Info.Tiles[index].Type = GetSurfaceTileType(area.Info.Location, tileX, tileY, tileZ);
                        }
                        // Below the ground level
                        else
                        {
                            area.Info.Tiles[index].Type = GetSurfaceTileType(area.Info.Location, tileX, tileY, tileZ);
                        }

                        index++;
                    }
                }
            }
        }
        private void FindCollidingTiles(Area area, ref List<Vector3> points)
        {
            // Loop through all corners of the bounding box
            for (int i = 0; i < points.Count; i++)
            {
                // If the current point is inside the area
                if (area.Info.BoundingBox.Contains(points[i]) == ContainmentType.Contains)
                {
                    // Calculate the point indices within the area tile array
                    int x = Math.Min((Area.Size.X - 1), (int)(points[i].X - area.Info.BoundingBox.Min.X));
                    int y = Math.Min((Area.Size.Y - 1), (int)(area.Info.BoundingBox.Max.Y - points[i].Y));
                    int z = Math.Min((Area.Size.Z - 1), (int)(points[i].Z - area.Info.BoundingBox.Min.Z));

                    int index = (Area.LevelSize * y) + (z * (int)Area.Size.Z) + x;

                    // Get the tile
                    var tile = area.Info.Tiles[index];

                    // If the tile is visible and hasnt been added yet
                    if (tile.Type != TileType.Empty && !CollisionTilesContains(x, y, z))
                    {
                        var result = new CollisionTile()
                        {
                            Id = index.ToString(),
                            Tile = tile,
                            BoundingBox = new BoundingBox(new Vector3(area.Info.BoundingBox.Min.X + x * Tile.Size.X,
                                                                      area.Info.BoundingBox.Max.Y - ((y + 1) * Tile.Size.Y),
                                                                      area.Info.BoundingBox.Min.Z + z * Tile.Size.Z),
                                                          new Vector3((area.Info.BoundingBox.Min.X + x * Tile.Size.X) + Tile.Size.X,
                                                                      area.Info.BoundingBox.Max.Y - (y * Tile.Size.Y),
                                                                      (area.Info.BoundingBox.Min.Z + z * Tile.Size.Z) + Tile.Size.Z))
                        };

                        result.BoundingBox.Min -= new Vector3(0.05f);
                        result.BoundingBox.Max += new Vector3(0.05f);

                        collisionTiles.Add(result);
                    }
                }
            }
        }
        public void GenerateSurface(ref Area area)
        {
            for (int y = 0; y < Area.Size.Y; y++)
            {
                int currentY = y * Area.LevelSize;

                for (int z = 0; z < Area.Size.Z; z++)
                {
                    int currentZ = z * Area.Size.X;

                    for (int x = 0; x < Area.Size.X; x++)
                    {
                        int currentIndex = currentY + currentZ + x;

                        area.Info.Tiles[currentIndex].Type = TileType.Empty;

                        //if (y == Area.Size.Y - 1)
                        //{
                        //    area.Info.Tiles[currentIndex].Type = TileType.Stone;
                        //}
                        //else if (y == Area.Size.Y - 2 && x == 16 && z == 16)
                        //{
                        //    area.Info.Tiles[currentIndex].Type = TileType.Stone;
                        //}
                        //else if (y > 20 && x == 17 && z == 16)
                        //{
                        //    area.Info.Tiles[currentIndex].Type = TileType.Stone;
                        //}
                        //else if (y > 20 && x == 15 && z == 16)
                        //{
                        //    area.Info.Tiles[currentIndex].Type = TileType.Stone;
                        //}
                        //else if (y > 23 && x == 16 && z == 17)
                        //{
                        //    area.Info.Tiles[currentIndex].Type = TileType.Stone;
                        //}
                    }
                }
            }
        }
        public void ExpandHeight(ref Area area, int x, int z, int height)
        {
            if (height < 1)
            {
                return;
            }

            int index = (z * Area.Size.X) + ((Area.Size.Y - 1) * Area.LevelSize) + x;

            for (int y = 0; y < Area.Size.Y; y++)
            {
                if (y < height || height == Area.Size.Y - 1)
                {
                    area.Info.Tiles[index].Type = TileType.Stone;
                }
                else if (y == height)
                {
                    area.Info.Tiles[index].Type = GetSurfaceTileType(area.Info.Location, x, y, z);
                }

                index -= Area.LevelSize;
            }
        }
 /// <summary>
 /// Sets the area to perform collision tests with
 /// </summary>
 /// <param name="area"></param>
 public void SetArea(Area area)
 {
     collisionArea = area;
 }
        /// <summary>
        /// Calculates if the area is visible within a camera viewport or not
        /// </summary>
        /// <param name="area">The area</param>
        /// <param name="camera">The camera to check against</param>
        /// <returns>True if the area is visible, false if not</returns>
        public bool IsAreaVisible(Area area, CameraBase camera)
        {
            if (area.Info.IsEmpty)
            {
                return false;
            }

            // Calculate the distance from the area to the camera
            areaToCameraDistance = (area.Info.Center - camera.Position).Length();

            // Is the area within stand-on or next-to distance
            if (areaToCameraDistance < areasAlwaysVisibleWithinDistance)
            {
                return true;
            }

            // Calculate the normal from the area pointing towards the camera position
            areaLookAtNormal = (camera.Position - area.Info.Center);
            areaLookAtNormal.Normalize();

            return Vector3.Dot(camera.LookAtNormal, areaLookAtNormal) <= -0.5f;
        }
 private void MoveVisibleAreaToCache(Area area)
 {
     area.Model.Clear();
     AreaCollection.Remove(area);
     AreaCache.Add(area);
 }
        public void TrimHeight(ref Area area, int x, int z, int height)
        {
            int index = (z * Area.Size.X) + ((Area.Size.Y - 1) * Area.LevelSize) + x;

            for (int y = 0; y < Area.Size.Y; y++)
            {
                // Above the surface
                if (y >= height)
                {
                    area.Info.Tiles[index].Type = TileType.Empty;
                }
                // At the surface
                else if (y == height - 1)
                {
                    area.Info.Tiles[index].Type = GetSurfaceTileType(area.Info.Location, x, y, z);
                }
                // Below the surface
                else
                {
                    area.Info.Tiles[index].Type = TileType.Stone;
                }

                index -= Area.LevelSize;
            }
        }
        public int GetHeight(Vector2i location, int x, int z)
        {
            if (!heightMapCache.HeightMaps.ContainsKey(location))
            {
                var area = new Area();
                area.Info.Location = new Vector3i(location.X, 0, location.Y);
                GenerateSurface(ref area);
            }

            return heightMapCache.HeightMaps[location][(z * Area.Size.X) + x];
        }
 public void GenerateUnderground(ref Area area)
 {
     for (int i = 0; i < area.Info.Tiles.Length; i++)
     {
         area.Info.Tiles[i].Type = TileType.Mud;
     }
 }
Exemple #15
0
        private void HandleEmptyArea(Area area, Area areaMask, byte[] mask)
        {
            var location2i = new Vector2i(area.Info.Location.X, area.Info.Location.Z);

            bool isEmpty = true;

            // Loop through all columns of the area
            for (int z = 0; z < Area.Size.Z; z++)
            {
                int currentZ = z * Area.Size.X;

                for (int x = 0; x < Area.Size.X; x++)
                {
                    // Skip unaffected columns
                    if (mask[currentZ + x] == 0)
                    {
                        continue;
                    }

                    // Get the heights of the two areas at the current column location
                    int areaHeight = areaTilesGenerators[area.Info.Type].GetHeight(location2i, x, z);
                    int maskAreaHeight = areaTilesGenerators[areaMask.Info.Type].GetHeight(location2i, x, z);

                    // Calculate the new height based on the weight between the two areas
                    float maskPercentage = mask[currentZ + x] / 255f;
                    int delta = Math.Max(0, (int)((maskAreaHeight - areaHeight) * maskPercentage));
                    int newHeight = areaHeight + delta;

                    // Completely filled column
                    if (newHeight > area.Info.TileHeight.End)
                    {
                        isEmpty = false;
                        areaTilesGenerators[area.Info.Type].ExpandHeight(ref area, x, z, newHeight);
                    }
                    // The column height is within the bounds of the area
                    else if (delta > 0)
                    {
                        newHeight -= area.Info.TileHeight.Start;
                        areaTilesGenerators[area.Info.Type].ExpandHeight(ref area, x, z, newHeight);

                        if (isEmpty)
                        {
                            isEmpty = newHeight > 0;
                        }
                    }
                }
            }

            area.Info.IsEmpty = isEmpty;
        }
        private bool CanSpawnInArea(Area area, BoundingBox boundingBox)
        {
            // Handle empty areas
            if (area.Info.IsEmpty)
            {
                SnapBoundingBoxToBottomOfArea(area, ref boundingBox);
                info.IsAtBottomOfArea = true;
                info.Position = boundingBoxHelper.GetCenter(boundingBox);
                return true;
            }

            areaCollisionHelper.SetArea(area);

            float boundsHeight = boundingBox.Max.Y - boundingBox.Min.Y;

            // Loop through all tiles in the area and perform collision checks against the bounding box, looping from the bottom of the area and up
            for (int y = 0; y < Area.Size.Y; y++)
            {
                int worldY = area.Info.Location.Y * Area.Size.Y;

                // Adjust the bounding box height
                boundingBox.Min.Y = worldY + y;
                boundingBox.Max.Y = boundingBox.Min.Y + boundsHeight;

                // Get all intersecting tiles for the bounding box at the current height
                var intersectingTiles = areaCollisionHelper.GetIntersectingTiles(boundingBox);

                // Found a suitable position?
                if (intersectingTiles.Count == 0)
                {
                    //ImageExporter.AreaSliceOnXAxisToBitmap("AreaSpawnPointHelper_Plains.png", area, 16);

                    info.IsAtBottomOfArea = (y == 0);
                    info.Position = boundingBoxHelper.GetCenter(boundingBox);
                    return true;
                }
            }

            // Failed to find a suitable spawnpoint in this area
            return false;
        }
        public Area Generate(int x, int y, int z)
        {
            // Initialize the area
            var area = new Area();
            area.Info.Location = new Vector3i(x, y, z);

            // Generate the area types surrounding this location
            noiseManager.World.Generators[NoiseWorldType.Default].Generate(x - 1, y - 1);
            byte[] areaTypes = noiseManager.World.Generators[NoiseWorldType.Default].Output;

            // Surface level terrain
            if (y >= 0)
            {
                NoiseAreaType areaTheme;

                if (x < 0)
                {
                    areaTheme = NoiseAreaType.Plains;

                    noiseManager.Areas.Generators[NoiseAreaType.Plains].Generate(x, z);
                    surface = noiseManager.Areas.Generators[NoiseAreaType.Plains].Output;
                }
                else
                {
                    areaTheme = NoiseAreaType.Mountains;

                    noiseManager.Areas.Generators[NoiseAreaType.Mountains].Generate(x, z);
                    surface = noiseManager.Areas.Generators[NoiseAreaType.Mountains].Output;
                }

                // Down/up (vertically)
                for (int tileY = 0; tileY < Area.Size.Y; tileY++)
                {
                    int currentY = tileY * Area.LevelSize;
                    int currentTileY = (Area.Size.Y - (tileY + 1)) + (y * Area.Size.Y);

                    // In/out
                    for (int tileZ = 0; tileZ < Area.Size.Z; tileZ++)
                    {
                        int currentZ = tileZ * Area.Size.Z;

                        // Left/right (horizontally)
                        for (int tileX = 0; tileX < Area.Size.X; tileX++)
                        {
                            int currentIndex = currentY + currentZ + tileX;
                            int currentSurfaceIndex = currentZ + tileX;
                            int currentSurfaceY = surface[currentSurfaceIndex];

                            // Above the ground?
                            if (currentTileY > currentSurfaceY)
                            {
                                // Empty tile
                                area.Info.Tiles[currentIndex].Type = TileType.Empty;
                            }
                            // At the exact ground level?
                            else if (currentTileY == currentSurfaceY)
                            {
                                if (areaTheme == NoiseAreaType.Plains)
                                {
                                    area.Info.Tiles[currentIndex].Type = TileType.Grass;
                                }
                                else if (areaTheme == NoiseAreaType.Mountains)
                                {
                                    area.Info.Tiles[currentIndex].Type = TileType.Sand;
                                }
                            }
                            // Below the ground level
                            else
                            {
                                area.Info.Tiles[currentIndex].Type = TileType.Sand;
                            }
                        }
                    }
                }
            }
            // Underground level terrain
            else
            {
                for (int i = 0; i < area.Info.Tiles.Count(); i++)
                {
                    area.Info.Tiles[i].Type = TileType.Sand;
                }
            }

            UpdateAreaInfo(ref area.Info);

            return area;
        }
        private void SnapBoundingBoxToBottomOfArea(Area area, ref BoundingBox boundingBox)
        {
            float boundsHeight = boundingBox.Max.Y - boundingBox.Min.Y;

            int worldY = area.Info.Location.Y * Area.Size.Y;

            boundingBox.Min.Y = worldY;
            boundingBox.Max.Y = boundingBox.Min.Y + boundsHeight;
        }
        public void Render(GameTime gameTime, CameraBase camera)
        {
            // Clear old content
            VisibleTerrainMeshes.Clear();

            // Loop through all areas to see which ones should be rendered
            for (int i = 0; i < terrainVisibility.AreaCollection.Areas.Count; i++)
            {
                area = terrainVisibility.AreaCollection.Areas[i];

                // Skip areas not visible to the camera
                if (!terrainVisibility.IsAreaVisible(area, camera))
                {
                    continue;
                }

                // Loop through all meshes within the current area and add them to the visible groups
                foreach (KeyValuePair<TileType, TerrainMesh> meshPair in area.Model.Meshes)
                {
                    // Initialize the current mesh-group key if needed
                    if (!VisibleTerrainMeshes.ContainsKey(meshPair.Key))
                    {
                        VisibleTerrainMeshes.Add(meshPair.Key, new List<TerrainMesh>());
                    }

                    meshPair.Value.Offset.X = area.Info.Location.X * Area.Size.X;
                    meshPair.Value.Offset.Y = (area.Info.Location.Y * Area.Size.Y);
                    meshPair.Value.Offset.Z = area.Info.Location.Z * Area.Size.Z;

                    // Add the mesh to the visible groups
                    VisibleTerrainMeshes[meshPair.Key].Add(meshPair.Value);
                }
            }

            // Initiate rendering
            var device = context.Graphics.Device;
            var effect = context.Graphics.Effect as BasicEffect;
            RenderStateContext.SetRenderStates(device);

            // Loop through all visible meshes
            foreach (var meshCollection in VisibleTerrainMeshes)
            {
                // Set the current texture
                effect.Texture = context.Resources.Textures["Tile" + ((ushort)meshCollection.Key).ToString()];

                // Loop through all meshes using the current texture
                for (int i = 0; i < meshCollection.Value.Count; i++)
                {
                    mesh = meshCollection.Value[i];

                    // Skip empty meshes
                    if (mesh.VertexCount == 0 || mesh.VertexBuffer == null)
                    {
                        continue;
                    }

                    // Set the vertex and index data to be rendered
                    device.SetVertexBuffer(mesh.VertexBuffer);
                    device.Indices = mesh.IndexBuffer;

                    // Translate the mesh
                    effect.World = Matrix.CreateTranslation(mesh.Offset);

                    // Loop through all effect passes
                    for (int j = 0; j < context.Graphics.Effect.CurrentTechnique.Passes.Count; j++)
                    {
                        // Apply the current effect pass
                        context.Graphics.Effect.CurrentTechnique.Passes[j].Apply();

                        // Render the mesh
                        device.DrawIndexedPrimitives(PrimitiveType.TriangleList,
                                                     0,
                                                     0,
                                                     mesh.VertexCount,
                                                     0,
                                                     mesh.IndexCount / 3);

                    }
                }
            }
        }