コード例 #1
0
    /// <summary>
    /// Places a roof over the specified building.
    /// The roof will only cover the tile specified by 'roofTileID'. If this is null,
    /// then a roof over the total building will be created
    /// </summary>
    /// <param name="vox"></param>
    /// <param name="build"></param>
    /// <param name="roofTileID"></param>
    public static void AddRoof(GenerationRandom genRan, BuildingVoxels vox, Building build, Voxel roofVox, int roofStartY = 5, Tile roofTileReplace = null)
    {
        if (roofTileReplace == null)
        {
            Vec2i dir = genRan.RandomQuadDirection();
            dir.x = Mathf.Abs(dir.x);
            dir.z = Mathf.Abs(dir.z);

            Vec2i start   = new Vec2i(build.Width / 2 * dir.x, build.Height / 2 * dir.z);
            Vec2i end     = start + new Vec2i(dir.z * build.Width, dir.x * build.Height);
            LineI t       = new LineI(start, end);
            float maxDist = Mathf.Max(t.Distance(new Vec2i(0, 0)), t.Distance(new Vec2i(build.Width - 1, 0)),
                                      t.Distance(new Vec2i(0, build.Height - 1)), t.Distance(new Vec2i(build.Width - 1, build.Height - 1)));

            int   maxHeight = genRan.RandomInt(4, 6);
            float scale     = maxHeight / (maxDist + 1);
            //float scale = 0.7f;

            for (int x = 0; x < build.Width; x++)
            {
                for (int z = 0; z < build.Height; z++)
                {
                    int height = (int)Mathf.Clamp((maxDist - t.Distance(new Vec2i(x, z)) + 1) * scale, 1, World.ChunkHeight - 1);
                    for (int y = 0; y < height; y++)
                    {
                        vox.AddVoxel(x, Mathf.Clamp(roofStartY + y, 0, World.ChunkHeight - 1), z, roofVox);
                    }
                }
            }
        }
    }
コード例 #2
0
    public void SetVoxels(int x, int y, int z, BuildingVoxels vox)
    {
        int cx = WorldToChunk(x);
        int cz = WorldToChunk(z);

        for (int x_ = 0; x_ < vox.Width; x_++)
        {
            for (int z_ = 0; z_ < vox.Depth; z_++)
            {
                int tx = (x_ + x) % World.ChunkSize;
                int tz = (z_ + z) % World.ChunkSize;
                //If tx or tz are 0, then cz must have changed - update it
                if (tx == 0)
                {
                    cx = (WorldToChunk(x + x_));
                }
                if (tz == 0)
                {
                    cz = (WorldToChunk(x + x_));
                }
                for (int y_ = 0; y_ < vox.Height; y_++)
                {
                    ChunkVoxels[cx, cz].SetVoxelNode(tx, y_ + y, tz, vox.GetVoxelNode(x_, y_, z_));
                }
            }
        }
    }
コード例 #3
0
    public static Blacksmith GenerateBlacksmith(GenerationRandom genRan, Blacksmith smith, out BuildingVoxels vox, BuildingGenerationPlan plan)
    {
        vox = new BuildingVoxels(smith.Width, World.ChunkHeight, smith.Height);
        ChooseWallBounds(genRan, smith);
        BuildingGenerator.ConnectBoundingWall(vox, smith.BoundingWall, Voxel.stone);
        Tile[,] tileMap = new Tile[smith.Width, smith.Height];
        //Make the whole floor stone
        BuildingGenerator.SetTiles(tileMap, 0, 0, smith.Width - 1, smith.Height - 1, Tile.STONE_FLOOR);

        Vec2i outSideMin = null;
        Vec2i outSideMax = null;

        //Find the outdoor part and make the floor dirt
        for (int i = 0; i < smith.BoundingWall.Length; i++)
        {
            Vec2i p = smith.BoundingWall[i];
            //If this boundry point does not lie on any of the edges, then it is indented into the
            //building. This means this point defines the outside region of the building.
            if ((p.x != 0 && p.x != smith.Width - 1) && (p.z != 0 && p.z != smith.Height - 1))
            {
                //We get the 2 neigboring wall points, as these define the outside region
                Vec2i nm1 = smith.BoundingWall[(i - 1 + smith.BoundingWall.Length) % smith.BoundingWall.Length];
                Vec2i np1 = smith.BoundingWall[(i + 1) % smith.BoundingWall.Length];

                int minX = Mathf.Min(p.x, nm1.x, np1.x);
                int minZ = Mathf.Min(p.z, nm1.z, np1.z);
                int maxX = Mathf.Max(p.x, nm1.x, np1.x);
                int maxZ = Mathf.Max(p.z, nm1.z, np1.z);
                BuildingGenerator.SetTiles(tileMap, minX, minZ, maxX - minX, maxZ - minZ, Tile.DIRT);
                outSideMin = new Vec2i(minX, minZ);
                outSideMax = new Vec2i(maxX, maxZ);
                break;
            }
        }
        smith.SetBuilding(tileMap);
        PlaceOutsideObjects(genRan, smith, vox, outSideMin, outSideMax);



        BuildingGenerator.ChooseEntrancePoint(genRan, vox, smith, plan);
        BuildingGenerator.AddWindow(genRan, vox, smith);
        BuildingGenerator.AddWindow(genRan, vox, smith);
        BuildingGenerator.AddWindow(genRan, vox, smith, autoReattempt: false);
        BuildingGenerator.AddWindow(genRan, vox, smith, autoReattempt: false);

        BuildingGenerator.PlaceObjectAgainstWall(genRan, new Chest(), 0, vox, smith, .1f, attemptsCount: 20, distToEntr: 4);
        BuildingGenerator.PlaceObjectAgainstWall(genRan, new WeaponStand(), 0, vox, smith, 0.1f, distToEntr: 4);
        BuildingGenerator.PlaceObjectAgainstWall(genRan, new ArmourStand(), 0, vox, smith, .1f, distToEntr: 4);

        WorkBuildingData wbd = new WorkBuildingData(new NPCJob[] { new NPCJobMerchant(smith), new NPCJobBlackSmith(smith), new NPCJobBlackSmith(smith) });

        smith.SetWorkBuildingData(wbd);

        for (int i = 0; i < 10; i++)
        {
            smith.Inventory.AddItem(new Shirt(new ItemMetaData().SetColor(Color.blue)));
        }

        return(smith);
    }
