Пример #1
0
    // Place objects from the generated BSP
    public void Build()
    {
        if (nodes == null)
        {
            return;
        }

        // Destroy all children in base plane
        for (int i = objectContainer.childCount - 1; i >= 0; i--)
        {
            DestroyImmediate(objectContainer.GetChild(i).gameObject);
        }

        // Scale base plane correctly
        basePlane.localScale = new Vector3(width / 10f, 1, height / 10f);

        lampLights = new List <Light>();

        for (int i = 0; i < nodes.Count; i++)
        {
            BSPNode node = nodes[i];
            int     x    = (int)(node.x - width / 2f + borderSize);
            int     y    = (int)(node.y - height / 2f + borderSize);

            // Add roads
            if (node.y != 0)
            {
                // TODO: Add function that adds a road and sets the grid types all in one
                // Roads and pavements are raised by a small random value to avoid graphical glitches
                // when point light interacts with overlapping geometry = needs changing
                GameObject roadH = Instantiate(roadPrefab, new Vector3(x + node.width / 2f, 0.01f + Random.value * 0.001f, y), Quaternion.Euler(90, 0, 0), objectContainer);
                roadH.transform.localScale = new Vector3(node.width, 2 /*Random.Range(1.5f, 2.5f)*/, 1);
                setGridPointsFromRect(node.x + borderSize, node.y + borderSize - 1, node.width, 2, GridPoint.Type.Path);
            }
            if (node.x != 0)
            {
                GameObject roadV = Instantiate(roadPrefab, new Vector3(x, 0.01f + Random.value * 0.001f, y + node.height / 2f), Quaternion.Euler(90, 0, 0), objectContainer);
                roadV.transform.localScale = new Vector3(2, node.height, 1);
                setGridPointsFromRect(node.x + borderSize - 1, node.y + borderSize, 2, node.height, GridPoint.Type.Path);
            }

            // Add pavements
            float      pavementWidth = 0.8f;
            GameObject pavementL     = Instantiate(pavementPrefab, new Vector3(x + 1 + pavementWidth / 2f, Random.value * 0.001f, y + node.height / 2f), Quaternion.identity, objectContainer);
            GameObject pavementR     = Instantiate(pavementPrefab, new Vector3(x + node.width - 1 - pavementWidth / 2f, Random.value * 0.001f, y + node.height / 2f), Quaternion.identity, objectContainer);
            GameObject pavementT     = Instantiate(pavementPrefab, new Vector3(x + node.width / 2f, Random.value * 0.001f, y + node.height - 1 - pavementWidth / 2f), Quaternion.identity, objectContainer);
            GameObject pavementB     = Instantiate(pavementPrefab, new Vector3(x + node.width / 2f, Random.value * 0.001f, y + 1 + pavementWidth / 2f), Quaternion.identity, objectContainer);
            pavementL.transform.localScale = pavementR.transform.localScale = new Vector3(pavementWidth, pavementL.transform.localScale.y, node.height - 2);
            pavementT.transform.localScale = pavementB.transform.localScale = new Vector3(node.width - 2, pavementL.transform.localScale.y, pavementWidth);
            setGridPointsFromRect(node.x + borderSize + 1, node.y + borderSize + 1, 1, node.height - 2, GridPoint.Type.Pavement);
            setGridPointsFromRect(node.x + borderSize + 1, node.y + borderSize + node.height - 2, node.width - 2, 1, GridPoint.Type.Pavement);
            setGridPointsFromRect(node.x + borderSize + node.width - 2, node.y + borderSize + 1, 1, node.height - 2, GridPoint.Type.Pavement);
            setGridPointsFromRect(node.x + borderSize + 1, node.y + borderSize + 1, node.width - 2, 1, GridPoint.Type.Pavement);

            // Add buildings
            float border = 2.5f;
            float gapMin = 0.5f, gapMax = 2.5f;
            Rect  buildingArea = new Rect(x + border, y + border, node.width - border * 2, node.height - border * 2);

            Building buildingPrefabFirst = buildingPrefabs[Random.Range(0, buildingPrefabs.Length)];
            Building buildingNext;

            // Left edge
            buildingNext = placeBuildingsAlongEdge(buildingPrefabFirst, new Vector3(buildingArea.xMin, 0, buildingArea.yMin), new Vector3(buildingArea.x, 0, buildingArea.yMax), gapMin, gapMax);
            // Top edge
            buildingNext = placeBuildingsAlongEdge(buildingNext, new Vector3(buildingArea.x, 0, buildingArea.yMax), new Vector3(buildingArea.xMax, 0, buildingArea.yMax), gapMin, gapMax);
            // Right edge
            buildingNext = placeBuildingsAlongEdge(buildingNext, new Vector3(buildingArea.xMax, 0, buildingArea.yMax), new Vector3(buildingArea.xMax, 0, buildingArea.y), gapMin, gapMax);
            // Bottom edge
            placeBuildingsAlongEdge(buildingNext, new Vector3(buildingArea.xMax, 0, buildingArea.y), new Vector3(buildingArea.xMin, 0, buildingArea.yMin), gapMin, gapMax);

            // Add lampposts
            int        corner   = Random.Range(0, 4); // 0 is bottom left, increases clockwise
            float      indent   = 2.2f;
            Vector3    pos      = new Vector3(x + indent + (corner > 1 ? node.width - indent * 2 : 0), 0, y + indent + (corner == 1 || corner == 2 ? node.height - indent * 2 : 0));
            GameObject lamppost = Instantiate(lamppostPrefab, pos, Quaternion.Euler(0, -135 + 90 * corner, 0), objectContainer);
            setGridPointFromWorldPos(pos, GridPoint.Type.Obstacle);
            lampLights.Add(lamppost.GetComponentInChildren <Light>(true));
        }

        int roadAreaWidth  = width - borderSize * 2;
        int roadAreaHeight = height - borderSize * 2;

        // Add border roads
        GameObject roadL = Instantiate(roadPrefab, new Vector3(-roadAreaWidth / 2f, 0.01f + Random.value * 0.001f, 0), Quaternion.Euler(90, 0, 0), objectContainer);
        GameObject roadR = Instantiate(roadPrefab, new Vector3(roadAreaWidth / 2f, 0.01f + Random.value * 0.001f, 0), Quaternion.Euler(90, 0, 0), objectContainer);
        GameObject roadT = Instantiate(roadPrefab, new Vector3(0, 0.01f + Random.value * 0.001f, roadAreaHeight / 2), Quaternion.Euler(90, 0, 0), objectContainer);
        GameObject roadB = Instantiate(roadPrefab, new Vector3(0, 0.01f + Random.value * 0.001f, -roadAreaHeight / 2), Quaternion.Euler(90, 0, 0), objectContainer);

        roadL.transform.localScale = roadR.transform.localScale = new Vector3(2, roadAreaHeight + 2, 1);
        roadT.transform.localScale = roadB.transform.localScale = new Vector3(roadAreaWidth + 2, 2, 1);
        setGridPointsFromRect(borderSize - 1, borderSize - 1, 2, roadAreaHeight + 2, GridPoint.Type.Path);
        setGridPointsFromRect(width - borderSize - 1, borderSize - 1, 2, roadAreaHeight + 2, GridPoint.Type.Path);
        setGridPointsFromRect(borderSize - 1, borderSize - 1, roadAreaWidth + 2, 2, GridPoint.Type.Path);
        setGridPointsFromRect(borderSize - 1, height - borderSize - 1, roadAreaWidth + 2, 2, GridPoint.Type.Path);

        // Add gates
        bool       gate1Left   = Random.value > 0.5f; // Gate on left or right wall
        bool       gate2Bottom = Random.value > 0.5f; // Gate on top or bottom wall
        int        gate1Pos    = Random.Range((int)(-roadAreaHeight / 2 * 0.8f), (int)(roadAreaHeight / 2 * 0.8f));
        int        gate2Pos    = Random.Range((int)(-roadAreaWidth / 2 * 0.8f), (int)(roadAreaWidth / 2 * 0.8f));
        GameObject gate1       = Instantiate(gatePrefab, new Vector3(width / 2f * (gate1Left ? -1 : 1), 0, gate1Pos), Quaternion.Euler(0, 90, 0), objectContainer);
        GameObject gate2       = Instantiate(gatePrefab, new Vector3(gate2Pos, 0, height / 2f * (gate2Bottom ? -1 : 1)), Quaternion.identity, objectContainer);

        GridPoint gate1GridPoint = GridPointFromWorldPos(gate1.transform.position);
        GridPoint gate2GridPoint = GridPointFromWorldPos(gate2.transform.position);

        // Add border buildings
        Bounds gate1Bounds = new Bounds(gate1.transform.position, MathHelper.AbsVector3(gate1.transform.rotation * new Vector3(8, 1, borderSize + 12)));
        Bounds gate2Bounds = new Bounds(gate2.transform.position, MathHelper.AbsVector3(gate2.transform.rotation * new Vector3(8, 1, borderSize + 12)));

        placeBuildingsAlongEdge(null, new Vector3(-roadAreaWidth / 2, 0, -roadAreaHeight / 2 - 2), new Vector3(roadAreaWidth / 2, 0, -roadAreaHeight / 2 - 2), 0.5f, 2.5f, false, gate2Bounds);
        placeBuildingsAlongEdge(null, new Vector3(roadAreaWidth / 2 + 2, 0, -roadAreaHeight / 2), new Vector3(roadAreaWidth / 2 + 2, 0, roadAreaHeight / 2 - 2), 0.5f, 2.5f, false, gate1Bounds);
        placeBuildingsAlongEdge(null, new Vector3(roadAreaWidth / 2, 0, roadAreaHeight / 2 + 2), new Vector3(-roadAreaWidth / 2, 0, roadAreaHeight / 2 + 2), 0.5f, 2.5f, false, gate2Bounds);
        placeBuildingsAlongEdge(null, new Vector3(-roadAreaWidth / 2 - 2, 0, roadAreaHeight / 2), new Vector3(-roadAreaWidth / 2 - 2, 0, -roadAreaHeight / 2), 0.5f, 2.5f, false, gate1Bounds);

        // Add walls (TODO: Put this into functions to reduce number of lines)
        if (gate1Left)
        {
            GameObject wallL1 = Instantiate(wallPrefab, new Vector3(-width / 2f, 0, (-height / 2f + gate1Pos) / 2f - 1), Quaternion.Euler(0, 90, 0), objectContainer);
            GameObject wallL2 = Instantiate(wallPrefab, new Vector3(-width / 2f, 0, (height / 2f + gate1Pos) / 2f + 1), Quaternion.Euler(0, 90, 0), objectContainer);
            GameObject wallR  = Instantiate(wallPrefab, new Vector3(width / 2f, 0, 0), Quaternion.Euler(0, 90, 0), objectContainer);
            wallL1.transform.localScale = new Vector3(height / 2f + gate1Pos - 4, 1, 1);
            wallL2.transform.localScale = new Vector3(height / 2f - gate1Pos - 4, 1, 1);
            wallR.transform.localScale  = new Vector3(height - 2, 1, 1);
        }
        else
        {
            GameObject wallL  = Instantiate(wallPrefab, new Vector3(-width / 2f, 0, 0), Quaternion.Euler(0, 90, 0), objectContainer);
            GameObject wallR1 = Instantiate(wallPrefab, new Vector3(width / 2f, 0, (-height / 2f + gate1Pos) / 2f - 1), Quaternion.Euler(0, 90, 0), objectContainer);
            GameObject wallR2 = Instantiate(wallPrefab, new Vector3(width / 2f, 0, (height / 2f + gate1Pos) / 2f + 1), Quaternion.Euler(0, 90, 0), objectContainer);
            wallL.transform.localScale  = new Vector3(height - 2, 1, 1);
            wallR1.transform.localScale = new Vector3(height / 2f + gate1Pos - 4, 1, 1);
            wallR2.transform.localScale = new Vector3(height / 2f - gate1Pos - 4, 1, 1);
        }
        if (gate2Bottom)
        {
            GameObject wallB1 = Instantiate(wallPrefab, new Vector3((-width / 2f + gate2Pos) / 2f - 1, 0, -height / 2f), Quaternion.identity, objectContainer);
            GameObject wallB2 = Instantiate(wallPrefab, new Vector3((width / 2f + gate2Pos) / 2f + 1, 0, -height / 2f), Quaternion.identity, objectContainer);
            GameObject wallT  = Instantiate(wallPrefab, new Vector3(0, 0, height / 2f), Quaternion.identity, objectContainer);
            wallB1.transform.localScale = new Vector3(width / 2f + gate2Pos - 4, 1, 1);
            wallB2.transform.localScale = new Vector3(width / 2f - gate2Pos - 4, 1, 1);
            wallT.transform.localScale  = new Vector3(width - 2, 1, 1);
        }
        else
        {
            GameObject wallB  = Instantiate(wallPrefab, new Vector3(0, 0, -height / 2f), Quaternion.identity, objectContainer);
            GameObject wallT1 = Instantiate(wallPrefab, new Vector3((-width / 2f + gate2Pos) / 2f - 1, 0, height / 2f), Quaternion.identity, objectContainer);
            GameObject wallT2 = Instantiate(wallPrefab, new Vector3((width / 2f + gate2Pos) / 2f + 1, 0, height / 2f), Quaternion.identity, objectContainer);
            wallB.transform.localScale  = new Vector3(width - 2, 1, 1);
            wallT1.transform.localScale = new Vector3(width / 2f + gate2Pos - 4, 1, 1);
            wallT2.transform.localScale = new Vector3(width / 2f - gate2Pos - 4, 1, 1);
        }

        // Add roads from the gates
        GameObject roadGate1 = Instantiate(roadPrefab, new Vector3((width / 2f - borderSize / 2f) * (gate1Left ? -1 : 1), 0.01f + Random.value * 0.001f, gate1Pos), Quaternion.Euler(90, 0, 0), objectContainer);
        GameObject roadGate2 = Instantiate(roadPrefab, new Vector3(gate2Pos, 0.01f + Random.value * 0.001f, (height / 2f - borderSize / 2f) * (gate2Bottom ? -1 : 1)), Quaternion.Euler(90, 0, 0), objectContainer);

        roadGate1.transform.localScale = new Vector3(borderSize, 4, 1);
        roadGate2.transform.localScale = new Vector3(4, borderSize, 1);
        setGridPointsFromRect(gate1Left ? 1 : width - borderSize, gate1Pos + height / 2 - 2, borderSize, 4, GridPoint.Type.Path);
        setGridPointsFromRect(gate2Pos + width / 2 - 2, gate2Bottom ? 1 : height - borderSize, 4, borderSize, GridPoint.Type.Path);

        // Add wall corners
        GameObject wallCorner1 = Instantiate(wallCornerPrefab, new Vector3(-width / 2f, 0, -height / 2f), Quaternion.Euler(0, 90, 0), objectContainer);
        GameObject wallCorner2 = Instantiate(wallCornerPrefab, new Vector3(width / 2f, 0, -height / 2f), Quaternion.Euler(0, 0, 0), objectContainer);
        GameObject wallCorner3 = Instantiate(wallCornerPrefab, new Vector3(width / 2f, 0, height / 2f), Quaternion.Euler(0, -90, 0), objectContainer);
        GameObject wallCorner4 = Instantiate(wallCornerPrefab, new Vector3(-width / 2f, 0, height / 2f), Quaternion.Euler(0, 180, 0), objectContainer);

        // Add lampposts at all 4 corners of the map
        for (int i = 0; i < 4; i++)
        {
            float      indent   = 1.8f;
            Vector3    pos      = new Vector3(-roadAreaWidth / 2f - indent + (i > 1 ? roadAreaWidth + indent * 2 : 0), 0, -roadAreaHeight / 2f - indent + (i == 1 || i == 2 ? roadAreaHeight + indent * 2 : 0));
            GameObject lamppost = Instantiate(lamppostPrefab, pos, Quaternion.Euler(0, 45 + 90 * i, 0), objectContainer);
            setGridPointFromWorldPos(pos, GridPoint.Type.Obstacle);
            lampLights.Add(lamppost.GetComponentInChildren <Light>(true));
        }

        // Add trees
        for (int j = 0; j < height; j += 2)
        {
            for (int i = 0; i < width; i += 2)
            {
                // Make sure there are no obstacles in the 2x2 area around the tree
                if (gridPoints[i, j].type != GridPoint.Type.Grass || gridPoints[i + 1, j].type != GridPoint.Type.Grass || gridPoints[i, j + 1].type != GridPoint.Type.Grass ||
                    gridPoints[i + 1, j + 1].type != GridPoint.Type.Grass)
                {
                    continue;
                }

                float noiseValue = Mathf.PerlinNoise(i * treeNoiseScale, j * treeNoiseScale);

                if (noiseValue > treeNoiseThreshold)
                {
                    Vector3    offset     = MathHelper.RandomVector2(0.2f, 0.8f);
                    Vector3    pos        = new Vector3(-width / 2f + i + offset.x, 0, -height / 2f + j + offset.y);
                    GameObject treeObject = Instantiate(treePrefabs[Random.Range(0, treePrefabs.Length)], pos, Quaternion.Euler(0, Random.Range(0f, 360f), 0), objectContainer);
                    treeObject.transform.localScale = Vector3.one * Random.Range(1f, 3f);
                    // treeObject.transform.localScale = Vector3.one * 3f * noiseValue;
                    gridPoints[i, j].type = GridPoint.Type.Obstacle;
                }
            }
        }

        // Add bushes
        for (int j = 0; j < height; j++)
        {
            for (int i = 0; i < width; i++)
            {
                if (gridPoints[i, j].type != GridPoint.Type.Grass)
                {
                    continue;
                }

                float noiseValue = Mathf.PerlinNoise(i * bushNoiseScale, j * bushNoiseScale);

                if (noiseValue > bushNoiseThreshold)
                {
                    Vector3    offset     = MathHelper.RandomVector2(0.2f, 0.8f);
                    Vector3    pos        = new Vector3(-width / 2f + i + offset.x, 0, -height / 2f + j + offset.y);
                    GameObject bushObject = Instantiate(bushPrefabs[Random.Range(0, bushPrefabs.Length)], pos, Quaternion.Euler(0, Random.Range(0f, 360f), 0), objectContainer);
                    bushObject.transform.Translate(new Vector3(Random.Range(-.25f, .25f), 0, Random.Range(-.25f, .25f)));
                    bushObject.transform.localScale = Vector3.one * Random.Range(0.7f, 1.3f);
                    // treeObject.transform.localScale = Vector3.one * 3f * noiseValue;
                    gridPoints[i, j].type = GridPoint.Type.Obstacle;
                }
            }
        }

        // Add grass
        for (int j = 0; j < height; j++)
        {
            for (int i = 0; i < width; i++)
            {
                if (gridPoints[i, j].type != GridPoint.Type.Grass)
                {
                    continue;
                }

                float noiseValue = Mathf.PerlinNoise(i * grassNoiseScale, j * grassNoiseScale);

                int grassNumber = 0;
                if (noiseValue > grassNoiseThresholdSmall)
                {
                    grassNumber = 1;
                }
                if (noiseValue > grassNoiseThresholdBig)
                {
                    grassNumber = 2;
                }

                for (int g = 0; g < grassNumber; g++)
                {
                    Vector3    offset      = MathHelper.RandomVector2(0.2f, 0.8f);
                    Vector3    pos         = new Vector3(-width / 2f + i + offset.x, 0, -height / 2f + j + offset.y);
                    GameObject grassObject = Instantiate(grassPrefab, pos, Quaternion.Euler(0, Random.Range(0f, 360f), 0), objectContainer);
                    grassObject.transform.localScale = Vector3.one * Random.Range(0.8f, 2.0f);
                }
            }
        }
    }