コード例 #4
0
    public static Barracks GenerateBarracks(GenerationRandom genRan, Barracks barr, out BuildingVoxels vox, BuildingGenerationPlan plan)
    {
        vox = new BuildingVoxels(barr.Width, World.ChunkHeight, barr.Height);
        ChooseWallBounds(genRan, barr);
        BuildingGenerator.ConnectBoundingWall(vox, barr.BoundingWall, Voxel.stone);
        Tile[,] tileMap = new Tile[barr.Width, barr.Height];
        BuildingGenerator.ChooseEntrancePoint(genRan, vox, barr, plan);
        BuildingGenerator.SetTiles(tileMap, 0, 0, barr.Width / 2, barr.Height - 1, Tile.STONE_FLOOR);
        BuildingGenerator.SetTiles(tileMap, barr.Width / 2, 0, barr.Width / 2 - 1, barr.Height - 1, Tile.DIRT);

        List <NPCJob> jobs = new List <NPCJob>();

        for (int x = 2; x < barr.Height; x += 3)
        {
            Vector3       pos      = new Vector3(barr.Width - 2, 0, x);
            float         rotation = Vec2i.Angle(Vec2i.Forward, BuildingGenerator.GetWallPointDirection(barr, new Vec2i(barr.Width - 2, x)));
            TrainingDummy obj      = new TrainingDummy().SetPosition(pos).SetRotation(rotation) as TrainingDummy;
            if (BuildingGenerator.AddObject(barr, vox, obj))
            {
                jobs.Add(new NPCJobSoldier(barr));
            }
        }



        WorkBuildingData wbd = new WorkBuildingData(jobs.ToArray());

        barr.SetWorkBuildingData(wbd);
        barr.SetBuilding(tileMap);

        return(barr);
    }
コード例 #5
0
ファイル: Building.cs プロジェクト: nikitapond/ProceduralRPG
    public void CalculateSpawnableTiles(BuildingVoxels vox)
    {
        SpawnableTiles = new List <Vec2i>();

        for (int x = 0; x < Width; x++)
        {
            for (int z = 0; z < Height; z++)
            {
                if (vox.GetVoxelNode(x, 0, z).Voxel != Voxel.none)
                {
                    continue;
                }
                bool canPlace = true;
                foreach (WorldObjectData obj in InternalObjects)
                {
                    if (obj.IntersectsPoint(new Vec2i(x, z)))
                    {
                        canPlace = false;
                        break;
                    }
                }
                if (canPlace)
                {
                    if (BuildingSubworld != null)
                    {
                        SpawnableTiles.Add(new Vec2i(x, z));
                    }
                    else
                    {
                        SpawnableTiles.Add(new Vec2i(x, z) + WorldPosition);
                    }
                }
            }
        }
    }
コード例 #6
0
    public BuildingSubworldBuilder(Building building, BuildingVoxels vox, BuildingGenerationPlan plan)
    {
        Building = building;
        BuildVox = vox;
        Plan     = plan;
        Size     = new Vec2i(building.Width, building.Height);
        int cWidth  = Mathf.CeilToInt(((float)Size.x) / World.ChunkSize);
        int cHeight = Mathf.CeilToInt(((float)Size.z) / World.ChunkSize);

        if (cWidth < 1)
        {
            cWidth = 1;
        }
        if (cHeight < 1)
        {
            cHeight = 1;
        }
        ChunkSize = new Vec2i(cWidth, cHeight);

        Tiles   = new int[cWidth, cHeight][, ];
        Voxels  = new ChunkVoxelData[cWidth, cHeight];
        Objects = new List <WorldObjectData> [cWidth, cHeight];
        for (int x = 0; x < cWidth; x++)
        {
            for (int z = 0; z < cHeight; z++)
            {
                Tiles[x, z]  = new int[World.ChunkSize, World.ChunkSize];
                Voxels[x, z] = new ChunkVoxelData();
            }
        }
    }
コード例 #7
0
    public static Vec2i[] FindInsideWallBoundryPoints(BuildingVoxels vox, Building build, Tile groundTile = null)
    {
        Vec2i[]      dirs       = new Vec2i[] { new Vec2i(-1, 0), new Vec2i(1, 0), new Vec2i(0, 1), new Vec2i(0, -1) };
        List <Vec2i> wallPoints = new List <Vec2i>();

        for (int x = 1; x < build.Width - 1; x++)
        {
            for (int z = 1; z < build.Height - 1; z++)
            {
                //If the current tile is not defined as a ground tile, we do not include this point
                if (groundTile != null && build.BuildingTiles[x, z] != groundTile)
                {
                    continue;
                }

                for (int i = 0; i < 4; i++)
                {
                    int   x_ = dirs[i].x + x;
                    int   z_ = dirs[i].z + z;
                    Vec2i v_ = new Vec2i(x, z);
                    if (vox.GetVoxel(x_, 0, z_) != Voxel.none && !wallPoints.Contains(v_))
                    {
                        wallPoints.Add(v_);
                    }
                }
            }
        }
        return(wallPoints.ToArray());
    }
コード例 #8
0
    public static Farm GenerateVegFarm(GenerationRandom genRan, Farm farm, out BuildingVoxels vox, BuildingGenerationPlan plan)
    {
        vox = new BuildingVoxels(farm.Width, World.ChunkHeight, farm.Height);

        Tile[,] tiles = new Tile[farm.Width, farm.Height];
        BuildingGenerator.SetTiles(tiles, 0, 0, farm.Width - 1, farm.Height - 1, Tile.TEST_MAGENTA);

        farm.SetBuilding(tiles);
        BuildingGenerator.BuildBoundingWallRect(vox, farm.Width, farm.Height, 2, Voxel.stone);

        BuildingGenerator.ChooseEntrancePoint(genRan, vox, farm, plan, false);


        return(farm);
    }
コード例 #9
0
 //public static void ChooseRandomEntrance()
 public static void BuildBoundingWallRect(BuildingVoxels vox, int width, int depth, int wallHeight, Voxel wallVox)
 {
     for (int y = 0; y < wallHeight; y++)
     {
         for (int x = 0; x < width; x++)
         {
             vox.SetVoxel(x, y, 0, wallVox);
             vox.SetVoxel(x, y, depth - 1, wallVox);
         }
         for (int z = 0; z < depth; z++)
         {
             vox.SetVoxel(0, y, z, wallVox);
             vox.SetVoxel(width - 1, y, z, wallVox);
         }
     }
 }
コード例 #10
0
    public static void ChooseEntrancePoint(GenerationRandom genRan, BuildingVoxels vox, Building build, BuildingGenerationPlan plan, bool requiredSubworld = true)
    {
        Vec2i entranceSide = plan.EntranceSide;

        Vec2i mid  = new Vec2i(build.Width / 2, build.Height / 2);
        Vec2i entr = null;

        //Travel out iterativly till we reach the wall
        for (int r = 0; r < Mathf.Max(build.Width, build.Height); r++)
        {
            Vec2i v = mid + entranceSide * r;
            if (v.x < 0 || v.z < 0 || v.x >= build.Width || v.z >= build.Height)
            {
                break;
            }
            if (vox.GetVoxel(v.x, 1, v.z) != Voxel.none)
            {
                entr = v;
                break;
            }
        }

        if (entr == null)
        {
            entr = new Vec2i(2, 2);
        }
        build.SetEntrancePoint(entr);
        for (int y = 0; y < 4; y++)
        {
            vox.ClearVoxel(entr.x, y, entr.z);
        }
        if (requiredSubworld)
        {
            Door interior = new Door();
            interior.SetRotation(Vector2.Angle(Vector2.up, entranceSide));
            interior.SetPosition(entr);
            build.InternalEntranceObject = interior;
            AddObject(build, vox, interior, true);

            Door external = new Door();
            external.SetPosition(entr);
            external.SetRotation(Vector2.Angle(Vector2.up, entranceSide));

            build.ExternalEntranceObject = external;
            build.AddExternalObject(external);
        }
    }
コード例 #11
0
    /// <summary>
    /// Generates the simplest type of house - a shack
    /// A shack is made of either (cobble?) stone or wood,
    /// it consists of only 1 room, with basic objects inside (bed, chair, table)
    /// </summary>
    /// <param name="house"></param>
    /// <param name="vox"></param>
    /// <returns></returns>
    public static House GenerateShack(GenerationRandom genRan, House house, out BuildingVoxels vox, BuildingGenerationPlan plan)
    {
        vox           = new BuildingVoxels(house.Width, World.ChunkHeight, house.Height);
        Tile[,] floor = new Tile[house.Width, house.Height];

        BuildingGenerator.BuildBoundingWallRect(vox, house.Width, house.Height, 6, Voxel.wood);
        //BuildingGenerator.ConnectBoundingWall(vox, house.BoundingWall, Voxel.wood, 5);
        BuildingGenerator.SetTiles(floor, 0, 0, house.Width - 1, house.Height - 1, Tile.STONE_FLOOR);
        house.SetBuilding(floor);

        BuildingGenerator.ChooseEntrancePoint(genRan, vox, house, plan);
        BuildingGenerator.AddWindow(genRan, vox, house, size: genRan.RandomInt(1, 4), autoReattempt: true);
        BuildingGenerator.AddWindow(genRan, vox, house, size: genRan.RandomInt(1, 4), autoReattempt: true);
        BuildingGenerator.AddWindow(genRan, vox, house, size: genRan.RandomInt(1, 4), autoReattempt: false);
        BuildingGenerator.AddWindow(genRan, vox, house, size: genRan.RandomInt(1, 4), autoReattempt: false);
        BuildingGenerator.AddWindow(genRan, vox, house, size: genRan.RandomInt(1, 4), autoReattempt: false);
        house.InsideWallPoints = BuildingGenerator.FindInsideWallBoundryPoints(vox, house);

        /*foreach (Vec2i v in house.InsideWallPoints)
         * {
         *  //house.AddObjectReference(new Chest().SetPosition(v));
         *  WorldObjectData bed = new Bed().SetPosition(v);
         *  bed.SetRotation(Vec2i.Angle(Vec2i.Forward, BuildingGenerator.GetWallPointDirection(house, v)));
         *  if(!house.ObjectIntersects(bed))
         *      house.AddObjectReference(bed);
         * }*/

        BuildingGenerator.PlaceObjectAgainstWall(genRan, new DoubleBed(), 0, vox, house, .3f, distToEntr: 4, attemptsCount: 40);
        BuildingGenerator.PlaceObjectAgainstWall(genRan, new Chest(), 0, vox, house, 0.1f, distToEntr: 3, attemptsCount: 40);

        for (int i = 0; i < house.BoundingWall.Length; i++)
        {
            BuildingGenerator.PlaceObjectAgainstWall(genRan, new WallTorch(), 1.5f, vox, house, 0f, requireWallBacking: true);
        }
        house.AddExternalObject(new BuildingInternalNoWalkFloor(new Vector3(1, 0, 1), new Vector3(house.Width - 2, 5, house.Height - 2)));
        BuildingGenerator.AddRoof(genRan, vox, house, Voxel.thatch);

        BuildingSubworldBuilder b = new BuildingSubworldBuilder(house, vox, plan);

        b.CreateSubworld();
        //ChunkData[,] subChunks = new ChunkData[1, 1];


        return(house);
    }
コード例 #12
0
    public static bool AddObject(Building build, BuildingVoxels vox, WorldObjectData obj, bool force = false)
    {
        if (force)
        {
            build.AddInternalObject(obj);
            return(true);
        }
        else
        {
            //Iterate all objects in the building and check for intersection.
            foreach (WorldObjectData obj_ in build.GetBuildingInternalObjects())
            {
                //If they intersect, then we cannot place this object.
                if (obj_.Intersects(obj))
                {
                    return(false);
                }
            }

            //Find the integer bounds
            Recti bounds = obj.CalculateIntegerBounds();
            int   yMin   = (int)obj.Position.y;
            int   yMax   = yMin + (int)obj.Size.y;
            //Iterate the voxel position of the object bounds.
            for (int x = bounds.X; x < bounds.X + bounds.Width; x++)
            {
                for (int z = bounds.Y; z < bounds.Y + bounds.Height; z++)
                {
                    for (int y = yMin; y < yMax; y++)
                    {
                        //If any single voxel is non-none, then we cannot place the object here.
                        if (vox.GetVoxel(x, y, z) != Voxel.none)
                        {
                            return(false);
                        }
                    }
                }
            }
            build.AddInternalObject(obj);
            return(true);
        }
    }
コード例 #13
0
    public static void ConnectBoundingWall(BuildingVoxels vox, Vec2i[] bounds, Voxel voxel, int wallHeight = 6)
    {
        for (int i = 0; i < bounds.Length; i++)
        {
            Vec2i a = bounds[i];
            Vec2i b = bounds[(i + 1) % bounds.Length];
            int   x = a.x;
            int   z = a.z;

            int xDir = (int)Mathf.Sign(b.x - a.x);
            int zDir = (int)Mathf.Sign(b.z - a.z);

            while (!(x == b.x && z == b.z))
            {
                for (int y = 0; y < wallHeight; y++)
                {
                    vox.SetVoxel(x, y, z, voxel);
                }

                //data[x, z] = copy.Copy(globalPos + new Vec2i(x, z));



                int dx = (int)Mathf.Abs(b.x - x);
                int dz = (int)Mathf.Abs(b.z - z);

                if (dx > dz)
                {
                    x += xDir;
                }
                else if (dz > dx)
                {
                    z += zDir;
                }
                else
                {
                    x += xDir;
                    z += zDir;
                }
            }
        }
    }
コード例 #14
0
    public static Building CreateBuilding(GenerationRandom genRan, out BuildingVoxels vox, BuildingGenerationPlan plan)
    {
        Vec2i zero      = new Vec2i(0, 0);
        int   maxWidth  = (plan.DesiredSize == null || plan.DesiredSize == zero) ?Mathf.Min(plan.BuildingPlan.MaxSize, plan.MaxWidth): plan.DesiredSize.x;
        int   maxHeight = (plan.DesiredSize == null || plan.DesiredSize == zero)? Mathf.Min(plan.BuildingPlan.MaxSize, plan.MaxHeight) : plan.DesiredSize.z;
        int   width     = genRan.RandomInt(plan.BuildingPlan.MinSize, maxWidth);
        int   height    = genRan.RandomInt(plan.BuildingPlan.MinSize, maxHeight);

        if (plan.BuildingPlan == Building.BLACKSMITH)
        {
            Blacksmith smith = BlacksmithGenerator.GenerateBlacksmith(genRan, new Blacksmith(width, height), out vox, plan);
            return(smith);
        }
        if (plan.BuildingPlan == Building.BARACKS)
        {
            Barracks barr = BarracksGenerator.GenerateBarracks(genRan, new Barracks(width, height), out vox, plan);
            return(barr);
        }
        if (plan.BuildingPlan == Building.TAVERN)
        {
            return(TavernGenerator.GenerateTavern(genRan, new Tavern(width, height), out vox, plan));
        }
        if (plan.BuildingPlan == Building.VEGFARM)
        {
            Farm farm = FarmGenerator.GenerateVegFarm(genRan, new Farm(width, height), out vox, plan);
            return(farm);
        }
        if (plan.BuildingPlan == Building.WHEATFARM)
        {
            Farm farm = FarmGenerator.GenerateWheatFarm(genRan, new Farm(width, height), out vox, plan);
            return(farm);
        }

        House house = HouseGenerator.GenerateHouse(genRan, new House(width, height), out vox, plan);

        return(house);
        //return GenerateHouse(out vox, width, height);
    }
コード例 #15
0
    public void AddBuilding(Building b, BuildingVoxels vox, Vec2i pos)
    {
        float minHeight = 0;

        //SetTiles(pos.x, pos.z, b.Width, b.Height, b.BuildingTiles);
        for (int x = 0; x < b.Width; x++)
        {
            for (int z = 0; z < b.Height; z++)
            {
                int cx = WorldToChunk(x);
                int cz = WorldToChunk(z);

                int deltaHeight = ChunkBases != null ? (int)(minHeight - ChunkBases[cx, cz].Height) : 0;

                SetTile(x + pos.x, z + pos.z, b.BuildingTiles[x, z]);
                SetHeight(x + pos.x, z + pos.z, minHeight);



                for (int y = 0; y < vox.Height; y++)
                {
                    VoxelNode voxNode = vox.GetVoxelNode(x, y, z);
                    if (voxNode.IsNode)
                    {
                        //Debug.Log("Adding vox node: " + voxNode);
                        SetVoxelNode(x + pos.x, y, z + pos.z, vox.GetVoxelNode(x, y, z));
                    }
                }
            }
        }
        foreach (WorldObjectData obj in b.GetBuildingExternalObjects())
        {
            obj.SetPosition(obj.Position + pos.AsVector3());
            //We (should) already have checked for object validity when creating the building
            AddObject(obj, true);
        }
    }
コード例 #16
0
    public static Tavern GenerateTavern(GenerationRandom genRan, Tavern tavern, out BuildingVoxels vox, BuildingGenerationPlan plan)
    {
        vox = new BuildingVoxels(tavern.Width, World.ChunkHeight, tavern.Height);
        BuildingGenerator.BuildBoundingWallRect(vox, tavern.Width, tavern.Height, 6, Voxel.wood);
        BuildingGenerator.ChooseEntrancePoint(genRan, vox, tavern, plan);

        Tile[,] tileMap = new Tile[tavern.Width, tavern.Height];

        BuildingGenerator.SetTiles(tileMap, 0, 0, tavern.Width, tavern.Height, Tile.WOOD_FLOOR);
        tavern.SetBuilding(tileMap);
        BuildingGenerator.AddWindow(genRan, vox, tavern, autoReattempt: true);
        BuildingGenerator.AddWindow(genRan, vox, tavern, autoReattempt: true);
        BuildingGenerator.AddWindow(genRan, vox, tavern, autoReattempt: true);
        BuildingGenerator.AddWindow(genRan, vox, tavern, autoReattempt: false);
        BuildingGenerator.AddWindow(genRan, vox, tavern, autoReattempt: false);
        FirePlace fp = new FirePlace();

        BuildingGenerator.PlaceObjectAgainstWall(genRan, fp, 0, vox, tavern, 0, true, 4, true, 20);
        BuildingGenerator.PlaceObjectAgainstWall(genRan, new WallTorch(), 1.5f, vox, tavern, 0, true, 2);
        NPCJob[] jobs = new NPCJob[] { new NPCJobMerchant(tavern, "Tavern Keep"), new NPCJobMerchant(tavern, "Tavern Keep") };
        tavern.SetWorkBuildingData(new WorkBuildingData(jobs));
        BuildingGenerator.AddRoof(genRan, vox, tavern, Voxel.thatch);
        return(tavern);
    }
コード例 #17
0
    /// <summary>
    ///
    /// </summary>
    /// <param name="genRan">The RNG used for this building</param>
    /// <param name="obj">The object to place in the building</param>
    /// <param name="height">The height above the ground the object should sit</param>
    /// <param name="vox">The voxel data of this building. Only required if 'requireWallBacking' is true</param>
    /// <param name="build">The building to place the object in</param>
    /// <param name="distFromWall">The distance from a wall the object should be placed</param>
    /// <param name="wallIndex">Defines the wall we should attempt to place this object on. The 'i'th wall defines the wall
    /// connecting build.BoundingWall[i] -> build.BoundingWall[i+1]. If left as default value (-1), an index will be randomly generated</param>
    /// <param name="requireWallBacking">If true, then we will search for a point on the wall that is backed against a wall.
    /// Used to stop certain objects being placed in front of windows</param>
    /// <param name="forcePlace">If true, then we do not check for intersection with other objects in the building</param>
    /// <param name="attemptsCount">The number of attempts made to place the object on this wall</param>
    /// <returns>True if object is placed sucesfully, false otherwise</returns>
    public static bool PlaceObjectAgainstWall(GenerationRandom genRan, WorldObjectData obj, float height,
                                              BuildingVoxels vox, Building build, float distFromWall = 0, bool requireWallBacking = false, int distToEntr = 2,
                                              bool forcePlace = false, int attemptsCount = 5)
    {
        if (build.InsideWallPoints == null)
        {
            build.InsideWallPoints = FindInsideWallBoundryPoints(vox, build);
        }

        //Check attempts count
        attemptsCount--;
        if (attemptsCount == 0)
        {
            return(false);
        }

        float wallDisp = genRan.Random();
        //Define the position as the start pos + lambda*dir
        //Select a random position from all wall points
        Vec2i pos = genRan.RandomFromArray(build.InsideWallPoints);

        //If too close to entrance, try another placement
        if (build.Entrance != null && pos.QuickDistance(build.Entrance) < distToEntr * distToEntr)
        {
            return(PlaceObjectAgainstWall(genRan, obj, height, vox, build, distFromWall, requireWallBacking, distToEntr, forcePlace, attemptsCount));
        }
        //If the object is too close to any of the corners, try again
        foreach (Vec2i v in build.BoundingWall)
        {
            if (v.QuickDistance(pos) < 2)
            {
                return(PlaceObjectAgainstWall(genRan, obj, height, vox, build, distFromWall, requireWallBacking, distToEntr, forcePlace, attemptsCount));
            }
        }

        Vec2i faceDirection = GetWallPointDirection(build, pos);

        //If we require a backing wall, we check the position
        if (requireWallBacking)
        {
            Vec2i wPos = pos - faceDirection;
            for (int y = 0; y < 4; y++)
            {
                VoxelNode vn = vox.GetVoxelNode(wPos.x, y, wPos.z);
                //If there is no node (nothing set) then this position is not valid
                if (!vn.IsNode)
                {
                    return(PlaceObjectAgainstWall(genRan, obj, height, vox, build, distFromWall, requireWallBacking, distToEntr, forcePlace, attemptsCount));
                }
                if (vn.Voxel == Voxel.glass || vn.Voxel == Voxel.none)
                {
                    return(PlaceObjectAgainstWall(genRan, obj, height, vox, build, distFromWall, requireWallBacking, distToEntr, forcePlace, attemptsCount));
                }
            }
        }
        Vector3 finPos   = pos.AsVector3() + faceDirection.AsVector3() * distFromWall + Vector3.up * height;
        float   rotation = Vec2i.Angle(Vec2i.Forward, faceDirection);

        obj.SetPosition(finPos).SetRotation(rotation);
        if (!forcePlace)
        {
            foreach (WorldObjectData obj_ in build.GetBuildingExternalObjects())
            {
                if (obj.Intersects(obj_))
                {
                    return(PlaceObjectAgainstWall(genRan, obj, height, vox, build, distFromWall, requireWallBacking, distToEntr, forcePlace, attemptsCount));
                }
            }
        }


        //obj.SetPosition(finPos);
        build.AddInternalObject(obj);
        return(true);
    }
コード例 #18
0
 public static House GenerateHouse(GenerationRandom genRan, House house, out BuildingVoxels vox, BuildingGenerationPlan plan)
 {
     return(GenerateShack(genRan, house, out vox, plan));
 }
コード例 #19
0
    private static void PlaceOutsideObjects(GenerationRandom genRan, Blacksmith smith, BuildingVoxels vox, Vec2i outMin, Vec2i outMax)
    {
        List <WorldObjectData> toPlace = new List <WorldObjectData>(new WorldObjectData[] { new Anvil(), new Anvil() });
        bool isFinished = false;

        while (!isFinished)
        {
            WorldObjectData toPlaceCur = toPlace[0];
            toPlace.RemoveAt(0);
            Vector3 pos = genRan.RandomVector3(outMin.x, outMax.x, 0, 0, outMin.z, outMax.z);
            toPlaceCur.SetPosition(pos);
            while (!BuildingGenerator.AddObject(smith, vox, toPlaceCur))
            {
                pos = genRan.RandomVector3(outMin.x, outMax.x, 0, 0, outMin.z, outMax.z);
                toPlaceCur.SetPosition(pos);
            }
            if (toPlace.Count == 0)
            {
                isFinished = true;
            }
        }
    }
コード例 #20
0
    /// <summary>
    /// Adds the building to the settlement
    /// </summary>
    /// <param name="b"></param>
    /// <param name="vox"></param>
    /// <param name="pos"></param>
    /// <returns></returns>
    public Recti AddBuilding(Building b, BuildingVoxels vox, Vec2i pos)
    {
        if (!IsAreaFree(pos.x, pos.z, b.Width, b.Height))
        {
            return(null);
        }


        int nodeX      = Mathf.FloorToInt(((float)pos.x) / NodeSize);
        int nodeZ      = Mathf.FloorToInt(((float)pos.z) / NodeSize);
        int nodeWidth  = Mathf.CeilToInt(((float)b.Width) / NodeSize);
        int nodeHeight = Mathf.CeilToInt(((float)b.Height) / NodeSize);

        for (int x = nodeX; x < nodeX + nodeWidth; x++)
        {
            for (int z = nodeZ; z < nodeZ + nodeHeight; z++)
            {
                BuildingMap[x, z] = true;
            }
        }

        Recti bo = new Recti(pos.x - 1, pos.z - 1, b.Width + 2, b.Height + 2);

        foreach (Recti bound in BuildingPlots)
        {
            if (bo.Intersects(bound))
            {
                return(null);
            }
        }
        int height = (int)Mathf.FloorToInt(FlattenArea(pos.x - 1, pos.z - 1, b.Width + 2, b.Height + 2));

        BuildingPlots.Add(bo);

        //Debug.Log("Adding building " + b);
        //SetTiles(pos.x, pos.z, b.Width, b.Height, b.BuildingTiles);
        for (int x = 0; x < b.Width; x++)
        {
            for (int z = 0; z < b.Height; z++)
            {
                SetTile(x + pos.x, z + pos.z, b.BuildingTiles[x, z]);


                //SetHeight(x + pos.x, z + pos.z, maxHeight);
                for (int y = 0; y < vox.Height; y++)
                {
                    SetVoxelNode(x + pos.x, height + y, z + pos.z, vox.GetVoxelNode(x, y, z));
                }
            }
        }
        foreach (WorldObjectData obj in b.GetBuildingExternalObjects())
        {
            //We must set the object to have coordinates based on the settlement,
            //such that the object is added to the correct chunk.
            obj.SetPosition(obj.Position + pos.AsVector3());
            //We (should) already have checked for object validity when creating the building
            AddObject(obj, true);
        }


        Vec2i wPos = pos + BaseTile;
        Vec2i cPos = World.GetChunkPosition(wPos);

        //Debug.Log("Calculating tiles!!!");
        b.SetPositions(BaseTile, pos);

        //if (b.BuildingSubworld != null)
        //    AddObject(b.ExternalEntranceObject as WorldObjectData, true);
        //    World.Instance.AddSubworld(b.BuildingSubworld);

        b.CalculateSpawnableTiles(vox);
        Buildings.Add(b);
        //PathNodes.Add(b.Entrance);
        return(bo);
    }
コード例 #21
0
    public static bool AddWindow(GenerationRandom genRan, BuildingVoxels vox, Building build, int wallIndex = -1, int size = 2, int height = 1, bool autoReattempt = true, int reattemptCount = 3)
    {
        reattemptCount--;
        if (reattemptCount == 0)
        {
            return(false);
        }
        //if default index, we choose one randomly
        if (wallIndex == -1)
        {
            wallIndex = genRan.RandomInt(0, build.BoundingWall.Length);
        }
        int wp1 = (wallIndex + 1) % build.BoundingWall.Length;

        Vec2i dif = build.BoundingWall[wp1] - build.BoundingWall[wallIndex];

        int absX  = Mathf.Abs(dif.x);
        int signX = (int)Mathf.Sign(dif.x);


        int absZ  = Mathf.Abs(dif.z);
        int signZ = (int)Mathf.Sign(dif.z);


        Vec2i dir = new Vec2i(absX == 0?0:signX, absZ == 0 ? 0 : signZ);



        int len = absX + absZ;

        //if the selected wall has a length that is not large enough to house the window,
        if (len < size + 4)
        {
            if (autoReattempt)
            {
                return(AddWindow(genRan, vox, build, wp1, size, height, autoReattempt, reattemptCount));
            }
            //Then we do not build a window
            return(false);
        }


        int   dx    = dir.x == 0 ? 0 : genRan.RandomInt(1, absX - size - 2);
        int   dz    = dir.z == 0 ? 0 : genRan.RandomInt(1, absZ - size - 2);
        Vec2i dPos  = dir * (dx + dz);
        Vec2i start = build.BoundingWall[wallIndex];

        Vec2i cur = start + dPos;

        //If the building has an entrance, we iterate all window points
        //to make sure we aren't breaking a door
        if (build.Entrance != null)
        {
            //If we are too close to the door
            if (cur.QuickDistance(build.Entrance) < (size + 1) * (size + 1))
            {
                if (autoReattempt)
                {
                    return(AddWindow(genRan, vox, build, wp1, size, height, autoReattempt, reattemptCount));
                }
                return(false);
            }
            else
            {
                for (int i = 0; i < size; i++)
                {
                    cur = start + dPos + (dir * i);
                    if (cur.x > 0 && cur.z > 0 && cur.x < build.Width && cur.z < build.Height)
                    {
                        if (vox.GetVoxel(cur.x, 2, cur.z) == Voxel.glass)
                        {
                            if (autoReattempt)
                            {
                                return(AddWindow(genRan, vox, build, wp1, size, height, autoReattempt, reattemptCount));
                            }
                            return(false);
                        }
                    }
                    else
                    {
                        if (autoReattempt)
                        {
                            return(AddWindow(genRan, vox, build, wp1, size, height, autoReattempt, reattemptCount));
                        }
                        return(false);
                    }
                }
            }
        }
        cur = start + dPos;

        Vector3 position = (cur - dir).AsVector3() + Vector3.up;
        Vector3 scale    = new Vector3(0.5f, 2, (dir.x + dir.z) * size);
        float   rotation = Mathf.Acos(dir.z) * Mathf.Rad2Deg;

        //GlassWindow window = new GlassWindow(position, scale, rotation);
        //build.AddObjectReference(window);

        for (int i = -1; i <= size; i++)
        {
            cur = start + dPos + dir * i;

            for (int y = 1; y <= 2 + height; y++)
            {
                if (i < 0 || i >= size || y == 1 || y == 2 + height)
                {
                    vox.AddVoxel(cur.x, y, cur.z, Voxel.glass);
                }
                else
                {
                    vox.ClearVoxel(cur.x, y, cur.z);
                    vox.SetVoxel(cur.x, y, cur.z, Voxel.glass);
                }

                //vox.Add(cur.x, y, cur.z, Voxel.none);
            }
        }



        return(true);
    }